<commit_before>// Copyright © 2016, Peter Atashian

extern crate googl;
extern crate irc;
#[macro_use] extern crate lazy_static;
extern crate mediawiki;
extern crate rustc_serialize;
extern crate url;

use irc::client::prelude::*;
use mediawiki::{Error as MwError, JsonFun, Mediawiki};
use rustc_serialize::json::{Json, decode};
use std::cmp::{max};
use std::fmt::{Display, Error as FmtError, Formatter};
use std::fs::{File, OpenOptions};
use std::io::{Read, Error as IoError, Write};
use std::sync::{Arc};
use std::sync::mpsc::{Receiver, Sender, channel};
use std::thread::{sleep, spawn};
use std::time::{Duration};
use url::{Url};
use url::form_urlencoded::{serialize};

#[derive(Debug)]
enum Error {
    Mediawiki(MwError),
    Io(IoError),
    Unknown,
}
impl From<MwError> for Error {
    fn from(err: MwError) -> Error {
        Error::Mediawiki(err)
    }
}
impl From<IoError> for Error {
    fn from(err: IoError) -> Error {
        Error::Io(err)
    }
}
fn main() {
    let (send, recv) = channel();
    spawn(move|| mw_thread(send));
    irc_thread(recv);
}
enum Change {
    New {
        user: String,
        title: String,
        comment: String,
        size: i64,
        link: String,
    },
    Edit {
        user: String,
        title: String,
        comment: String,
        diff: i64,
        link: String,
    },
    Delete {
        user: String,
        title: String,
        comment: String,
    },
    Move {
        user: String,
        title: String,
        newtitle: String,
        comment: String,
    },
    Upload {
        user: String,
        title: String,
        comment: String,
        link: String,
    },
    MarkTranslation {
        user: String,
        title: String,
    },
    ReviewTranslation {
        user: String,
        title: String,
    },
    AddProtection {
        user: String,
        title: String,
        comment: String,
        detail: String,
    },
    RemoveProtection {
        user: String,
        title: String,
        comment: String,
    },
    ModifyProtection {
        user: String,
        title: String,
        comment: String,
        detail: String,
    },
    CreateUser {
        user: String,
    },
}
impl Display for Change {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        struct Type<'a>(&'a str);
        impl<'a> Display for Type<'a> {
            fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
                write!(f, "[\x0307{}\x0f]", self.0)
            }
        }
        struct Comment<'a>(&'a str);
        impl<'a> Display for Comment<'a> {
            fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
                if self.0.is_empty() {
                    write!(f, "")
                } else {
                    write!(f, "(\x1d{}\x0f)", self.0)
                }
            }
        }
        struct User<'a>(&'a str);
        impl<'a> Display for User<'a> {
            fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
                write!(f, "\x0310{}\x0f", self.0)
            }
        }
        struct Title<'a>(&'a str);
        impl<'a> Display for Title<'a> {
            fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
                write!(f, "\x02{}\x0f", self.0)
            }
        }
        struct Diff(i64);
        impl Display for Diff {
            fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
                if self.0 >= 500 {
                    write!(f, "(\x02\x0303+{}\x0f)", self.0)
                } else if self.0 > 0 {
                    write!(f, "(\x0303+{}\x0f)", self.0)
                } else if self.0 <= -500 {
                    write!(f, "(\x02\x0304{}\x0f)", self.0)
                } else if self.0 < 0 {
                    write!(f, "(\x0304{}\x0f)", self.0)
                } else {
                    write!(f, "(\x0314{}\x0f)", self.0)
                }
            }
        }
        match self {
            &Change::New { ref user, ref title, ref comment, ref size, ref link } => {
                write!(f, "{} {} {} created {} {} {}", Type("new"),
                    Diff(*size), User(user), Title(title), Comment(comment), link)
            },
            &Change::Edit { ref user, ref title, ref comment, ref diff, ref link } => {
                write!(f, "{} {} {} edited {} {} {}", Type("edit"),
                    Diff(*diff), User(user), Title(title), Comment(comment), link)
            },
            &Change::Delete { ref user, ref title, ref comment } => {
                write!(f, "{} {} deleted {} {}", Type("delete"),
                    User(user), Title(title), Comment(comment))
            },
            &Change::Move { ref user, ref title, ref newtitle, ref comment } => {
                write!(f, "{} {} moved {} to {} {}", Type("move"),
                    User(user), Title(title), Title(newtitle), Comment(comment))
            },
            &Change::Upload { ref user, ref title, ref comment, ref link } => {
                write!(f, "{} {} uploaded {} {} {}", Type("upload"),
                    User(user), Title(title), Comment(comment), link)
            },
            &Change::MarkTranslation { ref user, ref title } => {
                write!(f, "{} {} marked {} for translation", Type("mark"),
                    User(user), Title(title))
            },
            &Change::ReviewTranslation { ref user, ref title } => {
                write!(f, "{} {} reviewed the translation {}", Type("review"),
                    User(user), Title(title))
            },
            &Change::AddProtection { ref user, ref title, ref comment, ref detail } => {
                write!(f, "{} {} added protection to {} {} {}", Type("protect"),
                    User(user), Title(title), detail, Comment(comment))
            },
            &Change::ModifyProtection { ref user, ref title, ref comment, ref detail } => {
                write!(f, "{} {} modified the protection for {} {} {}", Type("protect"),
                    User(user), Title(title), detail, Comment(comment))
            },
            &Change::RemoveProtection { ref user, ref title, ref comment } => {
                write!(f, "{} {} removed the protection on {} {}", Type("protect"),
                    User(user), Title(title), Comment(comment))
            },
            &Change::CreateUser { ref user } => {
                write!(f, "{} {} created an account", Type("user"),
                    User(user))
            },
        }
    }
}
fn shorten(link: &str) -> String {
    lazy_static! {
        static ref KEY: String = {
            let mut file = File::open("key.txt").unwrap();
            let mut key = String::new();
            file.read_to_string(&mut key).unwrap();
            key
        };
    }
    let shortlink;
    loop {
        match googl::shorten(&KEY, &link) {
            Ok(link) => { shortlink = link; break },
            Err(_) => sleep(Duration::from_secs(5)),
        }
    }
    shortlink
}
fn make_article_link(title: &str) -> String {
    let args = [("title", title)];
    let url = Url::parse(&format!("http://ftb.gamepedia.com/index.php?{}",
        serialize(args.iter().map(|&x| x)))).unwrap().serialize();
    shorten(&url)
}
fn make_revision_link(title: &str, oldid: &str) -> String {
    let args = [("title", title), ("oldid", oldid)];
    let url = Url::parse(&format!("http://ftb.gamepedia.com/index.php?{}",
        serialize(args.iter().map(|&x| x)))).unwrap().serialize();
    shorten(&url)
}
fn make_diff_link(title: &str, oldid: &str) -> String {
    let args = [("title", title), ("diff", "prev"), ("oldid", oldid)];
    let url = Url::parse(&format!("http://ftb.gamepedia.com/index.php?{}",
        serialize(args.iter().map(|&x| x)))).unwrap().serialize();
    shorten(&url)
}
fn process_change(send: &Sender<Change>, change: &Json) -> Result<(), Error> {
    let kind = change.get("type").string().unwrap_or("");
    let user = change.get("user").string().unwrap_or("NO USER").to_owned();
    let title = change.get("title").string().unwrap_or("NO TITLE").to_owned();
    let comment = change.get("comment").string().unwrap_or("").to_owned();
    let oldlen = change.get("oldlen").integer().unwrap_or(0);
    let newlen = change.get("newlen").integer().unwrap_or(0);
    let revid = change.get("revid").integer().unwrap_or(0);
    let logaction = change.get("logaction").string().unwrap_or("");
    let logtype = change.get("logtype").string().unwrap_or("");
    match kind {
        "edit" => send.send(Change::Edit {
            user: user,
            link: make_diff_link(&title, &revid.to_string()),
            title: title,
            comment: comment,
            diff: newlen - oldlen,
        }).unwrap(),
        "new" => send.send(Change::New {
            user: user,
            link: make_revision_link(&title, &revid.to_string()),
            title: title,
            comment: comment,
            size: newlen,
        }).unwrap(),
        "log" => match (logtype, logaction) {
            ("delete", "delete") => send.send(Change::Delete {
                user: user,
                title: title,
                comment: comment,
            }).unwrap(),
            ("move", "move") => send.send(Change::Move {
                user: user,
                title: title,
                newtitle: change.get("logparams").get("target_title").string().unwrap_or("").into(),
                comment: comment,
            }).unwrap(),
            ("upload", "upload") => send.send(Change::Upload {
                user: user,
                link: make_article_link(&title),
                title: title,
                comment: comment,
            }).unwrap(),
            ("pagetranslation", "mark") => send.send(Change::MarkTranslation {
                user: user,
                title: title,
            }).unwrap(),
            ("translationreview", "message") => send.send(Change::ReviewTranslation {
                user: user,
                title: title,
            }).unwrap(),
            ("protect", "protect") => send.send(Change::AddProtection {
                user: user,
                title: title,
                comment: comment,
                detail: change.get("0").string().unwrap_or("").into(),
            }).unwrap(),
            ("protect", "unprotect") => send.send(Change::RemoveProtection {
                user: user,
                title: title,
                comment: comment,
            }).unwrap(),
            ("protect", "modify") => send.send(Change::ModifyProtection {
                user: user,
                title: title,
                comment: comment,
                detail: change.get("0").string().unwrap_or("").into(),
            }).unwrap(),
            ("newusers", "create") => send.send(Change::CreateUser {
                user: user,
            }).unwrap(),
            _ => return Err(Error::Unknown),
        },
        _ => return Err(Error::Unknown),
    }
    Ok(())
}
fn mw_thread(send: Sender<Change>) {
    let mut file = File::open("ftb.json").unwrap();
    let mut s = String::new();
    file.read_to_string(&mut s).unwrap();
    let config = decode(&s).unwrap();
    let mw = Mediawiki::login(config).unwrap();
    let mut latest = 0;
    let mut rcfile = OpenOptions::new().write(true).append(true).open("rc.txt").unwrap();
    loop {
        let previous = latest;
        match mw.recent_changes() {
            Ok(rc) => for change in rc {
                match change {
                    Ok(change) => {
                        let id = change.get("rcid").integer().unwrap();
                        latest = max(id, latest);
                        if id <= previous || previous == 0 {
                            break
                        }
                        if let Err(e) = process_change(&send, &change) {
                            writeln!(&mut rcfile, "{}", change.pretty()).unwrap();
                            println!("{:?}", e);
                        }
                    },
                    Err(e) => {
                        println!("{:?}", e);
                        break
                    },
                }
                sleep(Duration::from_secs(1))
            },
            Err(e) => {
                println!("{:?}", e);
                continue;
            },
        };
        sleep(Duration::from_secs(10))
    }
}
fn is_translation(change: &Change) -> bool {
    if let &Change::New { ref title, .. } = change {
        title.starts_with("Translations:")
    } else if let &Change::Edit { ref title, .. } = change {
        title.starts_with("Translations:")
    } else { false }
}
fn irc_print_changes<T, U>(server: &Arc<IrcServer<T, U>>, recv: &Receiver<Change>) -> Result<(), Error>
    where T: IrcRead, U: IrcWrite {
    try!(server.identify());
    for change in recv {
        if is_translation(&change) { continue }
        try!(server.send_privmsg("#FTB-Wiki-recentchanges", &change.to_string()));
    }
    Ok(())
}
fn irc_thread(recv: Receiver<Change>) -> ! {
    let server = Arc::new(IrcServer::new("irc.json").unwrap());
    let server_clone = server.clone();
    spawn(move|| irc_listen_thread(server_clone));
    loop {
        println!("Aw shit {:?}", irc_print_changes(&server, &recv));
        println!("Reconnecting {:?}", server.reconnect());
    }
}
fn irc_listen_thread<T, U>(server: Arc<IrcServer<T, U>>) where T: IrcRead, U: IrcWrite {
    let mut file = File::create("irc.txt").unwrap();
    loop {
        for msg in server.iter() {
            writeln!(&mut file, "{:?}", msg).unwrap();
        }
        sleep(Duration::from_secs(1))
    }
}
<commit_msg>Add support for curse profile things.<commit_after>// Copyright © 2016, Peter Atashian

extern crate googl;
extern crate irc;
#[macro_use] extern crate lazy_static;
extern crate mediawiki;
extern crate rustc_serialize;
extern crate url;

use irc::client::prelude::*;
use mediawiki::{Error as MwError, JsonFun, Mediawiki};
use rustc_serialize::json::{Json, decode};
use std::cmp::{max};
use std::fmt::{Display, Error as FmtError, Formatter};
use std::fs::{File, OpenOptions};
use std::io::{Read, Error as IoError, Write};
use std::sync::{Arc};
use std::sync::mpsc::{Receiver, Sender, channel};
use std::thread::{sleep, spawn};
use std::time::{Duration};
use url::{Url};
use url::form_urlencoded::{serialize};

#[derive(Debug)]
enum Error {
    Mediawiki(MwError),
    Io(IoError),
    Unknown,
}
impl From<MwError> for Error {
    fn from(err: MwError) -> Error {
        Error::Mediawiki(err)
    }
}
impl From<IoError> for Error {
    fn from(err: IoError) -> Error {
        Error::Io(err)
    }
}
fn main() {
    let (send, recv) = channel();
    spawn(move|| mw_thread(send));
    irc_thread(recv);
}
enum Change {
    New {
        user: String,
        title: String,
        comment: String,
        size: i64,
        link: String,
    },
    Edit {
        user: String,
        title: String,
        comment: String,
        diff: i64,
        link: String,
    },
    Delete {
        user: String,
        title: String,
        comment: String,
    },
    Move {
        user: String,
        title: String,
        newtitle: String,
        comment: String,
    },
    UploadNew {
        user: String,
        title: String,
        comment: String,
        link: String,
    },
    UploadOverwrite {
        user: String,
        title: String,
        comment: String,
        link: String,
    },
    MarkTranslation {
        user: String,
        title: String,
    },
    ReviewTranslation {
        user: String,
        title: String,
    },
    AddProtection {
        user: String,
        title: String,
        comment: String,
        detail: String,
    },
    RemoveProtection {
        user: String,
        title: String,
        comment: String,
    },
    ModifyProtection {
        user: String,
        title: String,
        comment: String,
        detail: String,
    },
    CreateUser {
        user: String,
    },
    NewProfileComment {
        user: String,
        title: String
    },
    ReplyProfileComment {
        user: String,
        title: String
    },
    EditProfileComment {
        user: String,
        title: String
    }
}
impl Display for Change {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        struct Type<'a>(&'a str);
        impl<'a> Display for Type<'a> {
            fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
                write!(f, "[\x0307{}\x0f]", self.0)
            }
        }
        struct Comment<'a>(&'a str);
        impl<'a> Display for Comment<'a> {
            fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
                if self.0.is_empty() {
                    write!(f, "")
                } else {
                    write!(f, "(\x1d{}\x0f)", self.0)
                }
            }
        }
        struct User<'a>(&'a str);
        impl<'a> Display for User<'a> {
            fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
                write!(f, "\x0310{}\x0f", self.0)
            }
        }
        struct Title<'a>(&'a str);
        impl<'a> Display for Title<'a> {
            fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
                write!(f, "\x02{}\x0f", self.0)
            }
        }
        struct Diff(i64);
        impl Display for Diff {
            fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
                if self.0 >= 500 {
                    write!(f, "(\x02\x0303+{}\x0f)", self.0)
                } else if self.0 > 0 {
                    write!(f, "(\x0303+{}\x0f)", self.0)
                } else if self.0 <= -500 {
                    write!(f, "(\x02\x0304{}\x0f)", self.0)
                } else if self.0 < 0 {
                    write!(f, "(\x0304{}\x0f)", self.0)
                } else {
                    write!(f, "(\x0314{}\x0f)", self.0)
                }
            }
        }
        match self {
            &Change::New { ref user, ref title, ref comment, ref size, ref link } => {
                write!(f, "{} {} {} created {} {} {}", Type("new"),
                    Diff(*size), User(user), Title(title), Comment(comment), link)
            },
            &Change::Edit { ref user, ref title, ref comment, ref diff, ref link } => {
                write!(f, "{} {} {} edited {} {} {}", Type("edit"),
                    Diff(*diff), User(user), Title(title), Comment(comment), link)
            },
            &Change::Delete { ref user, ref title, ref comment } => {
                write!(f, "{} {} deleted {} {}", Type("delete"),
                    User(user), Title(title), Comment(comment))
            },
            &Change::Move { ref user, ref title, ref newtitle, ref comment } => {
                write!(f, "{} {} moved {} to {} {}", Type("move"),
                    User(user), Title(title), Title(newtitle), Comment(comment))
            },
            &Change::UploadNew { ref user, ref title, ref comment, ref link } => {
                write!(f, "{} {} uploaded {} {} {}", Type("upload"),
                    User(user), Title(title), Comment(comment), link)
            },
            &Change::UploadOverwrite { ref user, ref title, ref comment, ref link } => {
                write!(f, "{} {} uploaded a new version of {} {} {}", Type("upload"),
                    User(user), Title(title), Comment(comment), link)
            },
            &Change::MarkTranslation { ref user, ref title } => {
                write!(f, "{} {} marked {} for translation", Type("mark"),
                    User(user), Title(title))
            },
            &Change::ReviewTranslation { ref user, ref title } => {
                write!(f, "{} {} reviewed the translation {}", Type("review"),
                    User(user), Title(title))
            },
            &Change::AddProtection { ref user, ref title, ref comment, ref detail } => {
                write!(f, "{} {} added protection to {} {} {}", Type("protect"),
                    User(user), Title(title), detail, Comment(comment))
            },
            &Change::ModifyProtection { ref user, ref title, ref comment, ref detail } => {
                write!(f, "{} {} modified the protection for {} {} {}", Type("protect"),
                    User(user), Title(title), detail, Comment(comment))
            },
            &Change::RemoveProtection { ref user, ref title, ref comment } => {
                write!(f, "{} {} removed the protection on {} {}", Type("protect"),
                    User(user), Title(title), Comment(comment))
            },
            &Change::CreateUser { ref user } => {
                write!(f, "{} {} created an account", Type("user"),
                    User(user))
            },
            &Change::NewProfileComment { ref user, ref title } => {
                write!(f, "{} {} created a new comment on {}", Type("profile"),
                    User(user), Title(title))
            },
            &Change::ReplyProfileComment { ref user, ref title } => {
                write!(f, "{} {} replied to a comment on {}", Type("profile"),
                    User(user), Title(title))
            },
            &Change::EditProfileComment { ref user, ref title } => {
                write!(f, "{} {} edited a profile comment on {}", Type("profile"),
                    User(user), Title(title))
            }
        }
    }
}
fn shorten(link: &str) -> String {
    lazy_static! {
        static ref KEY: String = {
            let mut file = File::open("key.txt").unwrap();
            let mut key = String::new();
            file.read_to_string(&mut key).unwrap();
            key
        };
    }
    let shortlink;
    loop {
        match googl::shorten(&KEY, &link) {
            Ok(link) => { shortlink = link; break },
            Err(_) => sleep(Duration::from_secs(5)),
        }
    }
    shortlink
}
fn make_article_link(title: &str) -> String {
    let args = [("title", title)];
    let url = Url::parse(&format!("http://ftb.gamepedia.com/index.php?{}",
        serialize(args.iter().map(|&x| x)))).unwrap().serialize();
    shorten(&url)
}
fn make_revision_link(title: &str, oldid: &str) -> String {
    let args = [("title", title), ("oldid", oldid)];
    let url = Url::parse(&format!("http://ftb.gamepedia.com/index.php?{}",
        serialize(args.iter().map(|&x| x)))).unwrap().serialize();
    shorten(&url)
}
fn make_diff_link(title: &str, oldid: &str) -> String {
    let args = [("title", title), ("diff", "prev"), ("oldid", oldid)];
    let url = Url::parse(&format!("http://ftb.gamepedia.com/index.php?{}",
        serialize(args.iter().map(|&x| x)))).unwrap().serialize();
    shorten(&url)
}
fn process_change(send: &Sender<Change>, change: &Json) -> Result<(), Error> {
    let kind = change.get("type").string().unwrap_or("");
    let user = change.get("user").string().unwrap_or("NO USER").to_owned();
    let title = change.get("title").string().unwrap_or("NO TITLE").to_owned();
    let comment = change.get("comment").string().unwrap_or("").to_owned();
    let oldlen = change.get("oldlen").integer().unwrap_or(0);
    let newlen = change.get("newlen").integer().unwrap_or(0);
    let revid = change.get("revid").integer().unwrap_or(0);
    let logaction = change.get("logaction").string().unwrap_or("");
    let logtype = change.get("logtype").string().unwrap_or("");
    match kind {
        "edit" => send.send(Change::Edit {
            user: user,
            link: make_diff_link(&title, &revid.to_string()),
            title: title,
            comment: comment,
            diff: newlen - oldlen,
        }).unwrap(),
        "new" => send.send(Change::New {
            user: user,
            link: make_revision_link(&title, &revid.to_string()),
            title: title,
            comment: comment,
            size: newlen,
        }).unwrap(),
        "log" => match (logtype, logaction) {
            ("delete", "delete") => send.send(Change::Delete {
                user: user,
                title: title,
                comment: comment,
            }).unwrap(),
            ("move", "move") => send.send(Change::Move {
                user: user,
                title: title,
                newtitle: change.get("logparams").get("target_title").string().unwrap_or("").into(),
                comment: comment,
            }).unwrap(),
            ("upload", "upload") => send.send(Change::UploadNew {
                user: user,
                link: make_article_link(&title),
                title: title,
                comment: comment,
            }).unwrap(),
            ("upload", "overwrite") => send.send(Change::UploadOverwrite {
                user: user,
                link: make_article_link(&title),
                title: title,
                comment: comment
            }).unwrap(),
            ("pagetranslation", "mark") => send.send(Change::MarkTranslation {
                user: user,
                title: title,
            }).unwrap(),
            ("translationreview", "message") => send.send(Change::ReviewTranslation {
                user: user,
                title: title,
            }).unwrap(),
            ("protect", "protect") => send.send(Change::AddProtection {
                user: user,
                title: title,
                comment: comment,
                detail: change.get("0").string().unwrap_or("").into(),
            }).unwrap(),
            ("protect", "unprotect") => send.send(Change::RemoveProtection {
                user: user,
                title: title,
                comment: comment,
            }).unwrap(),
            ("protect", "modify") => send.send(Change::ModifyProtection {
                user: user,
                title: title,
                comment: comment,
                detail: change.get("0").string().unwrap_or("").into(),
            }).unwrap(),
            ("newusers", "create") => send.send(Change::CreateUser {
                user: user,
            }).unwrap(),
            ("curseprofile", "comment-created") => send.send(Change::NewProfileComment {
                user: user,
                title: title,
            }).unwrap(),
            ("curseprofile", "comment-replied") => send.send(Change::ReplyProfileComment {
                user: user,
                title: title,
            }).unwrap(),
            ("curseprofile", "comment-edited") => send.send(Change::EditProfileComment {
                user: user,
                title: title,
            }).unwrap(),
            _ => return Err(Error::Unknown),
        },
        _ => return Err(Error::Unknown),
    }
    Ok(())
}
fn mw_thread(send: Sender<Change>) {
    let mut file = File::open("ftb.json").unwrap();
    let mut s = String::new();
    file.read_to_string(&mut s).unwrap();
    let config = decode(&s).unwrap();
    let mw = Mediawiki::login(config).unwrap();
    let mut latest = 0;
    let mut rcfile = OpenOptions::new().write(true).append(true).open("rc.txt").unwrap();
    loop {
        let previous = latest;
        match mw.recent_changes() {
            Ok(rc) => for change in rc {
                match change {
                    Ok(change) => {
                        let id = change.get("rcid").integer().unwrap();
                        latest = max(id, latest);
                        if id <= previous || previous == 0 {
                            break
                        }
                        if let Err(e) = process_change(&send, &change) {
                            writeln!(&mut rcfile, "{}", change.pretty()).unwrap();
                            println!("{:?}", e);
                        }
                    },
                    Err(e) => {
                        println!("{:?}", e);
                        break
                    },
                }
                sleep(Duration::from_secs(1))
            },
            Err(e) => {
                println!("{:?}", e);
                continue;
            },
        };
        sleep(Duration::from_secs(10))
    }
}
fn is_translation(change: &Change) -> bool {
    if let &Change::New { ref title, .. } = change {
        title.starts_with("Translations:")
    } else if let &Change::Edit { ref title, .. } = change {
        title.starts_with("Translations:")
    } else { false }
}
fn irc_print_changes<T, U>(server: &Arc<IrcServer<T, U>>, recv: &Receiver<Change>) -> Result<(), Error>
    where T: IrcRead, U: IrcWrite {
    try!(server.identify());
    for change in recv {
        if is_translation(&change) { continue }
        try!(server.send_privmsg("#FTB-Wiki-recentchanges", &change.to_string()));
    }
    Ok(())
}
fn irc_thread(recv: Receiver<Change>) -> ! {
    let server = Arc::new(IrcServer::new("irc.json").unwrap());
    let server_clone = server.clone();
    spawn(move|| irc_listen_thread(server_clone));
    loop {
        println!("Aw shit {:?}", irc_print_changes(&server, &recv));
        println!("Reconnecting {:?}", server.reconnect());
    }
}
fn irc_listen_thread<T, U>(server: Arc<IrcServer<T, U>>) where T: IrcRead, U: IrcWrite {
    let mut file = File::create("irc.txt").unwrap();
    loop {
        for msg in server.iter() {
            writeln!(&mut file, "{:?}", msg).unwrap();
        }
        sleep(Duration::from_secs(1))
    }
}
<|endoftext|>


<commit_before>extern crate argparse;
use argparse::{ArgumentParser, Store};

fn main() {
    let mut size:i32 = 20;
    let padding = vec!["  ", " ", "", " ", "  ", "   ", "    ", "   "];

    {  // this block limits scope of borrows by ap.refer() method
        let mut ap = ArgumentParser::new();

        ap.set_description("Print a beautiful millipede (written in rust)");
        ap.refer(&mut size)
            .add_option(&["-s", "--size"], Store,
            "Be verbose");
        ap.parse_args_or_exit();
    }
    if size >= 0 {
        let mut i: usize = 0;

        println!("    ╚⊙ ⊙╝");
        while i < size as usize {
            println!("{}╚═(███)═╝", padding[i % 8]);
            i = i + 1;
        }
    } else {
        let mut i: usize = size.abs() as usize;

        while i > 0 {
            println!("{}╔═(███)═╗", padding[i % 8]);
            i = i - 1;
        }
        println!("   ╔⊙ ⊙╗");
    }
}
<commit_msg>Add skin<commit_after>extern crate argparse;
use argparse::{ArgumentParser, Store};

fn main() {
    let mut size:i32 = 20;
    let mut skin = "███".to_string();
    let padding = vec!["  ", " ", "", " ", "  ", "   ", "    ", "   "];

    {  // this block limits scope of borrows by ap.refer() method
        let mut ap = ArgumentParser::new();

        ap.set_description("Print a beautiful millipede (written in rust)");
        ap.refer(&mut size)
            .add_option(&["--size"], Store,
            "Changes the size");
        ap.refer(&mut skin)
            .add_option(&["--skin"], Store,
            "Changes the skin");
        ap.parse_args_or_exit();
    }
    if size >= 0 {
        let mut i: usize = 0;

        println!("    ╚⊙ ⊙╝");
        while i < size as usize {
            println!("{}╚═({})═╝", padding[i % 8], skin);
            i = i + 1;
        }
    } else {
        let mut i: usize = size.abs() as usize;

        while i > 0 {
            println!("{}╔═({})═╗", padding[i % 8], skin);
            i = i - 1;
        }
        println!("   ╔⊙ ⊙╗");
    }
}
<|endoftext|>


<commit_before>extern crate open_gl_bindings;
extern crate sdl2;

use open_gl_bindings::gl;

use sdl2::event::Event;

use std::ffi::CStr;
use std::str;

fn find_sdl_gl_driver() -> Option<u32> {
    for (index, item) in sdl2::render::drivers().enumerate() {
        if item.name == "opengl" {
            return Some(index as u32);
        }
    }
    None
}

fn main() {
    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();
    let window = video_subsystem
        .window("Window", 800, 600)
        .opengl()
        .build()
        .unwrap();
    let canvas = window
        .into_canvas()
        .index(find_sdl_gl_driver().unwrap())
        .build()
        .unwrap();

    let ctx = gl::Gl::load_with(|name| video_subsystem.gl_get_proc_address(name) as *const _);
    canvas.window().gl_set_context_to_current().unwrap();

    let char_ptr = unsafe { ctx.GetString(gl::VERSION) };
    let c_str: &CStr = unsafe { CStr::from_ptr(std::mem::transmute(char_ptr)) };
    let buf: &[u8] = c_str.to_bytes();
    let str_slice: &str = str::from_utf8(buf).unwrap();
    let version: String = str_slice.to_owned();

    println!("OpenGL version: {}", version);

    let mut event_pump = sdl_context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit { .. } |
                Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::Escape), .. } |
                Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::F10), .. } => {
                    break 'running;
                }
                _ => {}
            }
        }
    }
}
<commit_msg>draw an irregular polygon and sleep some of the time<commit_after>extern crate open_gl_bindings;
extern crate sdl2;

use open_gl_bindings::gl;

use sdl2::event::Event;

use std::ffi::CStr;
use std::str;

fn find_sdl_gl_driver() -> Option<u32> {
    for (index, item) in sdl2::render::drivers().enumerate() {
        if item.name == "opengl" {
            return Some(index as u32);
        }
    }
    None
}

fn main() {
    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let gl_attr = video_subsystem.gl_attr();
    gl_attr.set_stencil_size(1);
    gl_attr.set_context_major_version(2);
    gl_attr.set_context_minor_version(1);

    let canvas = video_subsystem
        .window("Window", 800, 600)
        .opengl()
        .build()
        .unwrap()
        .into_canvas()
        .index(find_sdl_gl_driver().unwrap())
        .build()
        .unwrap();

    let ctx = gl::Gl::load_with(|name| video_subsystem.gl_get_proc_address(name) as *const _);
    canvas.window().gl_set_context_to_current().unwrap();

    let char_ptr = unsafe { ctx.GetString(gl::VERSION) };
    let c_str: &CStr = unsafe { CStr::from_ptr(std::mem::transmute(char_ptr)) };
    let buf: &[u8] = c_str.to_bytes();
    let str_slice: &str = str::from_utf8(buf).unwrap();
    let version: String = str_slice.to_owned();

    println!("OpenGL version: {}", version);

    let window = canvas.window();

    let (width, height) = window.drawable_size();

    unsafe {
        ctx.Viewport(0, 0, width as _, height as _);

        ctx.MatrixMode(gl::PROJECTION);
        ctx.LoadIdentity();

        ctx.MatrixMode(gl::MODELVIEW);
        ctx.LoadIdentity();
    }

    unsafe {
        ctx.ClearColor(0.0, 0.0, 0.0, 1.0);
        ctx.Clear(
            gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT,
        );
        ctx.Enable(gl::BLEND);
        ctx.BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);

        ctx.Clear(gl::STENCIL_BUFFER_BIT);

        let verts: Vec<f32> = get_verts();

        ctx.EnableClientState(gl::VERTEX_ARRAY);
        ctx.VertexPointer(2, gl::FLOAT, 0, std::mem::transmute(verts.as_ptr()));

        let cnt = (verts.len() / 2) as _;

        ctx.Enable(gl::STENCIL_TEST);

        ctx.ColorMask(gl::FALSE, gl::FALSE, gl::FALSE, gl::FALSE);
        ctx.StencilOp(gl::INVERT, gl::INVERT, gl::INVERT);
        ctx.StencilFunc(gl::ALWAYS, 0x1, 0x1);
        ctx.Color4f(1.0, 1.0, 1.0, 1.0);
        ctx.DrawArrays(gl::TRIANGLE_FAN, 0, cnt);

        ctx.ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
        ctx.Color4f(32.0 / 255.0, 32.0 / 255.0, 63.0 / 255.0, 1.0);

        ctx.StencilOp(gl::ZERO, gl::ZERO, gl::ZERO);
        ctx.StencilFunc(gl::EQUAL, 1, 1);
        ctx.DrawArrays(gl::TRIANGLE_FAN, 0, cnt);
        ctx.Disable(gl::STENCIL_TEST);

    }

    let mut event_pump = sdl_context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit { .. } |
                Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::Escape), .. } |
                Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::F10), .. } => {
                    break 'running;
                }
                _ => {}
            }
        }

        window.gl_swap_window();

        std::thread::sleep(std::time::Duration::from_millis(8));
    }
}

#[cfg_attr(rustfmt, rustfmt_skip)]
fn get_verts() -> Vec<f32> {
    vec![
        -0.012640, 0.255336,
        0.152259, 0.386185,
        0.223982, 0.275978,
        0.191749, 0.169082,
        0.396864, 0.121742,
        0.355419, -0.003047,
        0.251747, -0.044495,
        0.342622, -0.234376,
        0.219218, -0.279777,
        0.122174, -0.224565,
        0.030379, -0.414003,
        -0.082058, -0.345830,
        -0.099398, -0.235534,
        -0.304740, -0.281878,
        -0.321543, -0.151465,
        -0.246122, -0.069141,
        -0.410383, 0.062507,
        -0.318899, 0.156955,
        -0.207511, 0.149317,
        -0.207000, 0.359823,
        -0.076118, 0.347186,
        -0.012640, 0.255336,
    ]
}
<|endoftext|>


<commit_before>extern crate getopts;
extern crate nix;
extern crate colored;

mod util;
mod stats;
mod filesystems;

use std::cmp;
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use std::process;
use nix::sys::statvfs::vfs::Statvfs;
use colored::*;
use std::env;
use getopts::Options;

use util::{iec, bargraph};
use stats::Stats;
use filesystems::pseudo_filesystems;

const FS_SPEC: usize = 0;
const FS_FILE: usize = 1;
const FS_VFSTYPE: usize = 2;

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();
    opts.optflag("a", "all", "display all filesystems");
    let matches = match opts.parse(&args[1..]) {
        Ok(m)  => m,
        Err(e) => { panic!(e); },
    };

    let file = match File::open("/proc/mounts") {
        Ok(f)  => f,
        Err(e) => {
            println!("Error: Could not open /proc/mounts - {}", e);
            process::exit(1);
        },
    };
    let reader = BufReader::new(&file);

    let excludes = pseudo_filesystems();

    let mut stats: Vec<Stats> = Vec::new();
    let mut max_width = 0;

    for line in reader.lines() {
        match line {
            Ok(line) => {
                let fields: Vec<&str> = line.split_whitespace().collect();
                if !matches.opt_present("a") && excludes.contains(fields[FS_VFSTYPE]) {
                    continue;
                }
                let statvfs = match Statvfs::for_path(fields[FS_FILE]) {
                    Ok(s) => s,
                    Err(err) => {
                        println!("Error: {}", err);
                        continue;
                    },
                };
                let size = statvfs.f_blocks * statvfs.f_bsize;
                let avail = statvfs.f_bavail * statvfs.f_bsize;
                if size == 0 && !matches.opt_present("a") {
                    continue;
                }
                let s = Stats::new(fields[FS_SPEC], size, avail, fields[FS_FILE]);

                max_width = cmp::max(max_width, s.filesystem.len());
                stats.push(s);
            },
            Err(err) => println!("Error: {}", err),
        }
    }

    stats.sort();

    let headers = ["Filesystem", "Size", "Used", "Avail", "Use%", "", "Mounted on"];
    let headers: Vec<ColoredString> = headers.into_iter().map(|x| x.yellow()).collect();
    println!("{:width$} {:>5} {:>5} {:>5} {:>5} {:20} {}",
             headers[0], headers[1], headers[2], headers[3],
             headers[4], headers[5], headers[6], width = max_width);

    for stat in stats {
        let fs = if stat.is_network() {
            stat.filesystem.blue()
        } else {
            stat.filesystem.normal()
        };
        println!("{:width$} {:>5} {:>5} {:>5} {:>5.1} {:20} {}",
                 fs, iec(stat.size), iec(stat.used), iec(stat.avail),
                 stat.percent, bargraph(stat.percent), stat.mount, width = max_width);
    }

}
<commit_msg>Change color for net fs.<commit_after>extern crate getopts;
extern crate nix;
extern crate colored;

mod util;
mod stats;
mod filesystems;

use std::cmp;
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use std::process;
use nix::sys::statvfs::vfs::Statvfs;
use colored::*;
use std::env;
use getopts::Options;

use util::{iec, bargraph};
use stats::Stats;
use filesystems::pseudo_filesystems;

const FS_SPEC: usize = 0;
const FS_FILE: usize = 1;
const FS_VFSTYPE: usize = 2;

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();
    opts.optflag("a", "all", "display all filesystems");
    let matches = match opts.parse(&args[1..]) {
        Ok(m)  => m,
        Err(e) => { panic!(e); },
    };

    let file = match File::open("/proc/mounts") {
        Ok(f)  => f,
        Err(e) => {
            println!("Error: Could not open /proc/mounts - {}", e);
            process::exit(1);
        },
    };
    let reader = BufReader::new(&file);

    let excludes = pseudo_filesystems();

    let mut stats: Vec<Stats> = Vec::new();
    let mut max_width = 0;

    for line in reader.lines() {
        match line {
            Ok(line) => {
                let fields: Vec<&str> = line.split_whitespace().collect();
                if !matches.opt_present("a") && excludes.contains(fields[FS_VFSTYPE]) {
                    continue;
                }
                let statvfs = match Statvfs::for_path(fields[FS_FILE]) {
                    Ok(s) => s,
                    Err(err) => {
                        println!("Error: {}", err);
                        continue;
                    },
                };
                let size = statvfs.f_blocks * statvfs.f_bsize;
                let avail = statvfs.f_bavail * statvfs.f_bsize;
                if size == 0 && !matches.opt_present("a") {
                    continue;
                }
                let s = Stats::new(fields[FS_SPEC], size, avail, fields[FS_FILE]);

                max_width = cmp::max(max_width, s.filesystem.len());
                stats.push(s);
            },
            Err(err) => println!("Error: {}", err),
        }
    }

    stats.sort();

    let headers = ["Filesystem", "Size", "Used", "Avail", "Use%", "", "Mounted on"];
    let headers: Vec<ColoredString> = headers.into_iter().map(|x| x.yellow()).collect();
    println!("{:width$} {:>5} {:>5} {:>5} {:>5} {:20} {}",
             headers[0], headers[1], headers[2], headers[3],
             headers[4], headers[5], headers[6], width = max_width);

    for stat in stats {
        let fs = if stat.is_network() {
            stat.filesystem.cyan()
        } else {
            stat.filesystem.normal()
        };
        println!("{:width$} {:>5} {:>5} {:>5} {:>5.1} {:20} {}",
                 fs, iec(stat.size), iec(stat.used), iec(stat.avail),
                 stat.percent, bargraph(stat.percent), stat.mount, width = max_width);
    }

}
<|endoftext|>


<commit_before>#![feature(io)]
use std::io;
use std::io::Write;
use std::process::Command;

mod parser;

fn run_command(cmd: parser::Command) {
    let mut command = Command::new(cmd.cmd)
        .args(cmd.argv)
        .spawn()
        .expect("Failed exec command");
    let ecode = command.wait().expect("failed to wait");
    assert!(ecode.success());
}

fn main() {
    // Main work loop
    let mut parser = parser::Parser::new();

    print!("$ ");
    io::stdout().flush().unwrap();

    loop {
        match parser.get_command().expect("Error parsing command") {
            parser::Line::Full(cmd) => {
                run_command(cmd);
                io::stdout().flush().unwrap();
                print!("$ ");
            }
            parser::Line::Partial => {
                print!("> ");
                io::stdout().flush().unwrap();
            }
            parser::Line::Empty => ()
        }
    }
}
<commit_msg>Flush after prompt<commit_after>#![feature(io)]
use std::io;
use std::io::Write;
use std::process::Command;

mod parser;

fn run_command(cmd: parser::Command) {
    let mut command = Command::new(cmd.cmd)
        .args(cmd.argv)
        .spawn()
        .expect("Failed exec command");
    let ecode = command.wait().expect("failed to wait");
    assert!(ecode.success());
}

fn main() {
    // Main work loop
    let mut parser = parser::Parser::new();

    print!("$ ");
    io::stdout().flush().unwrap();

    loop {
        match parser.get_command().expect("Error parsing command") {
            parser::Line::Full(cmd) => {
                run_command(cmd);
                print!("$ ");
                io::stdout().flush().unwrap();
            }
            parser::Line::Partial => {
                print!("> ");
                io::stdout().flush().unwrap();
            }
            parser::Line::Empty => ()
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
#[macro_use]
extern crate log;
extern crate pretty_env_logger;
extern crate linkerd_tcp;

use clap::{Arg, App};
use linkerd_tcp::app::{self, Runner};
use std::fs;
use std::io::Read;
use std::thread;

static CONFIG_PATH_ARG: &'static str = "PATH";

fn main() {
    // Configure the logger from the RUST_LOG environment variable.
    drop(pretty_env_logger::init());

    // Load command-line options.
    let opts = App::new(crate_name!())
        .version(crate_version!())
        .about(crate_description!())
        .arg(Arg::with_name(CONFIG_PATH_ARG)
            .required(true)
            .index(1)
            .help("Config file path."))
        .get_matches();

    // Parse configuration file.
    let config = {
        let path = opts.value_of(CONFIG_PATH_ARG).unwrap();
        let mut txt = String::new();
        fs::File::open(path)
            .unwrap()
            .read_to_string(&mut txt)
            .expect("failed to read config");
        app::config::from_str(&txt).expect("configuration error")
    };

    // Process the configuration, splitting it into two threads. These threads are
    // connected by synchronization primitives as needed, but no work is being done yet.
    // Next, we'll attach each of these to a reactor in an independent thread, driving
    // both admin and serving work.
    let (admin, proxies) = app::configure(config);

    // Run admin in a new thread.z
    let admin_thread = thread::Builder::new()
        .name("admin".into())
        .spawn(move || admin.run().expect("could not run admin"))
        .expect("could not spawn admin thread");

    proxies.run().expect("could not run proxies");
    admin_thread.join().expect("admin thread failed to join");
    info!("Closing.")
}
<commit_msg>Improve error message when config file cannot be read (#13)<commit_after>#[macro_use]
extern crate clap;
#[macro_use]
extern crate log;
extern crate pretty_env_logger;
extern crate linkerd_tcp;

use clap::{Arg, App};
use linkerd_tcp::app::{self, Runner};
use std::fs;
use std::io::Read;
use std::thread;

static CONFIG_PATH_ARG: &'static str = "PATH";

fn main() {
    // Configure the logger from the RUST_LOG environment variable.
    drop(pretty_env_logger::init());

    // Load command-line options.
    let opts = App::new(crate_name!())
        .version(crate_version!())
        .about(crate_description!())
        .arg(Arg::with_name(CONFIG_PATH_ARG)
            .required(true)
            .index(1)
            .help("Config file path."))
        .get_matches();

    // Parse configuration file.
    let config = {
        let path = opts.value_of(CONFIG_PATH_ARG).unwrap();
        let mut txt = String::new();
        fs::File::open(path)
            .and_then(|mut f| f.read_to_string(&mut txt))
            .expect("failed to read config");
        app::config::from_str(&txt).expect("configuration error")
    };

    // Process the configuration, splitting it into two threads. These threads are
    // connected by synchronization primitives as needed, but no work is being done yet.
    // Next, we'll attach each of these to a reactor in an independent thread, driving
    // both admin and serving work.
    let (admin, proxies) = app::configure(config);

    // Run admin in a new thread.z
    let admin_thread = thread::Builder::new()
        .name("admin".into())
        .spawn(move || admin.run().expect("could not run admin"))
        .expect("could not spawn admin thread");

    proxies.run().expect("could not run proxies");
    admin_thread.join().expect("admin thread failed to join");
    info!("Closing.")
}
<|endoftext|>


<commit_before>use monolith::html::{html_to_dom, stringify_document, walk_and_embed_assets};
use monolith::utils::{data_url_to_text, is_data_url, is_file_url, is_http_url, retrieve_asset};
use reqwest::blocking::Client;
use reqwest::header::{HeaderMap, HeaderValue, USER_AGENT};
use reqwest::Url;
use std::collections::HashMap;
use std::env;
use std::fs;
use std::io::{self, Error, Write};
use std::path::Path;
use std::process;
use std::time::Duration;

mod args;
mod macros;

#[macro_use]
extern crate clap;
use crate::args::AppArgs;

enum Output {
    Stdout(io::Stdout),
    File(fs::File),
}

impl Output {
    fn new(file_path: &str) -> Result<Output, Error> {
        if file_path.is_empty() {
            Ok(Output::Stdout(io::stdout()))
        } else {
            Ok(Output::File(fs::File::create(file_path)?))
        }
    }

    fn writeln_str(&mut self, s: &str) -> Result<(), Error> {
        match self {
            Output::Stdout(stdout) => {
                writeln!(stdout, "{}", s)?;
                stdout.flush()
            }
            Output::File(f) => {
                writeln!(f, "{}", s)?;
                f.flush()
            }
        }
    }
}

fn main() {
    let app_args = AppArgs::get();
    let original_target: &str = &app_args.target;
    let target_url: &str;
    let base_url;
    let dom;

    // Pre-process the input
    let cwd_normalized: String =
        str!(env::current_dir().unwrap().to_str().unwrap()).replace("\\", "/");
    let path = Path::new(original_target);
    let mut target: String = str!(original_target.clone()).replace("\\", "/");
    let path_is_relative: bool = path.is_relative();

    if target.clone().len() == 0 {
        eprintln!("No target specified");
        process::exit(1);
    } else if is_http_url(target.clone()) || is_data_url(target.clone()) {
        target_url = target.as_str();
    } else if is_file_url(target.clone()) {
        target_url = target.as_str();
    } else if path.exists() {
        if !path.is_file() {
            eprintln!("Local target is not a file: {}", original_target);
            process::exit(1);
        }
        target.insert_str(0, if cfg!(windows) { "file:///" } else { "file://" });
        if path_is_relative {
            target.insert_str(if cfg!(windows) { 8 } else { 7 }, &cwd_normalized);
            target.insert_str(
                if cfg!(windows) { 8 } else { 7 } + &cwd_normalized.len(),
                "/",
            );
        }
        target_url = target.as_str();
    } else {
        target.insert_str(0, "http://");
        target_url = target.as_str();
    }

    let mut output = Output::new(&app_args.output).expect("Could not prepare output");

    // Initialize client
    let mut cache = HashMap::new();
    let mut header_map = HeaderMap::new();
    header_map.insert(
        USER_AGENT,
        HeaderValue::from_str(&app_args.user_agent).expect("Invalid User-Agent header specified"),
    );

    let timeout: u64 = if app_args.timeout > 0 {
        app_args.timeout
    } else {
        std::u64::MAX / 4
    };
    let client = Client::builder()
        .timeout(Duration::from_secs(timeout))
        .danger_accept_invalid_certs(app_args.insecure)
        .default_headers(header_map)
        .build()
        .expect("Failed to initialize HTTP client");

    // Retrieve root document
    if is_file_url(target_url) || is_http_url(target_url) {
        let (data, final_url) = retrieve_asset(
            &mut cache,
            &client,
            target_url,
            target_url,
            false,
            "",
            app_args.silent,
        )
        .expect("Could not retrieve target document");
        base_url = final_url;
        dom = html_to_dom(&data);
    } else if is_data_url(target_url) {
        let (media_type, text): (String, String) = data_url_to_text(target_url);
        if !media_type.eq_ignore_ascii_case("text/html") {
            eprintln!("Unsupported data URL media type");
            process::exit(1);
        }
        base_url = str!(target_url);
        dom = html_to_dom(&text);
    } else {
        process::exit(1);
    }

    let time_saved = time::now_utc();

    walk_and_embed_assets(
        &mut cache,
        &client,
        &base_url,
        &dom.document,
        app_args.no_css,
        app_args.no_fonts,
        app_args.no_frames,
        app_args.no_js,
        app_args.no_images,
        app_args.silent,
    );

    let mut html: String = stringify_document(
        &dom.document,
        app_args.no_css,
        app_args.no_frames,
        app_args.no_js,
        app_args.no_images,
        app_args.isolate,
    );

    if !app_args.no_metadata {
        // Safe to unwrap (we just put this through an HTTP request)
        let mut clean_url = Url::parse(&base_url).unwrap();
        clean_url.set_fragment(None);
        // Don't include credentials
        clean_url.set_username("");
        clean_url.set_password(None);
        let metadata_comment = if is_http_url(&base_url) {
            format!(
                "<!--- Saved from {} on {} using {} v{} -->\n",
                &clean_url,
                time_saved.rfc3339(),
                env!("CARGO_PKG_NAME"),
                env!("CARGO_PKG_VERSION"),
            )
        } else {
            format!(
                "<!--- Saved from local source on {} using {} v{} -->\n",
                time_saved.rfc3339(),
                env!("CARGO_PKG_NAME"),
                env!("CARGO_PKG_VERSION"),
            )
        };
        html.insert_str(0, &metadata_comment);
    }

    output
        .writeln_str(&html)
        .expect("Could not write HTML output");
}
<commit_msg>improve metadata comments<commit_after>use monolith::html::{html_to_dom, stringify_document, walk_and_embed_assets};
use monolith::utils::{data_url_to_text, is_data_url, is_file_url, is_http_url, retrieve_asset};
use reqwest::blocking::Client;
use reqwest::header::{HeaderMap, HeaderValue, USER_AGENT};
use reqwest::Url;
use std::collections::HashMap;
use std::env;
use std::fs;
use std::io::{self, Error, Write};
use std::path::Path;
use std::process;
use std::time::Duration;

mod args;
mod macros;

#[macro_use]
extern crate clap;
use crate::args::AppArgs;

enum Output {
    Stdout(io::Stdout),
    File(fs::File),
}

impl Output {
    fn new(file_path: &str) -> Result<Output, Error> {
        if file_path.is_empty() {
            Ok(Output::Stdout(io::stdout()))
        } else {
            Ok(Output::File(fs::File::create(file_path)?))
        }
    }

    fn writeln_str(&mut self, s: &str) -> Result<(), Error> {
        match self {
            Output::Stdout(stdout) => {
                writeln!(stdout, "{}", s)?;
                stdout.flush()
            }
            Output::File(f) => {
                writeln!(f, "{}", s)?;
                f.flush()
            }
        }
    }
}

fn main() {
    let app_args = AppArgs::get();
    let original_target: &str = &app_args.target;
    let target_url: &str;
    let base_url;
    let dom;

    // Pre-process the input
    let cwd_normalized: String =
        str!(env::current_dir().unwrap().to_str().unwrap()).replace("\\", "/");
    let path = Path::new(original_target);
    let mut target: String = str!(original_target.clone()).replace("\\", "/");
    let path_is_relative: bool = path.is_relative();

    if target.clone().len() == 0 {
        eprintln!("No target specified");
        process::exit(1);
    } else if is_http_url(target.clone()) || is_data_url(target.clone()) {
        target_url = target.as_str();
    } else if is_file_url(target.clone()) {
        target_url = target.as_str();
    } else if path.exists() {
        if !path.is_file() {
            eprintln!("Local target is not a file: {}", original_target);
            process::exit(1);
        }
        target.insert_str(0, if cfg!(windows) { "file:///" } else { "file://" });
        if path_is_relative {
            target.insert_str(if cfg!(windows) { 8 } else { 7 }, &cwd_normalized);
            target.insert_str(
                if cfg!(windows) { 8 } else { 7 } + &cwd_normalized.len(),
                "/",
            );
        }
        target_url = target.as_str();
    } else {
        target.insert_str(0, "http://");
        target_url = target.as_str();
    }

    let mut output = Output::new(&app_args.output).expect("Could not prepare output");

    // Initialize client
    let mut cache = HashMap::new();
    let mut header_map = HeaderMap::new();
    header_map.insert(
        USER_AGENT,
        HeaderValue::from_str(&app_args.user_agent).expect("Invalid User-Agent header specified"),
    );

    let timeout: u64 = if app_args.timeout > 0 {
        app_args.timeout
    } else {
        std::u64::MAX / 4
    };
    let client = Client::builder()
        .timeout(Duration::from_secs(timeout))
        .danger_accept_invalid_certs(app_args.insecure)
        .default_headers(header_map)
        .build()
        .expect("Failed to initialize HTTP client");

    // Retrieve root document
    if is_file_url(target_url) || is_http_url(target_url) {
        let (data, final_url) = retrieve_asset(
            &mut cache,
            &client,
            target_url,
            target_url,
            false,
            "",
            app_args.silent,
        )
        .expect("Could not retrieve target document");
        base_url = final_url;
        dom = html_to_dom(&data);
    } else if is_data_url(target_url) {
        let (media_type, text): (String, String) = data_url_to_text(target_url);
        if !media_type.eq_ignore_ascii_case("text/html") {
            eprintln!("Unsupported data URL media type");
            process::exit(1);
        }
        base_url = str!(target_url);
        dom = html_to_dom(&text);
    } else {
        process::exit(1);
    }

    let time_saved = time::now_utc();

    walk_and_embed_assets(
        &mut cache,
        &client,
        &base_url,
        &dom.document,
        app_args.no_css,
        app_args.no_fonts,
        app_args.no_frames,
        app_args.no_js,
        app_args.no_images,
        app_args.silent,
    );

    let mut html: String = stringify_document(
        &dom.document,
        app_args.no_css,
        app_args.no_frames,
        app_args.no_js,
        app_args.no_images,
        app_args.isolate,
    );

    if !app_args.no_metadata {
        // Safe to unwrap (we just put this through an HTTP request)
        let mut clean_url = Url::parse(&base_url).unwrap();
        clean_url.set_fragment(None);
        // Don't include credentials
        clean_url.set_username("");
        clean_url.set_password(None);
        let metadata_comment = if is_http_url(&base_url) {
            format!(
                "<!-- Saved from {} at {} using {} v{} -->\n",
                &clean_url,
                time_saved.rfc3339(),
                env!("CARGO_PKG_NAME"),
                env!("CARGO_PKG_VERSION"),
            )
        } else {
            format!(
                "<!-- Saved from local source at {} using {} v{} -->\n",
                time_saved.rfc3339(),
                env!("CARGO_PKG_NAME"),
                env!("CARGO_PKG_VERSION"),
            )
        };
        html.insert_str(0, &metadata_comment);
    }

    output
        .writeln_str(&html)
        .expect("Could not write HTML output");
}
<|endoftext|>


<commit_before>#![deny(missing_docs,
        missing_debug_implementations, missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unstable_features,
        unused_qualifications)]

//! This binary will group network usage per process nethogs-like. See library documentation or 'lib.rs' for more information.

#[macro_use] extern crate log;
#[macro_use] extern crate enum_primitive;
#[macro_use] extern crate error_chain;
extern crate pnet;
extern crate byteorder;

mod netinfo;
pub use netinfo::*;
pub use pnet::datalink::NetworkInterface;

use std::time::Duration;
use std::thread::sleep;

static SEPARATOR: &'static str = "#####################";

fn main() {
    let net_interface = Netinfo::list_net_interfaces().pop().unwrap();

    println!("Please use applications that send data over network interface '{}' to see statistics.", net_interface.name);
    println!();
    println!("{}", SEPARATOR);
    println!();

    let mut netinfo = Netinfo::new(net_interface).unwrap();
    netinfo.set_autorefresh_interval(Some(Duration::from_millis(100)));
    netinfo.start_async();

    loop {
        let statistics = netinfo.get_net_statistics();
        let mut printed_pid = false;
        for pid in statistics.get_all_pids() {
            let num_incoming_bytes = statistics.get_bytes_per_pid_inout(pid, ConnectionType::Incoming);
            let num_outgoing_bytes = statistics.get_bytes_per_pid_inout(pid, ConnectionType::Outgoing);
            println!("Pid: {}  i: {}kB   o: {}kB", pid, num_incoming_bytes / 1000, num_outgoing_bytes / 1000);
            printed_pid = true;
        }

        if printed_pid {
            let num_total_bytes = statistics.get_total();
            let num_unknown = statistics.get_unassigned_bytes();
            let num_tcp_bytes = statistics.get_bytes_by_transport_type(TransportType::Tcp);
            let num_udp_bytes = statistics.get_bytes_by_transport_type(TransportType::Udp);

            println!();
            println!("Tcp/Udp: {}kB / {}kB", num_tcp_bytes / 1000, num_udp_bytes / 1000);
            println!("Unknown: {}kB", num_unknown / 1000);
            println!("Total: {}kB", num_total_bytes / 1000);
            println!();
            println!("{}", SEPARATOR);
            println!();
        }
        netinfo.clear();
        sleep(Duration::new(1, 0));
    }
}
<commit_msg>fix empty println!<commit_after>#![deny(missing_docs,
        missing_debug_implementations, missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unstable_features,
        unused_qualifications)]

//! This binary will group network usage per process nethogs-like. See library documentation or 'lib.rs' for more information.

#[macro_use] extern crate log;
#[macro_use] extern crate enum_primitive;
#[macro_use] extern crate error_chain;
extern crate pnet;
extern crate byteorder;

mod netinfo;
pub use netinfo::*;
pub use pnet::datalink::NetworkInterface;

use std::time::Duration;
use std::thread::sleep;

static SEPARATOR: &'static str = "#####################";

fn main() {
    let net_interface = Netinfo::list_net_interfaces().pop().unwrap();

    println!("Please use applications that send data over network interface '{}' to see statistics.", net_interface.name);
    println!("");
    println!("{}", SEPARATOR);
    println!("");

    let mut netinfo = Netinfo::new(net_interface).unwrap();
    netinfo.set_autorefresh_interval(Some(Duration::from_millis(100)));
    netinfo.start_async();

    loop {
        let statistics = netinfo.get_net_statistics();
        let mut printed_pid = false;
        for pid in statistics.get_all_pids() {
            let num_incoming_bytes = statistics.get_bytes_per_pid_inout(pid, ConnectionType::Incoming);
            let num_outgoing_bytes = statistics.get_bytes_per_pid_inout(pid, ConnectionType::Outgoing);
            println!("Pid: {}  i: {}kB   o: {}kB", pid, num_incoming_bytes / 1000, num_outgoing_bytes / 1000);
            printed_pid = true;
        }

        if printed_pid {
            let num_total_bytes = statistics.get_total();
            let num_unknown = statistics.get_unassigned_bytes();
            let num_tcp_bytes = statistics.get_bytes_by_transport_type(TransportType::Tcp);
            let num_udp_bytes = statistics.get_bytes_by_transport_type(TransportType::Udp);

            println!("");
            println!("Tcp/Udp: {}kB / {}kB", num_tcp_bytes / 1000, num_udp_bytes / 1000);
            println!("Unknown: {}kB", num_unknown / 1000);
            println!("Total: {}kB", num_total_bytes / 1000);
            println!("");
            println!("{}", SEPARATOR);
            println!("");
        }
        netinfo.clear();
        sleep(Duration::new(1, 0));
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate woodpecker;
use woodpecker as wp;
use wp::handlers::{rotating_file, stdout};

extern crate argparse;
use argparse::{ArgumentParser, StoreTrue, Store};

#[macro_use]
extern crate lazy_static;

extern crate libc;

extern crate mio;
use mio::{Events, Poll, Ready, PollOpt, Token};
use mio::unix::{EventedFd, UnixReady};

use std::ops::Deref;
use std::path::Path;
use std::io::{Write, Read};
use std::process;
use std::fs::File;
use std::os::unix::io::FromRawFd;

lazy_static! {
    static ref B_SUFFIX: Vec<&'static str> = vec!["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
    static ref B_SUFFIX_LOWER: Vec<String> = B_SUFFIX.iter().map(|x| x.to_lowercase()).collect();
}

const BUF_SIZE: usize = 4096;
const NL: u8 = '\n' as u8;
const CR: u8 = '\r' as u8;

#[derive(Debug)]
enum ParseError {
    Invalid,
}

fn unbytify(value: &String) -> Result<u64, ParseError> {
    let value = value.to_lowercase();
    let value = value.trim();

    // w/o any suffix
    match value.parse() {
        Ok(x) => return Ok(x),
        _ => {},
    }

    for (idx, suffix) in B_SUFFIX_LOWER.iter().enumerate().rev() {
        let sfx = &suffix[..1];
        let mut res = value.split(sfx);

        let val: f64 = match res.next() {
            Some(x) => {
                match x.parse() {
                    Ok(x) => x,
                    _ => continue,
                }
            },
            _ => continue,
        };

        match res.next() {
            Some(rest) => {
                if rest.len() > 0 && rest != "b" && rest != "ib" {
                    return Err(ParseError::Invalid);
                }
            },
            _ => {},
        };

        let val = val * 1024u64.pow(idx as u32) as f64;
        return Ok(val.round() as u64);
    }

    Err(ParseError::Invalid)
}

pub fn set_nonblock(fd: libc::c_int) -> Result<(), ()> {
    unsafe {
        let flags = libc::fcntl(fd, libc::F_GETFL);
        let res = libc::fcntl(fd, libc::F_SETFL, flags | libc::O_NONBLOCK);
        if res == -1 {
            Err(())
        } else {
            Ok(())
        }
    }
}

fn main() {
    wp::init();

    let mut count = 10;
    let mut size = "1M".to_string();
    let mut stdout = false;
    let mut date = false;
    let mut file = String::new();

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Pipe logger");
        ap.refer(&mut stdout).add_option(&["--stdout"], StoreTrue, "Log to stdout");
        ap.refer(&mut date).add_option(&["-d", "--date"], StoreTrue, "Insert a timestamp before the log message");
        ap.refer(&mut count).add_option(&["-c", "--count"], Store, "Max number of log files");
        ap.refer(&mut size).add_option(&["-s", "--size"], Store, "Max size of a single log file");
        ap.refer(&mut file).add_argument("file", Store, "Log file name");
        ap.parse_args_or_exit();
    }

    let size: u64 = match unbytify(&size) {
        Ok(val) if val > 0 => val,
        _ => {
            writeln!(&mut std::io::stderr(), "Invalid size").unwrap();
            process::exit(2);
        }
    };

    if stdout {
        wp_register_handler!(stdout::handler());
    }

    if date {
        wp_set_formatter!(Box::new(|record| {
            format!("{} {}", record.ts_utc(), record.msg())
        }));
    } else {
        wp_set_formatter!(Box::new(|record| {
            record.msg().deref().clone()
        }));
    }

    wp_register_handler!(rotating_file::handler(Path::new(&file), count, size));

    let mut stdin = unsafe { File::from_raw_fd(libc::STDIN_FILENO) };
    set_nonblock(libc::STDIN_FILENO).unwrap();

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1);
    let token = Token(0);

    poll.register(&EventedFd(&libc::STDIN_FILENO),
                  token,
                  Ready::readable() | UnixReady::hup(),
                  PollOpt::edge() | PollOpt::level()
    ).unwrap();

    let mut buffer = Vec::new();
    loop {
        poll.poll(&mut events, None).unwrap();

        for event in &events {
            if token != event.token() {
                continue;
            }

            let readiness = event.readiness();

            if readiness.is_readable() {
                let mut chunk = [0; 1];
                match stdin.read_exact(&mut chunk) {
                    Ok(_) => {
                        let ch = chunk[0];
                        if ch == CR {
                            continue;
                        }
                        buffer.push(ch);
                        if ch == NL || buffer.len() == BUF_SIZE {
                            log!("{}", String::from_utf8_lossy(&buffer));
                            buffer.clear();
                        }
                    },
                    _ => {
                        break;
                    },
                }
                continue;
            }

            if UnixReady::from(readiness).is_hup()  {
                if buffer.len() > 0 {
                    log!("{}", String::from_utf8_lossy(&buffer));
                }
                return;
            }
        }
    }
}
<commit_msg>rs: do not output empty lines<commit_after>#[macro_use]
extern crate woodpecker;
use woodpecker as wp;
use wp::handlers::{rotating_file, stdout};

extern crate argparse;
use argparse::{ArgumentParser, StoreTrue, Store};

#[macro_use]
extern crate lazy_static;

extern crate libc;

extern crate mio;
use mio::{Events, Poll, Ready, PollOpt, Token};
use mio::unix::{EventedFd, UnixReady};

use std::path::Path;
use std::io::{Write, Read};
use std::process;
use std::fs::File;
use std::os::unix::io::FromRawFd;

lazy_static! {
    static ref B_SUFFIX: Vec<&'static str> = vec!["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
    static ref B_SUFFIX_LOWER: Vec<String> = B_SUFFIX.iter().map(|x| x.to_lowercase()).collect();
}

const BUF_SIZE: usize = 4096;
const NL: u8 = '\n' as u8;

#[derive(Debug)]
enum ParseError {
    Invalid,
}

fn unbytify(value: &String) -> Result<u64, ParseError> {
    let value = value.to_lowercase();
    let value = value.trim();

    // w/o any suffix
    match value.parse() {
        Ok(x) => return Ok(x),
        _ => {},
    }

    for (idx, suffix) in B_SUFFIX_LOWER.iter().enumerate().rev() {
        let sfx = &suffix[..1];
        let mut res = value.split(sfx);

        let val: f64 = match res.next() {
            Some(x) => {
                match x.parse() {
                    Ok(x) => x,
                    _ => continue,
                }
            },
            _ => continue,
        };

        match res.next() {
            Some(rest) => {
                if rest.len() > 0 && rest != "b" && rest != "ib" {
                    return Err(ParseError::Invalid);
                }
            },
            _ => {},
        };

        let val = val * 1024u64.pow(idx as u32) as f64;
        return Ok(val.round() as u64);
    }

    Err(ParseError::Invalid)
}

pub fn set_nonblock(fd: libc::c_int) -> Result<(), ()> {
    unsafe {
        let flags = libc::fcntl(fd, libc::F_GETFL);
        let res = libc::fcntl(fd, libc::F_SETFL, flags | libc::O_NONBLOCK);
        if res == -1 {
            Err(())
        } else {
            Ok(())
        }
    }
}

fn do_log(buffer: &mut Vec<u8>) {
    log!("{}", String::from_utf8_lossy(buffer));
    buffer.clear();
}

fn main() {
    wp::init();

    let mut count = 10;
    let mut size = "1M".to_string();
    let mut stdout = false;
    let mut date = false;
    let mut file = String::new();

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Pipe logger");
        ap.refer(&mut stdout).add_option(&["--stdout"], StoreTrue, "Log to stdout");
        ap.refer(&mut date).add_option(&["-d", "--date"], StoreTrue, "Insert a timestamp before the log message");
        ap.refer(&mut count).add_option(&["-c", "--count"], Store, "Max number of log files");
        ap.refer(&mut size).add_option(&["-s", "--size"], Store, "Max size of a single log file");
        ap.refer(&mut file).add_argument("file", Store, "Log file name");
        ap.parse_args_or_exit();
    }

    let size: u64 = match unbytify(&size) {
        Ok(val) if val > 0 => val,
        _ => {
            writeln!(&mut std::io::stderr(), "Invalid size").unwrap();
            process::exit(2);
        }
    };

    if stdout {
        wp_register_handler!(stdout::handler());
    }
    wp_register_handler!(rotating_file::handler(Path::new(&file), count, size));

    wp_set_formatter!(Box::new(move |record| {
        if date {
            format!("{} {}\n", record.ts_utc(), record.msg())
        } else {
            format!("{}\n", record.msg())
        }
    }));

    let mut stdin = unsafe { File::from_raw_fd(libc::STDIN_FILENO) };
    set_nonblock(libc::STDIN_FILENO).unwrap();

    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(1);
    let token = Token(0);

    poll.register(&EventedFd(&libc::STDIN_FILENO),
                  token,
                  Ready::readable() | UnixReady::hup(),
                  PollOpt::edge() | PollOpt::level()
    ).unwrap();

    let mut buffer = Vec::new();
    loop {
        poll.poll(&mut events, None).unwrap();

        for event in &events {
            if token != event.token() {
                continue;
            }

            let readiness = event.readiness();

            if readiness.is_readable() {
                let mut chunk = [0; 1];
                match stdin.read_exact(&mut chunk) {
                    Ok(_) => {
                        let ch = chunk[0];
                        if ch == NL {
                            if !buffer.is_empty() {
                                do_log(&mut buffer);
                            }
                        } else {
                            buffer.push(ch);
                            if buffer.len() == BUF_SIZE {
                                do_log(&mut buffer);
                            }
                        }
                    },
                    _ => {
                        break;
                    },
                }
                continue;
            }

            if UnixReady::from(readiness).is_hup()  {
                if buffer.len() > 0 {
                    do_log(&mut buffer);
                }
                return;
            }
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate "rust-md2" as md2;

use md2::{S, S2, md2_compress};
use std::collections::HashMap;
use std::num::Int;

pub fn main() {
    let rows = 14;
    let mut values = [[0u8, ..49], ..19];

    for row in range(1, rows + 1) {
      // Fill row of T1.
      for i in range(1, 17) {
          values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
      }

      // Last bytes are equal.
      values[row][32] = values[row][16];
      values[row][48] = values[row][16];

      // Next t value.
      values[row + 1][0] = values[row][48] + (row as u8) - 1;
    }

    // Compute triangles.
    for col in range(0, rows) {
      for row in range(0, rows - col - 1) {
        let row2 = rows - row;
        values[row2][32 - col - 1] = S2[(values[row2][32 - col] ^ values[row2 - 1][32 - col]) as uint];
        values[row2][48 - col - 1] = S2[(values[row2][48 - col] ^ values[row2 - 1][48 - col]) as uint];
      }
    }

    let mut collisions: HashMap<u64,Vec<u64>> = HashMap::new();

    // TODO random bytes
    for bytes in range(0u64, 256u64.pow(16 - rows)) {
        // TODO set bytes
        let mut shift = (16 - rows - 1) * 8;
        for col in range(17, 17 + 16 - rows) {
            values[rows][col] = (bytes >> shift) as u8;
            values[rows][col + 16] = (bytes >> shift) as u8;
            shift -= 8;
        }

        for row in range(rows + 1, 18) {
            // Fill row.
            for i in range(1, 49) {
                values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
            }

            // Next t value.
            values[row + 1][0] = values[row][48] + (row as u8) - 1;
        }

        let mut key = 0u64;
        let mut shift = (16 - rows) * 8;
        for row in range(rows + 2, 19) {
            key |= (values[row][0] as u64) << shift;
            shift -= 8;
        }

        if !collisions.contains_key(&key) {
            collisions.insert(key, vec!());
        }

        match collisions.get_mut(&key) {
            Some(vec) => vec.push(bytes),
            None => panic!("unreachable")
        }
    }

    // Compute original messages for each collision.
    let mut count = 0u;
    for collision in collisions.values().filter(|x| x.len() > 1) {
        count += 1;
        for bytes in collision.iter() {
            // TODO set bytes
            let mut shift = (16 - rows - 1) * 8;
            for col in range(17, 17 + 16 - rows) {
                values[rows][col] = (*bytes >> shift) as u8;
                values[rows][col + 16] = (*bytes >> shift) as u8;
                shift -= 8;
            }

            // Fill upper rectangles.
            for row in range(0, rows) {
                let row2 = rows - row;
                for col in range(17, 32 - row2 + 2) {
                    values[row2 - 1][col] = S[values[row2][col - 1] as uint] ^ values[row2][col];
                }
            }

            let empty = [0u8, ..16];
            let msg = values[0].slice(17, 33).iter().fold(String::new(), |a, &b| format!("{}{:02x}", a, b));
            let hash = md2_compress(&empty, values[0].slice(17, 33)).iter().fold(String::new(), |a, &b| format!("{}{:02x}", a, b));
            println!("msg = {}, hash = {}", msg, hash);
        }

        println!("");
    }

    println!("Found {} collisions.", count);
}
<commit_msg>simplify hash map stuff<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate "rust-md2" as md2;

use md2::{S, S2, md2_compress};
use std::collections::HashMap;
use std::collections::hash_map::{Occupied, Vacant};
use std::num::Int;

pub fn main() {
    let rows = 14;
    let mut values = [[0u8, ..49], ..19];

    for row in range(1, rows + 1) {
      // Fill row of T1.
      for i in range(1, 17) {
          values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
      }

      // Last bytes are equal.
      values[row][32] = values[row][16];
      values[row][48] = values[row][16];

      // Next t value.
      values[row + 1][0] = values[row][48] + (row as u8) - 1;
    }

    // Compute triangles.
    for col in range(0, rows) {
      for row in range(0, rows - col - 1) {
        let row2 = rows - row;
        values[row2][32 - col - 1] = S2[(values[row2][32 - col] ^ values[row2 - 1][32 - col]) as uint];
        values[row2][48 - col - 1] = S2[(values[row2][48 - col] ^ values[row2 - 1][48 - col]) as uint];
      }
    }

    let mut collisions: HashMap<String,Vec<u64>> = HashMap::new();

    // TODO random bytes
    for bytes in range(0u64, 256u64.pow(16 - rows)) {
        // TODO set bytes
        let mut shift = (16 - rows - 1) * 8;
        for col in range(17, 17 + 16 - rows) {
            values[rows][col] = (bytes >> shift) as u8;
            values[rows][col + 16] = (bytes >> shift) as u8;
            shift -= 8;
        }

        for row in range(rows + 1, 18) {
            // Fill row.
            for i in range(1, 49) {
                values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
            }

            // Next t value.
            values[row + 1][0] = values[row][48] + (row as u8) - 1;
        }

        // TODO use byte string?
        let key = range(rows + 2, 19).fold(String::new(), |acc, row| {
          format!("{}{:02x}", acc, values[row][0])
        });

        match collisions.entry(key) {
            Vacant(entry) => { entry.set(vec!(bytes)); },
            Occupied(mut entry) => { entry.get_mut().push(bytes); }
        };
    }

    // Compute original messages for each collision.
    let mut count = 0u;
    for collision in collisions.values().filter(|x| x.len() > 1) {
        count += 1;
        for bytes in collision.iter() {
            // TODO set bytes
            let mut shift = (16 - rows - 1) * 8;
            for col in range(17, 17 + 16 - rows) {
                values[rows][col] = (*bytes >> shift) as u8;
                values[rows][col + 16] = (*bytes >> shift) as u8;
                shift -= 8;
            }

            // Fill upper rectangles.
            for row in range(0, rows) {
                let row2 = rows - row;
                for col in range(17, 32 - row2 + 2) {
                    values[row2 - 1][col] = S[values[row2][col - 1] as uint] ^ values[row2][col];
                }
            }

            let empty = [0u8, ..16];
            let msg = values[0].slice(17, 33).iter().fold(String::new(), |a, &b| format!("{}{:02x}", a, b));
            let hash = md2_compress(&empty, values[0].slice(17, 33)).iter().fold(String::new(), |a, &b| format!("{}{:02x}", a, b));
            println!("msg = {}, hash = {}", msg, hash);
        }

        println!("");
    }

    println!("Found {} collisions.", count);
}
<|endoftext|>