<commit_before>use std::io::{self, BufReader, Write};
use std::io::BufRead;
use std::net::TcpStream;
use std::fs::File;

extern crate chrono;
use chrono::*;

extern crate stats;
use stats::median;

extern crate clap;
use clap::{Arg, App};

mod percentile;
use percentile::percentile;

mod http_status;

mod request_response;
use request_response::*;

pub fn open_logfile(path: &str, time_filter: Option<Duration>) -> Result<(Vec<Request>,Vec<Response>), io::Error> {
    let f = try!(File::open(path));

    let f = BufReader::new(f);

    let mut requests: Vec<Request> = Vec::new();
    let mut responses: Vec<Response> = Vec::new();

    for line in f.lines() {
        let line_value = &line.unwrap();

        if line_value.contains("->") {
            let r = try!(Request::new_from_log_line(&line_value));

            if time_filter.is_none() ||
              (time_filter.is_some() && r.is_between_times(UTC::now().with_timezone(&r.time.timezone()) - time_filter.unwrap(), UTC::now().with_timezone(&r.time.timezone()))) {
                requests.push(r);
            }
        }

        if line_value.contains("<-") {
            let r = try!(Response::new_from_log_line(&line_value));
            responses.push(r);
        }

    }

    responses.sort_by_key(|r| r.id);

    Ok((requests, responses))
}

#[derive(Eq, PartialEq)]
#[derive(Debug)]
pub struct RequestLogAnalyzerResult {
    count: usize,
    max: usize,
    min: usize,
    avg: usize,
    median: usize,
    percentile90: usize,
}

pub fn analyze(request_response_pairs: &Vec<RequestResponsePair>) -> Option<RequestLogAnalyzerResult> {
    if request_response_pairs.len() == 0 {
        return None;
    }

    let times: Vec<i64> = request_response_pairs.iter()
        .map(|rr: &RequestResponsePair| -> i64 {rr.response.response_time.num_milliseconds() })
        .collect();

    let sum: usize = times.iter().sum::<i64>() as usize;
    let avg: usize = sum / times.len();

    let max: usize = *times.iter().max().unwrap() as usize;
    let min: usize = *times.iter().min().unwrap() as usize;

    let percentile90: usize = percentile(&times, 0.9) as usize;

    let median = median(times.into_iter()).unwrap() as usize;

    Some(RequestLogAnalyzerResult {
        count: request_response_pairs.len().into(),
        max: max,
        min: min,
        avg: avg,
        median: median,
        percentile90: percentile90,
    })
}

fn render_terminal(result: RequestLogAnalyzerResult) {
    println!("count:\t{}", result.count);
    println!("time.avg:\t{}", result.avg);
    println!("time.min:\t{}", result.min);
    println!("time.median:\t{}", result.median);
    println!("time.90percent:\t{}", result.percentile90);
    println!("time.max:\t{}", result.max);
}

pub fn render_graphite<T: Write>(result: RequestLogAnalyzerResult, time: DateTime<FixedOffset>, mut stream: T) {
    let mut write = |text: String| {
        stream.write(
            format!("{} {}\n", text, time.timestamp() )
            .as_bytes()
        );
    };

    write(format!("requests.count {}", result.count));
    write(format!("requests.time.max {}", result.max));
    write(format!("requests.time.min {}", result.min));
    write(format!("requests.time.avg {}", result.avg));
    write(format!("requests.time.median {}", result.median));
    write(format!("requests.time.90percent {}", result.percentile90));
}

fn main() {
    let args = App::new("Request.log Analyzer")
        .arg(Arg::with_name("filename")
            .index(1)
            .value_name("FILE")
            .required(true)
            .help("Log file to analyze")
            .takes_value(true))
        .arg(Arg::with_name("time_filter_minutes")
            .value_name("MINUTES")
            .short("t")
            .help("Limit to the last n minutes")
            .takes_value(true))
        .arg(Arg::with_name("include_term")
            .value_name("TERM")
            .long("include")
            .help("Only includes lines that contain this term")
            .takes_value(true))
        .arg(Arg::with_name("exclude_term")
            .value_name("TERM")
            .long("exclude")
            .help("Excludes lines that contain this term")
            .takes_value(true))
        .get_matches();

    let filename = args.value_of("filename").unwrap();

    let time_filter = match args.value_of("time_filter_minutes") {
        Some(minutes) => Some(Duration::minutes(minutes.parse().unwrap())),
        None => None
    };

    let lines = open_logfile(filename, time_filter);
    let (requests, responses) = lines.unwrap();

    let time_zone = &requests[0].time.timezone();

    let pairs: Vec<RequestResponsePair> = pair_requests_responses(requests, responses)
        .into_iter()
        .filter(|rr| rr.matches_include_exclude_filter(
            args.value_of("include_term"),
            args.value_of("exclude_term")
        ))
        .collect();

    let stream = TcpStream::connect("127.0.0.1:2003").unwrap();

    match analyze(&pairs) {
        // Some(result) => render_terminal(result),
        Some(result) => render_graphite(result, UTC::now().with_timezone(time_zone), stream),
        None => println!("No matching log lines in file.")
    }
}

#[cfg(test)]
mod tests {
	use super::*;
    use request_response::*;
    extern crate chrono;
    use chrono::*;

    #[test]
    fn test_open_logfile() {
        let lines = open_logfile("src/test/simple-1.log", None);
        let (requests, responses) = lines.unwrap();

        assert_eq!(requests.len(), 2);
        assert_eq!(responses.len(), 2);
    }

    #[test]
    fn test_open_logfile_time_filter() {
        let time_filter: Duration = Duration::minutes(1);
        let lines = open_logfile("src/test/simple-1.log", Some(time_filter));
        let (requests, responses) = lines.unwrap();

        assert_eq!(requests.len(), 0);

        let time_filter: Duration = Duration::minutes(52560000); // 100 years
        let lines = open_logfile("src/test/simple-1.log", Some(time_filter));
        let (requests, responses) = lines.unwrap();

        assert_eq!(requests.len(), 2);
    }

    #[test]
    fn test_pair_requests_resonses() {
        let lines = open_logfile("src/test/simple-1.log", None);
        let (requests, responses) = lines.unwrap();

        let result = pair_requests_responses(requests, responses);

        assert_eq!(result.len(), 2);

        assert_eq!(result[0].request.id, result[0].response.id);
        assert_eq!(result[1].request.id, result[1].response.id);
    }

    #[test]
    fn test_request_log_analyzer_result() {
        let lines = open_logfile("src/test/response-time-calculations.log", None);
        let (requests, responses) = lines.unwrap();

        let request_response_pairs = pair_requests_responses(requests, responses);

        let result = analyze(&request_response_pairs);

        let expected = Some(RequestLogAnalyzerResult {
            count: 3,
            max: 100,
            min: 1,
            avg: 37,
            median: 10,
            percentile90: 100,
        });

        assert_eq!(result, expected);
    }

    #[test]
    fn test_request_log_analyze_none_matching() {
        let lines = open_logfile("src/test/simple-1.log", Some(Duration::minutes(0)));
        let (requests, responses) = lines.unwrap();

        let request_response_pairs = pair_requests_responses(requests, responses);

        let result = analyze(&request_response_pairs);

        let expected = None;

        assert_eq!(result, expected);
    }

    #[test]
    fn test_90_percentile_calculation() {
        let lines = open_logfile("src/test/percentile.log", None);
        let (requests, responses) = lines.unwrap();

        let request_response_pairs = pair_requests_responses(requests, responses);

        let result: RequestLogAnalyzerResult = analyze(&request_response_pairs).unwrap();

        assert_eq!(result.percentile90, 9);
    }

    #[test]
    fn test_render_graphite() {
        use std::io::{self, BufReader};
        use std::io::prelude::Write;
        use std::str;

        struct MockTcpStream {
            write_calls: Vec<String>,
        };

        impl Write for MockTcpStream {
            fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
                self.write_calls.push(str::from_utf8(buf).unwrap().to_string());
                Ok(1)
            }

            fn flush(&mut self) -> io::Result<()> { Ok(()) }
        }

        let mut mock_tcp_stream = MockTcpStream {
            write_calls: vec![]
        };

        render_graphite(RequestLogAnalyzerResult {
                count: 3,
                max: 100,
                min: 1,
                avg: 37,
                median: 10,
                percentile90: 100,
            },
            DateTime::parse_from_str("22/Sep/2016:22:41:59 +0200", "%d/%b/%Y:%H:%M:%S %z").unwrap(),
            &mut mock_tcp_stream
        );

        assert_eq!(&mock_tcp_stream.write_calls[0], "requests.count 3 1474576919\n");
        assert_eq!(&mock_tcp_stream.write_calls[1], "requests.time.max 100 1474576919\n");
        assert_eq!(&mock_tcp_stream.write_calls[2], "requests.time.min 1 1474576919\n");
        assert_eq!(&mock_tcp_stream.write_calls[3], "requests.time.avg 37 1474576919\n");
        assert_eq!(&mock_tcp_stream.write_calls[4], "requests.time.median 10 1474576919\n");
        assert_eq!(&mock_tcp_stream.write_calls[5], "requests.time.90percent 100 1474576919\n");
    }
}
<commit_msg>Extract argument parsing from main()<commit_after>use std::io::{self, BufReader, Write};
use std::io::BufRead;
use std::net::TcpStream;
use std::fs::File;

extern crate chrono;
use chrono::*;

extern crate stats;
use stats::median;

extern crate clap;
use clap::{Arg, App, ArgMatches};

mod percentile;
use percentile::percentile;

mod http_status;

mod request_response;
use request_response::*;

pub fn open_logfile(path: &str, time_filter: Option<Duration>) -> Result<(Vec<Request>,Vec<Response>), io::Error> {
    let f = try!(File::open(path));

    let f = BufReader::new(f);

    let mut requests: Vec<Request> = Vec::new();
    let mut responses: Vec<Response> = Vec::new();

    for line in f.lines() {
        let line_value = &line.unwrap();

        if line_value.contains("->") {
            let r = try!(Request::new_from_log_line(&line_value));

            if time_filter.is_none() ||
              (time_filter.is_some() && r.is_between_times(UTC::now().with_timezone(&r.time.timezone()) - time_filter.unwrap(), UTC::now().with_timezone(&r.time.timezone()))) {
                requests.push(r);
            }
        }

        if line_value.contains("<-") {
            let r = try!(Response::new_from_log_line(&line_value));
            responses.push(r);
        }

    }

    responses.sort_by_key(|r| r.id);

    Ok((requests, responses))
}

#[derive(Eq, PartialEq)]
#[derive(Debug)]
pub struct RequestLogAnalyzerResult {
    count: usize,
    max: usize,
    min: usize,
    avg: usize,
    median: usize,
    percentile90: usize,
}

pub fn analyze(request_response_pairs: &Vec<RequestResponsePair>) -> Option<RequestLogAnalyzerResult> {
    if request_response_pairs.len() == 0 {
        return None;
    }

    let times: Vec<i64> = request_response_pairs.iter()
        .map(|rr: &RequestResponsePair| -> i64 {rr.response.response_time.num_milliseconds() })
        .collect();

    let sum: usize = times.iter().sum::<i64>() as usize;
    let avg: usize = sum / times.len();

    let max: usize = *times.iter().max().unwrap() as usize;
    let min: usize = *times.iter().min().unwrap() as usize;

    let percentile90: usize = percentile(&times, 0.9) as usize;

    let median = median(times.into_iter()).unwrap() as usize;

    Some(RequestLogAnalyzerResult {
        count: request_response_pairs.len().into(),
        max: max,
        min: min,
        avg: avg,
        median: median,
        percentile90: percentile90,
    })
}

fn render_terminal(result: RequestLogAnalyzerResult) {
    println!("count:\t{}", result.count);
    println!("time.avg:\t{}", result.avg);
    println!("time.min:\t{}", result.min);
    println!("time.median:\t{}", result.median);
    println!("time.90percent:\t{}", result.percentile90);
    println!("time.max:\t{}", result.max);
}

pub fn render_graphite<T: Write>(result: RequestLogAnalyzerResult, time: DateTime<FixedOffset>, mut stream: T) {
    let mut write = |text: String| {
        stream.write(
            format!("{} {}\n", text, time.timestamp() )
            .as_bytes()
        );
    };

    write(format!("requests.count {}", result.count));
    write(format!("requests.time.max {}", result.max));
    write(format!("requests.time.min {}", result.min));
    write(format!("requests.time.avg {}", result.avg));
    write(format!("requests.time.median {}", result.median));
    write(format!("requests.time.90percent {}", result.percentile90));
}

fn parse_args<'a>() -> ArgMatches<'a> {
    App::new("Request.log Analyzer")
        .arg(Arg::with_name("filename")
            .index(1)
            .value_name("FILE")
            .required(true)
            .help("Log file to analyze")
            .takes_value(true))
        .arg(Arg::with_name("time_filter_minutes")
            .value_name("MINUTES")
            .short("t")
            .help("Limit to the last n minutes")
            .takes_value(true))
        .arg(Arg::with_name("include_term")
            .value_name("TERM")
            .long("include")
            .help("Only includes lines that contain this term")
            .takes_value(true))
        .arg(Arg::with_name("exclude_term")
            .value_name("TERM")
            .long("exclude")
            .help("Excludes lines that contain this term")
            .takes_value(true))
        .get_matches()
}

fn main() {
    let args = parse_args();

    let filename = args.value_of("filename").unwrap();

    let time_filter = match args.value_of("time_filter_minutes") {
        Some(minutes) => Some(Duration::minutes(minutes.parse().unwrap())),
        None => None
    };

    let lines = open_logfile(filename, time_filter);
    let (requests, responses) = lines.unwrap();

    let time_zone = &requests[0].time.timezone();

    let pairs: Vec<RequestResponsePair> = pair_requests_responses(requests, responses)
        .into_iter()
        .filter(|rr| rr.matches_include_exclude_filter(
            args.value_of("include_term"),
            args.value_of("exclude_term")
        ))
        .collect();

    let stream = TcpStream::connect("127.0.0.1:2003").unwrap();

    match analyze(&pairs) {
        // Some(result) => render_terminal(result),
        Some(result) => render_graphite(result, UTC::now().with_timezone(time_zone), stream),
        None => println!("No matching log lines in file.")
    }
}

#[cfg(test)]
mod tests {
	use super::*;
    use request_response::*;
    extern crate chrono;
    use chrono::*;

    #[test]
    fn test_open_logfile() {
        let lines = open_logfile("src/test/simple-1.log", None);
        let (requests, responses) = lines.unwrap();

        assert_eq!(requests.len(), 2);
        assert_eq!(responses.len(), 2);
    }

    #[test]
    fn test_open_logfile_time_filter() {
        let time_filter: Duration = Duration::minutes(1);
        let lines = open_logfile("src/test/simple-1.log", Some(time_filter));
        let (requests, responses) = lines.unwrap();

        assert_eq!(requests.len(), 0);

        let time_filter: Duration = Duration::minutes(52560000); // 100 years
        let lines = open_logfile("src/test/simple-1.log", Some(time_filter));
        let (requests, responses) = lines.unwrap();

        assert_eq!(requests.len(), 2);
    }

    #[test]
    fn test_pair_requests_resonses() {
        let lines = open_logfile("src/test/simple-1.log", None);
        let (requests, responses) = lines.unwrap();

        let result = pair_requests_responses(requests, responses);

        assert_eq!(result.len(), 2);

        assert_eq!(result[0].request.id, result[0].response.id);
        assert_eq!(result[1].request.id, result[1].response.id);
    }

    #[test]
    fn test_request_log_analyzer_result() {
        let lines = open_logfile("src/test/response-time-calculations.log", None);
        let (requests, responses) = lines.unwrap();

        let request_response_pairs = pair_requests_responses(requests, responses);

        let result = analyze(&request_response_pairs);

        let expected = Some(RequestLogAnalyzerResult {
            count: 3,
            max: 100,
            min: 1,
            avg: 37,
            median: 10,
            percentile90: 100,
        });

        assert_eq!(result, expected);
    }

    #[test]
    fn test_request_log_analyze_none_matching() {
        let lines = open_logfile("src/test/simple-1.log", Some(Duration::minutes(0)));
        let (requests, responses) = lines.unwrap();

        let request_response_pairs = pair_requests_responses(requests, responses);

        let result = analyze(&request_response_pairs);

        let expected = None;

        assert_eq!(result, expected);
    }

    #[test]
    fn test_90_percentile_calculation() {
        let lines = open_logfile("src/test/percentile.log", None);
        let (requests, responses) = lines.unwrap();

        let request_response_pairs = pair_requests_responses(requests, responses);

        let result: RequestLogAnalyzerResult = analyze(&request_response_pairs).unwrap();

        assert_eq!(result.percentile90, 9);
    }

    #[test]
    fn test_render_graphite() {
        use std::io::{self, BufReader};
        use std::io::prelude::Write;
        use std::str;

        struct MockTcpStream {
            write_calls: Vec<String>,
        };

        impl Write for MockTcpStream {
            fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
                self.write_calls.push(str::from_utf8(buf).unwrap().to_string());
                Ok(1)
            }

            fn flush(&mut self) -> io::Result<()> { Ok(()) }
        }

        let mut mock_tcp_stream = MockTcpStream {
            write_calls: vec![]
        };

        render_graphite(RequestLogAnalyzerResult {
                count: 3,
                max: 100,
                min: 1,
                avg: 37,
                median: 10,
                percentile90: 100,
            },
            DateTime::parse_from_str("22/Sep/2016:22:41:59 +0200", "%d/%b/%Y:%H:%M:%S %z").unwrap(),
            &mut mock_tcp_stream
        );

        assert_eq!(&mock_tcp_stream.write_calls[0], "requests.count 3 1474576919\n");
        assert_eq!(&mock_tcp_stream.write_calls[1], "requests.time.max 100 1474576919\n");
        assert_eq!(&mock_tcp_stream.write_calls[2], "requests.time.min 1 1474576919\n");
        assert_eq!(&mock_tcp_stream.write_calls[3], "requests.time.avg 37 1474576919\n");
        assert_eq!(&mock_tcp_stream.write_calls[4], "requests.time.median 10 1474576919\n");
        assert_eq!(&mock_tcp_stream.write_calls[5], "requests.time.90percent 100 1474576919\n");
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate rand;
extern crate cgmath;
#[macro_use]
extern crate gfx;
extern crate gfx_app;
extern crate winit;

use std::time::Instant;
use std::ops::Neg;

use gfx_app::ColorFormat;
use gfx::{Bundle, ShaderSet, Primitive, buffer, Bind, Slice};
use gfx::state::Rasterizer;
use cgmath::{Matrix4, Vector3, Vector2, Basis2, ElementWise, Zero, Rotation2, Rotation, Rad, Deg};

// Declare the vertex format suitable for drawing,
// as well as the constants used by the shaders
// and the pipeline state object format.
gfx_defines! {
    // Data for each particle
    vertex Vertex {
        pos: [f32; 2] = "a_Pos",
        radius: f32 = "a_Radius",
        time: f32 = "a_Time",
        base_color: [f32; 4] = "a_BaseColor",
        new_color: [f32; 4] = "a_NewColor",
    }

    // Aspect ratio to keep particles round
    constant Locals {
        transformation: [[f32; 4]; 4] = "u_Transformation",
    }

    // Particle render pipeline
    pipeline circles {
        vbuf: gfx::VertexBuffer<Vertex> = (),
        locals: gfx::ConstantBuffer<Locals> = "Locals",
        out_color: gfx::BlendTarget<ColorFormat> = ("Target0", gfx::state::ColorMask::all(), gfx::preset::blend::ALPHA),
    }
}

impl Vertex {
    // Construct new particles far away so they can't be seen initially
    fn new() -> Vertex {
        Vertex {
            pos: [std::f32::INFINITY, std::f32::INFINITY],
            radius: 50.0,
            time: 0.0,
            base_color: Default::default(),
            new_color: Default::default(),
        }
    }
}

struct Camera {
    pub pos: Vector2<f32>,
    pub up: bool,
    pub right: bool,
    pub down: bool,
    pub left: bool,
}

impl Camera {
    pub fn compute(&mut self, time: f32) {
        self.pos += self.camera_speed() * time;
    }

    fn camera_speed(&self) -> Vector2<f32> {
        let angle = match (self.up, self.right, self.down, self.left) {
            (true, true, false, false) => 45.0,
            (true, false, false, true) => 135.0,
            (false, false, true, true) => 225.0,
            (false, true, true, false) => 315.0,
            (_, true, _, false) => 0.0,
            (true, _, false, _) => 90.0,
            (_, false, _, true) => 180.0,
            (false, _, true, _) => 270.0,
            _ => -1.0,
        };

        if angle == -1.0 {
            return Vector2::zero();
        }

        Basis2::from_angle(Deg(angle))
            .rotate_vector(Vector2::new(200.0, 0.0))
    }
}

struct App<R: gfx::Resources> {
    bundle: Bundle<R, circles::Data<R>>,
    circle: Vertex,
    time_start: Instant,
    camera: Camera,
}

fn create_shader_set<R: gfx::Resources, F: gfx::Factory<R>>(factory: &mut F,
                                                            vs_code: &[u8],
                                                            gs_code: &[u8],
                                                            ps_code: &[u8]) -> ShaderSet<R> {
    let vs = factory.create_shader_vertex(vs_code).expect("Failed to compile vertex shader");
    let gs = factory.create_shader_geometry(gs_code).expect("Failed to compile geometry shader");
    let ps = factory.create_shader_pixel(ps_code).expect("Failed to compile pixel shader");
    ShaderSet::Geometry(vs, gs, ps)
}

impl<R: gfx::Resources> gfx_app::Application<R> for App<R> {
    fn new<F: gfx::Factory<R>>(factory: &mut F, backend: gfx_app::shade::Backend,
                               window_targets: gfx_app::WindowTargets<R>) -> Self {
        use gfx::traits::FactoryExt;

        // Load in our vertex, geometry and pixel shaders
        let vs = gfx_app::shade::Source {
            glsl_150: include_bytes!("shaders/circle_150.glslv"),
            .. gfx_app::shade::Source::empty()
        };
        let gs = gfx_app::shade::Source {
            glsl_150: include_bytes!("shaders/circle_150.glslg"),
            .. gfx_app::shade::Source::empty()
        };
        let ps = gfx_app::shade::Source {
            glsl_150: include_bytes!("shaders/circle_150.glslf"),
            .. gfx_app::shade::Source::empty()
        };

        let shader_set = create_shader_set(
            factory,
            vs.select(backend).unwrap(),
            gs.select(backend).unwrap(),
            ps.select(backend).unwrap(),
        );

        // Create 4096 particles, using one point vertex per particle
        let mut circle = Vertex::new();

        // Create a dynamic vertex buffer to hold the particle data
        let vbuf = factory.create_buffer(1,
                                         buffer::Role::Vertex,
                                         gfx::memory::Usage::Dynamic,
                                         Bind::empty())
            .expect("Failed to create vertex buffer");
        let slice = Slice::new_match_vertex_buffer(&vbuf);

        // Construct our pipeline state
        let pso = factory.create_pipeline_state(
            &shader_set,
            Primitive::PointList,
            Rasterizer::new_fill(),
            circles::new()
        ).unwrap();

        circle.pos = [0.0, 0.0];
        circle.base_color = [rand::random(), rand::random(), rand::random(), 1.0];
        circle.new_color = [rand::random(), rand::random(), rand::random(), 1.0];

        let data = circles::Data {
            vbuf: vbuf,
            locals: factory.create_constant_buffer(1),
            out_color: window_targets.color,
        };

        App {
            bundle: Bundle::new(slice, pso, data),
            circle: circle,
            time_start: Instant::now(),
            camera: Camera {
                pos: Vector2::zero(),
                up: false,
                right: false,
                down: false,
                left: false,
            }
        }
    }

    fn render<C: gfx::CommandBuffer<R>>(&mut self, encoder: &mut gfx::Encoder<R, C>) {
        // Compute the time since last frame
        let delta = self.time_start.elapsed();
        self.time_start = Instant::now();
        let delta = delta.as_secs() as f32 + delta.subsec_nanos() as f32 / 1000_000_000.0;

        let anim_duration = 1.7;
        self.circle.time = self.circle.time + delta / anim_duration;
        if self.circle.time > 1. {
            self.circle.time %= 1.;
            let base_color = self.circle.base_color;
            self.circle.base_color = self.circle.new_color;
            self.circle.new_color = base_color;
        }

        let (width, height, _, _) = self.bundle.data.out_color.get_dimensions();

        self.camera.compute(delta);
        let scale_vector = Vector3::new(1.0 / width as f32 * 4.0, 1.0 / height as f32 * 4.0, 1.0);
        let camera_translation = Matrix4::from_translation(
            self.camera.pos.neg().extend(0.0).mul_element_wise(scale_vector)
        );
        let scale = Matrix4::from_nonuniform_scale(scale_vector.x, scale_vector.y, scale_vector.z);

        // Pass in the aspect ratio to the geometry shader
        let locals = Locals { transformation: (camera_translation * scale).into() };
        encoder.update_constant_buffer(&self.bundle.data.locals, &locals);
        // Update the vertex data with the changes to the particles array
        encoder.update_buffer(&self.bundle.data.vbuf, &[self.circle], 0).unwrap();
        // Clear the background to dark blue
        encoder.clear(&self.bundle.data.out_color, [0.1, 0.2, 0.3, 1.0]);
        // Draw the particles!
        self.bundle.encode(encoder);
    }

    fn on_resize(&mut self, window_targets: gfx_app::WindowTargets<R>) {
        self.bundle.data.out_color = window_targets.color;
    }

    fn on(&mut self, event: winit::WindowEvent) {
        match event {
            winit::WindowEvent::KeyboardInput(winit::ElementState::Pressed, _, Some(winit::VirtualKeyCode::W), _) => {
                self.camera.up = true;
            },
            winit::WindowEvent::KeyboardInput(winit::ElementState::Pressed, _, Some(winit::VirtualKeyCode::D), _) => {
                self.camera.right = true;
            },
            winit::WindowEvent::KeyboardInput(winit::ElementState::Pressed, _, Some(winit::VirtualKeyCode::S), _) => {
                self.camera.down = true;
            },
            winit::WindowEvent::KeyboardInput(winit::ElementState::Pressed, _, Some(winit::VirtualKeyCode::A), _) => {
                self.camera.left = true;
            },
            winit::WindowEvent::KeyboardInput(winit::ElementState::Released, _, Some(winit::VirtualKeyCode::W), _) => {
                self.camera.up = false;
            },
            winit::WindowEvent::KeyboardInput(winit::ElementState::Released, _, Some(winit::VirtualKeyCode::D), _) => {
                self.camera.right = false;
            },
            winit::WindowEvent::KeyboardInput(winit::ElementState::Released, _, Some(winit::VirtualKeyCode::S), _) => {
                self.camera.down = false;
            },
            winit::WindowEvent::KeyboardInput(winit::ElementState::Released, _, Some(winit::VirtualKeyCode::A), _) => {
                self.camera.left = false;
            },
            _ => ()
        }
    }
}

pub fn main() {
    use gfx_app::Application;
    App::launch_simple("circles-rs");
}
<commit_msg>Drop accidentally copypasted license from main.rs<commit_after>extern crate rand;
extern crate cgmath;
#[macro_use]
extern crate gfx;
extern crate gfx_app;
extern crate winit;

use std::time::Instant;
use std::ops::Neg;

use gfx_app::ColorFormat;
use gfx::{Bundle, ShaderSet, Primitive, buffer, Bind, Slice};
use gfx::state::Rasterizer;
use cgmath::{Matrix4, Vector3, Vector2, Basis2, ElementWise, Zero, Rotation2, Rotation, Rad, Deg};

// Declare the vertex format suitable for drawing,
// as well as the constants used by the shaders
// and the pipeline state object format.
gfx_defines! {
    // Data for each particle
    vertex Vertex {
        pos: [f32; 2] = "a_Pos",
        radius: f32 = "a_Radius",
        time: f32 = "a_Time",
        base_color: [f32; 4] = "a_BaseColor",
        new_color: [f32; 4] = "a_NewColor",
    }

    // Aspect ratio to keep particles round
    constant Locals {
        transformation: [[f32; 4]; 4] = "u_Transformation",
    }

    // Particle render pipeline
    pipeline circles {
        vbuf: gfx::VertexBuffer<Vertex> = (),
        locals: gfx::ConstantBuffer<Locals> = "Locals",
        out_color: gfx::BlendTarget<ColorFormat> = ("Target0", gfx::state::ColorMask::all(), gfx::preset::blend::ALPHA),
    }
}

impl Vertex {
    // Construct new particles far away so they can't be seen initially
    fn new() -> Vertex {
        Vertex {
            pos: [std::f32::INFINITY, std::f32::INFINITY],
            radius: 50.0,
            time: 0.0,
            base_color: Default::default(),
            new_color: Default::default(),
        }
    }
}

struct Camera {
    pub pos: Vector2<f32>,
    pub up: bool,
    pub right: bool,
    pub down: bool,
    pub left: bool,
}

impl Camera {
    pub fn compute(&mut self, time: f32) {
        self.pos += self.camera_speed() * time;
    }

    fn camera_speed(&self) -> Vector2<f32> {
        let angle = match (self.up, self.right, self.down, self.left) {
            (true, true, false, false) => 45.0,
            (true, false, false, true) => 135.0,
            (false, false, true, true) => 225.0,
            (false, true, true, false) => 315.0,
            (_, true, _, false) => 0.0,
            (true, _, false, _) => 90.0,
            (_, false, _, true) => 180.0,
            (false, _, true, _) => 270.0,
            _ => -1.0,
        };

        if angle == -1.0 {
            return Vector2::zero();
        }

        Basis2::from_angle(Deg(angle))
            .rotate_vector(Vector2::new(200.0, 0.0))
    }
}

struct App<R: gfx::Resources> {
    bundle: Bundle<R, circles::Data<R>>,
    circle: Vertex,
    time_start: Instant,
    camera: Camera,
}

fn create_shader_set<R: gfx::Resources, F: gfx::Factory<R>>(factory: &mut F,
                                                            vs_code: &[u8],
                                                            gs_code: &[u8],
                                                            ps_code: &[u8]) -> ShaderSet<R> {
    let vs = factory.create_shader_vertex(vs_code).expect("Failed to compile vertex shader");
    let gs = factory.create_shader_geometry(gs_code).expect("Failed to compile geometry shader");
    let ps = factory.create_shader_pixel(ps_code).expect("Failed to compile pixel shader");
    ShaderSet::Geometry(vs, gs, ps)
}

impl<R: gfx::Resources> gfx_app::Application<R> for App<R> {
    fn new<F: gfx::Factory<R>>(factory: &mut F, backend: gfx_app::shade::Backend,
                               window_targets: gfx_app::WindowTargets<R>) -> Self {
        use gfx::traits::FactoryExt;

        // Load in our vertex, geometry and pixel shaders
        let vs = gfx_app::shade::Source {
            glsl_150: include_bytes!("shaders/circle_150.glslv"),
            .. gfx_app::shade::Source::empty()
        };
        let gs = gfx_app::shade::Source {
            glsl_150: include_bytes!("shaders/circle_150.glslg"),
            .. gfx_app::shade::Source::empty()
        };
        let ps = gfx_app::shade::Source {
            glsl_150: include_bytes!("shaders/circle_150.glslf"),
            .. gfx_app::shade::Source::empty()
        };

        let shader_set = create_shader_set(
            factory,
            vs.select(backend).unwrap(),
            gs.select(backend).unwrap(),
            ps.select(backend).unwrap(),
        );

        // Create 4096 particles, using one point vertex per particle
        let mut circle = Vertex::new();

        // Create a dynamic vertex buffer to hold the particle data
        let vbuf = factory.create_buffer(1,
                                         buffer::Role::Vertex,
                                         gfx::memory::Usage::Dynamic,
                                         Bind::empty())
            .expect("Failed to create vertex buffer");
        let slice = Slice::new_match_vertex_buffer(&vbuf);

        // Construct our pipeline state
        let pso = factory.create_pipeline_state(
            &shader_set,
            Primitive::PointList,
            Rasterizer::new_fill(),
            circles::new()
        ).unwrap();

        circle.pos = [0.0, 0.0];
        circle.base_color = [rand::random(), rand::random(), rand::random(), 1.0];
        circle.new_color = [rand::random(), rand::random(), rand::random(), 1.0];

        let data = circles::Data {
            vbuf: vbuf,
            locals: factory.create_constant_buffer(1),
            out_color: window_targets.color,
        };

        App {
            bundle: Bundle::new(slice, pso, data),
            circle: circle,
            time_start: Instant::now(),
            camera: Camera {
                pos: Vector2::zero(),
                up: false,
                right: false,
                down: false,
                left: false,
            }
        }
    }

    fn render<C: gfx::CommandBuffer<R>>(&mut self, encoder: &mut gfx::Encoder<R, C>) {
        // Compute the time since last frame
        let delta = self.time_start.elapsed();
        self.time_start = Instant::now();
        let delta = delta.as_secs() as f32 + delta.subsec_nanos() as f32 / 1000_000_000.0;

        let anim_duration = 1.7;
        self.circle.time = self.circle.time + delta / anim_duration;
        if self.circle.time > 1. {
            self.circle.time %= 1.;
            let base_color = self.circle.base_color;
            self.circle.base_color = self.circle.new_color;
            self.circle.new_color = base_color;
        }

        let (width, height, _, _) = self.bundle.data.out_color.get_dimensions();

        self.camera.compute(delta);
        let scale_vector = Vector3::new(1.0 / width as f32 * 4.0, 1.0 / height as f32 * 4.0, 1.0);
        let camera_translation = Matrix4::from_translation(
            self.camera.pos.neg().extend(0.0).mul_element_wise(scale_vector)
        );
        let scale = Matrix4::from_nonuniform_scale(scale_vector.x, scale_vector.y, scale_vector.z);

        // Pass in the aspect ratio to the geometry shader
        let locals = Locals { transformation: (camera_translation * scale).into() };
        encoder.update_constant_buffer(&self.bundle.data.locals, &locals);
        // Update the vertex data with the changes to the particles array
        encoder.update_buffer(&self.bundle.data.vbuf, &[self.circle], 0).unwrap();
        // Clear the background to dark blue
        encoder.clear(&self.bundle.data.out_color, [0.1, 0.2, 0.3, 1.0]);
        // Draw the particles!
        self.bundle.encode(encoder);
    }

    fn on_resize(&mut self, window_targets: gfx_app::WindowTargets<R>) {
        self.bundle.data.out_color = window_targets.color;
    }

    fn on(&mut self, event: winit::WindowEvent) {
        match event {
            winit::WindowEvent::KeyboardInput(winit::ElementState::Pressed, _, Some(winit::VirtualKeyCode::W), _) => {
                self.camera.up = true;
            },
            winit::WindowEvent::KeyboardInput(winit::ElementState::Pressed, _, Some(winit::VirtualKeyCode::D), _) => {
                self.camera.right = true;
            },
            winit::WindowEvent::KeyboardInput(winit::ElementState::Pressed, _, Some(winit::VirtualKeyCode::S), _) => {
                self.camera.down = true;
            },
            winit::WindowEvent::KeyboardInput(winit::ElementState::Pressed, _, Some(winit::VirtualKeyCode::A), _) => {
                self.camera.left = true;
            },
            winit::WindowEvent::KeyboardInput(winit::ElementState::Released, _, Some(winit::VirtualKeyCode::W), _) => {
                self.camera.up = false;
            },
            winit::WindowEvent::KeyboardInput(winit::ElementState::Released, _, Some(winit::VirtualKeyCode::D), _) => {
                self.camera.right = false;
            },
            winit::WindowEvent::KeyboardInput(winit::ElementState::Released, _, Some(winit::VirtualKeyCode::S), _) => {
                self.camera.down = false;
            },
            winit::WindowEvent::KeyboardInput(winit::ElementState::Released, _, Some(winit::VirtualKeyCode::A), _) => {
                self.camera.left = false;
            },
            _ => ()
        }
    }
}

pub fn main() {
    use gfx_app::Application;
    App::launch_simple("circles-rs");
}
<|endoftext|>


<commit_before>extern crate gtk;
extern crate libnotify;
extern crate nix;
mod battery;

use std::env;

use gtk::prelude::*;
use gtk::{ButtonsType, DialogFlags, MessageType, MessageDialog, Window};

use nix::unistd::{fork, ForkResult};

use battery::Battery;
use battery::BatteryStatus;

const LEFT_CLICK: i32 = 1;
const RIGHT_CLICK: i32 = 3;
const CRITICAL_EXIT_CODE: i32 = 33;
const CRITICAL_BAT_LEVEL: u32 = 5;

fn console_output(bat: &Battery) {
    // Icons
    let plug          = '\u{f1e6}';
    let check         = '\u{f00c}';
    let full          = '\u{f240}';
    let three_quarter = '\u{f241}';
    let half          = '\u{f242}';
    let quarter       = '\u{f243}';
    let empty         = '\u{f244}';

    // Colors
    let green  = "#859900";
    let cyan   = "#2AA198";
    let yellow = "#B58900";
    let orange = "#CB4B16";
    let red    = "#DC322F";

    let mut percent = bat.percent_remaining();

    let (mut icon, mut color) = match percent {
        0  ... 10  => (empty, red),
        11 ... 35  => (quarter, orange),
        36 ... 60  => (half, yellow),
        61 ... 85  => (three_quarter, cyan),
        86 ... 100 => (full, green),
        _          => std::process::exit(1),
    };

    match bat.charge_status {
        BatteryStatus::FULL => {
            icon = check;
            color = green;
            percent = 100;
        },
        BatteryStatus::CHARGING => {
            icon = plug;
        },
        _ => (),
    };

    let out = format!("{} {}%\n",
                      color, icon, percent);
    print!("{0:}{0:}", out);

}

/*
 * Displays the GTK MessageDialog with information about the current status of
 * the battery. This contains all the fields that this program collects
 * information on.
 *
 * This function will return 0 on success and 1 on error.
 */
fn show_gtk_dialog(bat: &Battery) -> i32 {
    if gtk::init().is_err() {
        eprintln!("Failed to initialize GTK.");
        return 1;
    }

    let body_string = format!("Battery name:\t\t{}\n\
                              Battery charge:\t\t{}\n\
                              Charge when full:\t{}\n\
                              Design full:\t\t\t{}\n\
                              Cycle count:\t\t{}\n\
                              Charging status:\t{}\n\
                              Current now:\t\t{}\n\
                              Current avg:\t\t{}\n\
                              % Charged:\t\t\t{}%\n\
                              Time remaining:\t\t{}\n\
                              Battery health:\t\t{}%\n\
                              % Charged (abs):\t{}%\n",
                              bat.name, bat.charge_now, bat.charge_full,
                              bat.charge_full_design, bat.cycle_count,
                              bat.charge_status, bat.current_now,
                              bat.current_avg, bat.percent_remaining(),
                              bat.time_remaining(), bat.health(),
                              bat.abs_percent_remaining());

    MessageDialog::new(None::<&Window>,
                       DialogFlags::empty(),
                       MessageType::Info,
                       ButtonsType::Ok,
                       &body_string).run();
    return 0;
}

fn get_env_var(key: &str) -> Option<String> {
    match env::var(key) {
        Ok(ref val) if val.is_empty() => None,
        Ok(val) => Some(val),
        Err(_) => None
    }
}

fn show_notification(bat: &Battery) {
    let time_left = bat.time_remaining();
    libnotify::init("Battery").unwrap();
    let notification = libnotify::Notification::new("Time Remaining",
                                                    Some(&*time_left),
                                                    None);
    notification.show().unwrap();
    libnotify::uninit();
}

/*
 * For the purposes of i3blocks, 3 corresponds to a right click. When
 * that happens, fork() and then show a dialog. If we don't fork(), then
 * the dialog prevents this process from exiting and the block doesn't
 * update. The printing to the console is done in the parent thread.
 */
#[allow(unused_variables)]
fn handle_button_presses(bat: &Battery) {
    let button: i32 = match get_env_var("BLOCK_BUTTON") {
        Some(val) => val.trim().parse().unwrap(),
        None => 0
    };

    match button {
        RIGHT_CLICK => {
            match fork() {
                Ok(ForkResult::Parent { child, .. }) => (),
                Ok(ForkResult::Child) => std::process::exit(show_gtk_dialog(&bat)),
                Err(_) => eprintln!("Fork failed"),
            }
        },
        LEFT_CLICK => show_notification(&bat),
        _ => (),
    };
    console_output(&bat);
}

fn main() {
    let battery_name = match get_env_var("BLOCK_INSTANCE") {
        Some(val) => val,
        None => "BAT0".to_owned(),
    };

    let bat = match Battery::initialize(&battery_name) {
        Some(batt) => batt,
        None => {
            eprintln!("Unable to load battery data");
            std::process::exit(1);
        }
    };

    handle_button_presses(&bat);

    /*
     * i3blocks shows a block as critical if the process exits with code 33.
     * If the battery is less than 33% charged, the status is critical
     */
    if bat.percent_remaining() <= CRITICAL_BAT_LEVEL {
        std::process::exit(CRITICAL_EXIT_CODE)
    }
}
<commit_msg>Cleanup output when battery <=5%<commit_after>extern crate gtk;
extern crate libnotify;
extern crate nix;
mod battery;

use std::env;

use gtk::prelude::*;
use gtk::{ButtonsType, DialogFlags, MessageType, MessageDialog, Window};

use nix::unistd::{fork, ForkResult};

use battery::Battery;
use battery::BatteryStatus;

const LEFT_CLICK: i32 = 1;
const RIGHT_CLICK: i32 = 3;
const CRITICAL_EXIT_CODE: i32 = 33;
const CRITICAL_BAT_LEVEL: u32 = 5;

fn console_output(bat: &Battery) {
    // Icons
    let plug          = '\u{f1e6}';
    let check         = '\u{f00c}';
    let full          = '\u{f240}';
    let three_quarter = '\u{f241}';
    let half          = '\u{f242}';
    let quarter       = '\u{f243}';
    let empty         = '\u{f244}';

    // Colors
    let green  = "#859900";
    let cyan   = "#2AA198";
    let yellow = "#B58900";
    let orange = "#CB4B16";
    let red    = "#DC322F";
    let bg     = "#073642";

    let mut percent = bat.percent_remaining();

    let (mut icon, mut color) = match percent {
        0  ... 5   => (empty, bg),
        6  ... 10  => (empty, red),
        11 ... 35  => (quarter, orange),
        36 ... 60  => (half, yellow),
        61 ... 85  => (three_quarter, cyan),
        86 ... 100 => (full, green),
        _          => std::process::exit(1),
    };

    match bat.charge_status {
        BatteryStatus::FULL => {
            icon = check;
            color = green;
            percent = 100;
        },
        BatteryStatus::CHARGING => {
            icon = plug;
        },
        _ => (),
    };

    let out = format!(" {} {}%\n",
                      color, icon, percent);
    print!("{0:}{0:}", out);

}

/*
 * Displays the GTK MessageDialog with information about the current status of
 * the battery. This contains all the fields that this program collects
 * information on.
 *
 * This function will return 0 on success and 1 on error.
 */
fn show_gtk_dialog(bat: &Battery) -> i32 {
    if gtk::init().is_err() {
        eprintln!("Failed to initialize GTK.");
        return 1;
    }

    let body_string = format!("Battery name:\t\t{}\n\
                              Battery charge:\t\t{}\n\
                              Charge when full:\t{}\n\
                              Design full:\t\t\t{}\n\
                              Cycle count:\t\t{}\n\
                              Charging status:\t{}\n\
                              Current now:\t\t{}\n\
                              Current avg:\t\t{}\n\
                              % Charged:\t\t\t{}%\n\
                              Time remaining:\t\t{}\n\
                              Battery health:\t\t{}%\n\
                              % Charged (abs):\t{}%\n",
                              bat.name, bat.charge_now, bat.charge_full,
                              bat.charge_full_design, bat.cycle_count,
                              bat.charge_status, bat.current_now,
                              bat.current_avg, bat.percent_remaining(),
                              bat.time_remaining(), bat.health(),
                              bat.abs_percent_remaining());

    MessageDialog::new(None::<&Window>,
                       DialogFlags::empty(),
                       MessageType::Info,
                       ButtonsType::Ok,
                       &body_string).run();
    return 0;
}

fn get_env_var(key: &str) -> Option<String> {
    match env::var(key) {
        Ok(ref val) if val.is_empty() => None,
        Ok(val) => Some(val),
        Err(_) => None
    }
}

fn show_notification(bat: &Battery) {
    let time_left = bat.time_remaining();
    libnotify::init("Battery").unwrap();
    let notification = libnotify::Notification::new("Time Remaining",
                                                    Some(&*time_left),
                                                    None);
    notification.show().unwrap();
    libnotify::uninit();
}

/*
 * For the purposes of i3blocks, 3 corresponds to a right click. When
 * that happens, fork() and then show a dialog. If we don't fork(), then
 * the dialog prevents this process from exiting and the block doesn't
 * update. The printing to the console is done in the parent thread.
 */
#[allow(unused_variables)]
fn handle_button_presses(bat: &Battery) {
    let button: i32 = match get_env_var("BLOCK_BUTTON") {
        Some(val) => val.trim().parse().unwrap(),
        None => 0
    };

    match button {
        RIGHT_CLICK => {
            match fork() {
                Ok(ForkResult::Parent { child, .. }) => (),
                Ok(ForkResult::Child) => std::process::exit(show_gtk_dialog(&bat)),
                Err(_) => eprintln!("Fork failed"),
            }
        },
        LEFT_CLICK => show_notification(&bat),
        _ => (),
    };
    console_output(&bat);
}

fn main() {
    let battery_name = match get_env_var("BLOCK_INSTANCE") {
        Some(val) => val,
        None => "BAT0".to_owned(),
    };

    let bat = match Battery::initialize(&battery_name) {
        Some(batt) => batt,
        None => {
            eprintln!("Unable to load battery data");
            std::process::exit(1);
        }
    };

    handle_button_presses(&bat);

    /*
     * i3blocks shows a block as critical if the process exits with code 33.
     * If the battery is less than 33% charged, the status is critical
     */
    if bat.percent_remaining() <= CRITICAL_BAT_LEVEL {
        std::process::exit(CRITICAL_EXIT_CODE)
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate ast;
extern crate rand;

use ast::data::Evaluate;

fn main() {
	let program: ast::structure::Program = iff!(less!(vx!(), multiply!(constant!(2.0), constant!(3.0))), left!(), right!());

	let data: ast::data::SensorData = ast::data::SensorData { x: 37.0, y: 51.0, vx: 1.0, vy: 0.0, o: 0.0, w: 0.0 };

	let command = program.evaluate(data);

	let message = match **command {
		ast::structure::Command::Skip  => "skip",
		ast::structure::Command::Left  => "turnLeft",
		ast::structure::Command::Right => "turnRight",
		ast::structure::Command::Up    => "thruster",
	};

	println!("action is {}", message);

	let option: bool = rand::random();
	println!("option is {}", option);
}
<commit_msg>Use namespaces<commit_after>#[macro_use]
extern crate ast;
extern crate rand;

use ast::structure::{Program,Command};
use ast::data::{SensorData,Evaluate};

fn main() {
	let program: ast::structure::Program = iff!(less!(vx!(), multiply!(constant!(2.0), constant!(3.0))), left!(), right!());

	let data: SensorData = SensorData { x: 37.0, y: 51.0, vx: 1.0, vy: 0.0, o: 0.0, w: 0.0 };

	let command = program.evaluate(data);

	let message = match **command {
		Command::Skip  => "skip",
		Command::Left  => "turnLeft",
		Command::Right => "turnRight",
		Command::Up    => "thruster",
	};

	println!("action is {}", message);

	let option: bool = rand::random();
	println!("option is {}", option);
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate ansi_term;

use hyper::client::Client;
use std::io::Read;
use std::string::String;
use ansi_term::Colour::{Red, Green, Yellow, Cyan};
use std::process::Command;
use std::process::Stdio;

struct Server {
    protocol: String,
    players: u8,
    observers: u8,
    address: String,
    name: String,
}

fn main() {
    let mut servers: Vec<Server> = Vec::new();

    let client = Client::new();

    let mut res = client.get("https://my.bzflag.org/db/?action=LIST&listformat=plain").send().unwrap();
    assert_eq!(res.status, hyper::Ok);

    let mut data = String::new();
    res.read_to_string(&mut data).expect("Failed to read data");

    for line in data.lines() {
        let server: Vec<&str> = line.split(' ').collect();

        let data = server[2];
        let players = [
            u8::from_str_radix(&data[34..36], 16).unwrap(), // rogue
            u8::from_str_radix(&data[38..40], 16).unwrap(), // red
            u8::from_str_radix(&data[42..44], 16).unwrap(), // green
            u8::from_str_radix(&data[46..48], 16).unwrap(), // blue
            u8::from_str_radix(&data[50..52], 16).unwrap(), // purple
        ];
        let players: u8 = players.iter().fold(0u8, |a, &b| a + b);
        let observers = u8::from_str_radix(&data[54..56], 16).unwrap();

        let server = Server {
            protocol: server[1].to_string(),
            players: players,
            observers: observers,
            address: server[0].to_string(),
            name: (&server[4..]).join(" ").to_string()
        };

        servers.push(server);
    }

    servers.sort_by(|a, b| b.players.cmp(&a.players));

    let cols:usize = match Command::new("stty").arg("size").arg("-F").arg("/dev/stderr").stderr(Stdio::inherit()).output() {
        Ok(out) => String::from_utf8(out.stdout).unwrap().split_whitespace().last().unwrap().parse().unwrap(),
        Err(_) => 80,
    };

    println!("{}", cols);

    for server in servers {
        if server.players == 0 {
            break;
        }

        println!("[{}, {}]  {}  {}",
            Yellow.paint(format!("{:2}", server.players)),
            Cyan.paint(server.observers.to_string()),
            Green.paint(format!("{:1$}", server.name, cols/3)),
            Red.paint(server.address)
        );
    }
}
<commit_msg>Sort by observers too<commit_after>extern crate hyper;
extern crate ansi_term;

use hyper::client::Client;
use std::io::Read;
use std::string::String;
use ansi_term::Colour::{Red, Green, Yellow, Cyan};
use std::process::Command;
use std::process::Stdio;

struct Server {
    protocol: String,
    players: u8,
    observers: u8,
    address: String,
    name: String,
}

fn main() {
    let mut servers: Vec<Server> = Vec::new();

    let client = Client::new();

    let mut res = client.get("https://my.bzflag.org/db/?action=LIST&listformat=plain").send().unwrap();
    assert_eq!(res.status, hyper::Ok);

    let mut data = String::new();
    res.read_to_string(&mut data).expect("Failed to read data");

    for line in data.lines() {
        let server: Vec<&str> = line.split(' ').collect();

        let data = server[2];
        let players = [
            u8::from_str_radix(&data[34..36], 16).unwrap(), // rogue
            u8::from_str_radix(&data[38..40], 16).unwrap(), // red
            u8::from_str_radix(&data[42..44], 16).unwrap(), // green
            u8::from_str_radix(&data[46..48], 16).unwrap(), // blue
            u8::from_str_radix(&data[50..52], 16).unwrap(), // purple
        ];
        let players: u8 = players.iter().fold(0u8, |a, &b| a + b);
        let observers = u8::from_str_radix(&data[54..56], 16).unwrap();

        let server = Server {
            protocol: server[1].to_string(),
            players: players,
            observers: observers,
            address: server[0].to_string(),
            name: (&server[4..]).join(" ").to_string()
        };

        servers.push(server);
    }

    servers.sort_by(|a, b| match b.players.cmp(&a.players) {
        Ordering::Equal => b.observers.cmp(&a.observers),
        c => c
    });

    let cols:usize = match Command::new("stty").arg("size").arg("-F").arg("/dev/stderr").stderr(Stdio::inherit()).output() {
        Ok(out) => String::from_utf8(out.stdout).unwrap().split_whitespace().last().unwrap().parse().unwrap(),
        Err(_) => 80,
    };

    println!("{}", cols);

    for server in servers {
        if server.players == 0 {
            break;
        }

        println!("[{}, {}]  {}  {}",
            Yellow.paint(format!("{:2}", server.players)),
            Cyan.paint(server.observers.to_string()),
            Green.paint(format!("{:1$}", server.name, cols/3)),
            Red.paint(server.address)
        );
    }
}
<|endoftext|>


<commit_before>#![feature(box_syntax)]

#[macro_use]
extern crate objc;

#[macro_use]
extern crate log;

extern crate simplelog;
extern crate libc;
extern crate cocoa;
extern crate objc_foundation;

mod app;
mod controls;
mod window;
mod view;
mod servo;
mod platform;

use app::AppEvent;
use window::WindowEvent;
use view::ViewEvent;
use servo::ServoEvent;
use controls::ControlEvent;
use simplelog::{CombinedLogger, Config, LogLevel, LogLevelFilter, TermLogger, WriteLogger};
use std::fs::File;
use std::env::args;
use app::App;
use servo::{Servo, FollowLinkPolicy};

fn main() {

    let log_file = File::create("/tmp/servoshell.log").unwrap();
    let log_config = Config {
        time: None,
        level: Some(LogLevel::Info),
        target: Some(LogLevel::Info),
        location: Some(LogLevel::Info),
    };
    let _ = CombinedLogger::init(vec![
        TermLogger::new(LogLevelFilter::Info, log_config).unwrap(),
        WriteLogger::new(LogLevelFilter::Info, log_config, log_file)
    ]);

    platform::init();

    let (app, ctrls) = App::load().unwrap();
    let (window, view) = app.create_window(&ctrls).unwrap();

    let url = args().nth(1).unwrap_or("http://servo.org".to_owned());
    Servo::configure(&url).unwrap();
    let servo = {
        let geometry = view.get_geometry();
        let riser = window.create_eventloop_riser();
        let policy = FollowLinkPolicy::FollowOriginalDomain;
        Servo::new(geometry, riser, &url, policy)
    };

    info!("Servo version: {}", servo.version());

    view.enter_fullscreen();

    app.run(|| {

        // Loop until no events are available anymore.
        loop {

            let app_events = app.get_events();
            let ctrls_events = ctrls.get_events();
            let win_events = window.get_events();
            let view_events = view.get_events();
            let servo_events = servo.get_events();

            if app_events.is_empty() &&
               ctrls_events.is_empty() &&
               win_events.is_empty() &&
               view_events.is_empty() &&
               servo_events.is_empty() {
                   break
            }

            // FIXME: it's really annoying we need this
            let mut sync_needed = false;

            for event in app_events {
                match event {
                    AppEvent::DidFinishLaunching => {
                        // FIXME: does this work?
                    }
                    AppEvent::WillTerminate => {
                        // FIXME: does this work?
                    }
                    AppEvent::DidChangeScreenParameters => {
                        // FIXME: does this work?
                        servo.update_geometry(view.get_geometry());
                        view.update_drawable();
                        sync_needed = true;
                    }
                }
            }

            for event in ctrls_events {
                match event {
                    ControlEvent::Stop => {
                        // FIXME
                    }
                    ControlEvent::Reload => {
                        servo.reload();
                        sync_needed = true;
                    }
                    ControlEvent::GoBack => {
                        servo.go_back();
                        sync_needed = true;
                    }
                    ControlEvent::GoForward => {
                        servo.go_forward();
                        sync_needed = true;
                    }
                    ControlEvent::ZoomIn => {
                        // FIXME
                    }
                    ControlEvent::ZoomOut => {
                        // FIXME
                    }
                    ControlEvent::ZoomToActualSize => {
                        // FIXME
                    }
                }
            }

            for event in win_events {
                match event {
                    WindowEvent::EventLoopRised => {
                        sync_needed = true;
                    }
                    WindowEvent::GeometryDidChange => {
                        servo.update_geometry(view.get_geometry());
                        view.update_drawable();
                        sync_needed = true;
                    }
                    WindowEvent::DidEnterFullScreen => {
                        // FIXME
                    }
                    WindowEvent::DidExitFullScreen => {
                        // FIXME
                    }
                    WindowEvent::WillClose => {
                        // FIXME
                    }
                }
            }

            for event in view_events {
                match event {
                    ViewEvent::MouseWheel(delta, phase) => {
                        let (x, y) = match delta {
                            view::MouseScrollDelta::PixelDelta(x, y) => {
                                (x, y)
                            },
                            _ => (0.0, 0.0),
                        };
                        servo.perform_scroll(0, 0, x, y, phase);
                        sync_needed = true;
                    }
                }
            }

            for event in servo_events {
                match event {
                    ServoEvent::SetWindowInnerSize(..) => {
                        // ignore
                    }
                    ServoEvent::SetWindowPosition(..) => {
                        // ignore
                    }
                    ServoEvent::SetFullScreenState(fullscreen) => {
                        if fullscreen {
                            view.enter_fullscreen();
                        } else {
                            view.exit_fullscreen();
                        }
                    }
                    ServoEvent::Present => {
                        view.swap_buffers();
                    }
                    ServoEvent::TitleChanged(title) => {
                        window.set_title(&title.unwrap_or("No Title".to_owned()));

                    }
                    ServoEvent::UnhandledURL(..) => {
                        // FIXME
                    }
                    ServoEvent::StatusChanged(..) => {
                        // FIXME
                    }
                    ServoEvent::LoadStart(..) => {
                        ctrls.set_command_state(ControlEvent::Reload, false);
                        ctrls.set_command_state(ControlEvent::Stop, true);
                    }
                    ServoEvent::LoadEnd(..) => {
                        ctrls.set_command_state(ControlEvent::Reload, true);
                        ctrls.set_command_state(ControlEvent::Stop, false);
                    }
                    ServoEvent::LoadError(..) => {
                        // FIXME
                    }
                    ServoEvent::HeadParsed(url) => {
                        window.set_url(url.as_str());
                    }
                    ServoEvent::CursorChanged(..) => {
                        // FIXME
                    }
                    ServoEvent::FaviconChanged(..) => {
                        // FIXME
                    }
                    ServoEvent::Key(..) => {
                        // FIXME
                    }
                }
            }

            if sync_needed {
                servo.sync();
            }
        }
    });

}
<commit_msg>log will fail if no tty<commit_after>#![feature(box_syntax)]

#[macro_use]
extern crate objc;

#[macro_use]
extern crate log;

extern crate simplelog;
extern crate libc;
extern crate cocoa;
extern crate objc_foundation;

mod app;
mod controls;
mod window;
mod view;
mod servo;
mod platform;

use app::AppEvent;
use window::WindowEvent;
use view::ViewEvent;
use servo::ServoEvent;
use controls::ControlEvent;
use simplelog::{CombinedLogger, Config, LogLevel, LogLevelFilter, TermLogger, WriteLogger};
use std::fs::File;
use std::env::args;
use app::App;
use servo::{Servo, FollowLinkPolicy};

fn main() {

    // FIXME: can we use NSLog instead of a file?
    let log_file = File::create("/tmp/servoshell.log").unwrap();
    let log_config = Config {
        time: None,
        level: Some(LogLevel::Info),
        target: Some(LogLevel::Info),
        location: Some(LogLevel::Info),
    };

    let _ = match TermLogger::new(LogLevelFilter::Info, log_config) {
        Some(logger) => CombinedLogger::init(vec![
            logger,
            WriteLogger::new(LogLevelFilter::Info, log_config, log_file)
        ]),
        None => WriteLogger::init(LogLevelFilter::Info, log_config, log_file)
    };

    info!("starting");

    platform::init();

    let (app, ctrls) = App::load().unwrap();
    let (window, view) = app.create_window(&ctrls).unwrap();

    let url = args().nth(1).unwrap_or("http://servo.org".to_owned());
    Servo::configure(&url).unwrap();
    let servo = {
        let geometry = view.get_geometry();
        let riser = window.create_eventloop_riser();
        let policy = FollowLinkPolicy::FollowOriginalDomain;
        Servo::new(geometry, riser, &url, policy)
    };

    info!("Servo version: {}", servo.version());

    view.enter_fullscreen();

    app.run(|| {

        // Loop until no events are available anymore.
        loop {

            let app_events = app.get_events();
            let ctrls_events = ctrls.get_events();
            let win_events = window.get_events();
            let view_events = view.get_events();
            let servo_events = servo.get_events();

            if app_events.is_empty() &&
               ctrls_events.is_empty() &&
               win_events.is_empty() &&
               view_events.is_empty() &&
               servo_events.is_empty() {
                   break
            }

            // FIXME: it's really annoying we need this
            let mut sync_needed = false;

            for event in app_events {
                match event {
                    AppEvent::DidFinishLaunching => {
                        // FIXME: does this work?
                    }
                    AppEvent::WillTerminate => {
                        // FIXME: does this work?
                    }
                    AppEvent::DidChangeScreenParameters => {
                        // FIXME: does this work?
                        servo.update_geometry(view.get_geometry());
                        view.update_drawable();
                        sync_needed = true;
                    }
                }
            }

            for event in ctrls_events {
                match event {
                    ControlEvent::Stop => {
                        // FIXME
                    }
                    ControlEvent::Reload => {
                        servo.reload();
                        sync_needed = true;
                    }
                    ControlEvent::GoBack => {
                        servo.go_back();
                        sync_needed = true;
                    }
                    ControlEvent::GoForward => {
                        servo.go_forward();
                        sync_needed = true;
                    }
                    ControlEvent::ZoomIn => {
                        // FIXME
                    }
                    ControlEvent::ZoomOut => {
                        // FIXME
                    }
                    ControlEvent::ZoomToActualSize => {
                        // FIXME
                    }
                }
            }

            for event in win_events {
                match event {
                    WindowEvent::EventLoopRised => {
                        sync_needed = true;
                    }
                    WindowEvent::GeometryDidChange => {
                        servo.update_geometry(view.get_geometry());
                        view.update_drawable();
                        sync_needed = true;
                    }
                    WindowEvent::DidEnterFullScreen => {
                        // FIXME
                    }
                    WindowEvent::DidExitFullScreen => {
                        // FIXME
                    }
                    WindowEvent::WillClose => {
                        // FIXME
                    }
                }
            }

            for event in view_events {
                match event {
                    ViewEvent::MouseWheel(delta, phase) => {
                        let (x, y) = match delta {
                            view::MouseScrollDelta::PixelDelta(x, y) => {
                                (x, y)
                            },
                            _ => (0.0, 0.0),
                        };
                        servo.perform_scroll(0, 0, x, y, phase);
                        sync_needed = true;
                    }
                }
            }

            for event in servo_events {
                match event {
                    ServoEvent::SetWindowInnerSize(..) => {
                        // ignore
                    }
                    ServoEvent::SetWindowPosition(..) => {
                        // ignore
                    }
                    ServoEvent::SetFullScreenState(fullscreen) => {
                        if fullscreen {
                            view.enter_fullscreen();
                        } else {
                            view.exit_fullscreen();
                        }
                    }
                    ServoEvent::Present => {
                        view.swap_buffers();
                    }
                    ServoEvent::TitleChanged(title) => {
                        window.set_title(&title.unwrap_or("No Title".to_owned()));

                    }
                    ServoEvent::UnhandledURL(..) => {
                        // FIXME
                    }
                    ServoEvent::StatusChanged(..) => {
                        // FIXME
                    }
                    ServoEvent::LoadStart(..) => {
                        ctrls.set_command_state(ControlEvent::Reload, false);
                        ctrls.set_command_state(ControlEvent::Stop, true);
                    }
                    ServoEvent::LoadEnd(..) => {
                        ctrls.set_command_state(ControlEvent::Reload, true);
                        ctrls.set_command_state(ControlEvent::Stop, false);
                    }
                    ServoEvent::LoadError(..) => {
                        // FIXME
                    }
                    ServoEvent::HeadParsed(url) => {
                        window.set_url(url.as_str());
                    }
                    ServoEvent::CursorChanged(..) => {
                        // FIXME
                    }
                    ServoEvent::FaviconChanged(..) => {
                        // FIXME
                    }
                    ServoEvent::Key(..) => {
                        // FIXME
                    }
                }
            }

            if sync_needed {
                servo.sync();
            }
        }
    });

}
<|endoftext|>


<commit_before>extern crate serialize;
extern crate rustbox;
extern crate docopt;
extern crate iota;

#[cfg(not(test))] use std::io::stdio;
#[cfg(not(test))] use docopt::Docopt;
#[cfg(not(test))] use iota::{Editor, Input};
#[cfg(not(test))] use rustbox::{InitOption, RustBox};
#[cfg(not(test))] static USAGE: &'static str = "
Usage: iota [<filename>]
       iota --help

Options:
    -h, --help     Show this message.
";

#[deriving(Decodable, Show)]
struct Args {
    arg_filename: Option<String>,
    flag_help: bool,
}

#[cfg(not(test))]
fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());
    let (source, buffer_stderr) = if stdio::stdin_raw().isatty() {
        (Input::Filename(args.arg_filename), Some(InitOption::BufferStderr))
    } else {
        (Input::Stdin(stdio::stdin()), None)
    };

    let rb = RustBox::init(&[buffer_stderr]).unwrap();
    let mut editor = Editor::new(source, &rb);
    editor.start();
}
<commit_msg>Fix: don't capture stderr_raw, not stdin_raw.<commit_after>extern crate serialize;
extern crate rustbox;
extern crate docopt;
extern crate iota;

#[cfg(not(test))] use std::io::stdio;
#[cfg(not(test))] use docopt::Docopt;
#[cfg(not(test))] use iota::{Editor, Input};
#[cfg(not(test))] use rustbox::{InitOption, RustBox};
#[cfg(not(test))] static USAGE: &'static str = "
Usage: iota [<filename>]
       iota --help

Options:
    -h, --help     Show this message.
";

#[deriving(Decodable, Show)]
struct Args {
    arg_filename: Option<String>,
    flag_help: bool,
}

#[cfg(not(test))]
fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());
    let source = if stdio::stdin_raw().isatty() {
        Input::Filename(args.arg_filename)
    } else {
        Input::Stdin(stdio::stdin())
    };
    let options = [
        if stdio::stderr_raw().isatty() { Some(InitOption::BufferStderr) } else { None },
    ];
    let rb = RustBox::init(&options).unwrap();
    let mut editor = Editor::new(source, &rb);
    editor.start();
}
<|endoftext|>


<commit_before>extern crate env_logger;
extern crate mioco;
extern crate trust_dns;
extern crate rand;
#[macro_use] extern crate quick_error;
#[macro_use] extern crate log;

mod future;
mod utils;

use std::net::{SocketAddr, SocketAddrV4, IpAddr};

use mioco::udp::UdpSocket;
use mioco::mio::Ipv4Addr;
use trust_dns::op::{Message, MessageType, ResponseCode, Query, OpCode};

use utils::{Result, CloneExt, MessageExt};
use future::Future;

fn query(q: Query, server: Ipv4Addr) -> Result<Message> {
    let mut msg : Message = Message::new();
    msg.message_type(MessageType::Query);
    msg.id(rand::random());
    msg.op_code(OpCode::Query);
    msg.recursion_desired(true);
    debug!("Q[{}][{}] {} {:?} {:?}",
           server, msg.get_id(), q.get_name(), q.get_query_type(), q.get_query_class());
    msg.add_query(q);
    let msg_data = try!(msg.to_bytes());
    let mut sock = try!(UdpSocket::v4());
    let target = SocketAddr::new(IpAddr::V4(server), 53);
    try!(sock.send(&msg_data, &target));
    loop {
        let (resp, addr) = try!(Message::from_udp(&mut sock));
        if addr != target {
            warn!("Q[{}][{}] Response from unexpected server: {}",
                  server, msg.get_id(), addr);
            continue
        }
        if ! resp.is_resp_for(&msg) {
            warn!("Q[{}][{}] Invalid response: {:?}",
                  server, msg.get_id(), resp);
            continue
        }
        // TODO: Validate response, handle truncated message, retry and timeout
        debug!("A[{}][{}] {} answer(s)",
           server, resp.get_id(), resp.get_answers().len());
        return Ok(resp);
    };
}
fn query_multiple(q: &Query, servers: &[Ipv4Addr]) -> Result<Message> {
    let mut futures = servers.iter()
        .cloned()
        .map(move |server| {
            let qc = q.clone();
            Future::from_fn(move || query(qc, server.clone()))
        })
        .collect::<Vec<Future<Result<Message>>>>();
    let result_index = Future::wait_any(&mut futures);
    futures.remove(result_index).consume()
}

fn handle_request(msg: Message) -> Message {
    let mut ret : Message = msg.new_resp();
    ret.recursion_available(true);
    if msg.get_queries().len() != 1 {
        // For simplicity, only support one question
        ret.response_code(ResponseCode::Refused);
        return ret;
    }
    // TODO: EDNS?
    match query_multiple(&msg.get_queries()[0], &[Ipv4Addr::new(8, 8, 8, 8), Ipv4Addr::new(8, 8, 4, 4)]) {
        Ok(resp) => { ret.copy_resp_from(&resp); },
        Err(_)   => { ret.response_code(ResponseCode::ServFail); },
    };
    ret
}

fn main() {
    env_logger::init().unwrap();
    println!("Hello, world!");

    mioco::start(move || {
        let ip = Ipv4Addr::new(0, 0, 0, 0);
        let port = 5354;
        let addr = SocketAddr::V4(SocketAddrV4::new(ip, port));

        mioco::spawn(move || -> Result<()> {
            let mut sock : UdpSocket = UdpSocket::v4().unwrap();
            sock.bind(&addr).unwrap();

            loop {
                let (msg, addr) = try!(Message::from_udp(&mut sock));
                let ret = handle_request(msg);
                let resp = try!(ret.to_bytes());
                try!(sock.send(&resp, &addr));
            }
        });
    }).unwrap();
}
<commit_msg>Minor fix<commit_after>extern crate env_logger;
extern crate mioco;
extern crate trust_dns;
extern crate rand;
#[macro_use] extern crate quick_error;
#[macro_use] extern crate log;

mod future;
mod utils;

use std::net::{SocketAddr, SocketAddrV4, IpAddr};

use mioco::udp::UdpSocket;
use mioco::mio::Ipv4Addr;
use trust_dns::op::{Message, MessageType, ResponseCode, Query, OpCode};

use utils::{Result, CloneExt, MessageExt};
use future::Future;

fn query(q: Query, server: Ipv4Addr) -> Result<Message> {
    let mut msg : Message = Message::new();
    msg.message_type(MessageType::Query);
    msg.id(rand::random());
    msg.op_code(OpCode::Query);
    msg.recursion_desired(true);
    debug!("Q[{}][{}] {} {:?} {:?}",
           server, msg.get_id(), q.get_name(), q.get_query_type(), q.get_query_class());
    msg.add_query(q);
    let msg_data = try!(msg.to_bytes());
    let mut sock = try!(UdpSocket::v4());
    let target = SocketAddr::new(IpAddr::V4(server), 53);
    try!(sock.send(&msg_data, &target));
    loop {
        let (resp, addr) = try!(Message::from_udp(&mut sock));
        if addr != target {
            warn!("Q[{}][{}] Response from unexpected server: {}",
                  server, msg.get_id(), addr);
            continue
        }
        if ! resp.is_resp_for(&msg) {
            warn!("Q[{}][{}] Invalid response: {:?}",
                  server, msg.get_id(), resp);
            continue
        }
        // TODO: Validate response, handle truncated message, retry and timeout
        debug!("A[{}][{}] {} answer(s)",
           server, resp.get_id(), resp.get_answers().len());
        return Ok(resp);
    };
}
fn query_multiple(q: &Query, servers: &[Ipv4Addr]) -> Result<Message> {
    let mut futures = servers.iter()
        .cloned()
        .map(move |server| {
            let qc = q.clone();
            Future::from_fn(move || query(qc, server))
        })
        .collect::<Vec<Future<Result<Message>>>>();
    let result_index = Future::wait_any(&mut futures);
    // TODO: Handle server failure
    futures.remove(result_index).consume()
}

fn handle_request(msg: Message) -> Message {
    let mut ret : Message = msg.new_resp();
    ret.recursion_available(true);
    if msg.get_queries().len() != 1 {
        // For simplicity, only support one question
        ret.response_code(ResponseCode::Refused);
        return ret;
    }
    // TODO: EDNS?
    match query_multiple(&msg.get_queries()[0], &[Ipv4Addr::new(8, 8, 8, 8), Ipv4Addr::new(8, 8, 4, 4)]) {
        Ok(resp) => { ret.copy_resp_from(&resp); },
        Err(_)   => { ret.response_code(ResponseCode::ServFail); },
    };
    ret
}

fn main() {
    env_logger::init().unwrap();
    println!("Hello, world!");

    mioco::start(move || {
        let ip = Ipv4Addr::new(0, 0, 0, 0);
        let port = 5354;
        let addr = SocketAddr::V4(SocketAddrV4::new(ip, port));

        mioco::spawn(move || -> Result<()> {
            let mut sock : UdpSocket = UdpSocket::v4().unwrap();
            sock.bind(&addr).unwrap();

            loop {
                let (msg, addr) = try!(Message::from_udp(&mut sock));
                let ret = handle_request(msg);
                let resp = try!(ret.to_bytes());
                try!(sock.send(&resp, &addr));
            }
        });
    }).unwrap();
}
<|endoftext|>


<commit_before>extern crate getopts;
#[cfg(feature = "use-gmp")]
extern crate gmp;
#[cfg(feature = "use-num-rational")]
extern crate num_rational;
extern crate vote;

mod ballot_parser;

use ballot_parser::parse_ballot_files;
use getopts::Options;
use std::env;
use std::fmt::Display;
use std::io::{Write, stderr};
use std::process::exit;
use std::str::FromStr;
use vote::schulze_stv::schulze_stv;
use vote::traits::{Weight, WeightOps};

const USAGE: &'static str = include_str!("usage.txt");

struct Calc {
    calc: &'static str,
    run: fn(&Calc, &str, usize, &[String]) -> Result<(), String>,
}

const CALCS: &'static [Calc] = &[
    #[cfg(feature = "use-gmp")]
    Calc { calc: "mpq", run: run::<gmp::mpq::Mpq> },
    #[cfg(feature = "use-num-rational")]
    Calc { calc: "num", run: run::<num_rational::BigRational> },
    Calc { calc: "hw", run: run::<vote::hw_float::HwFloat> },
];

fn main_result() -> Result<(), String> {
    let args = env::args().collect::<Vec<_>>();
    let program = &args[0];

    let mut opts = Options::new();
    opts.optopt("w",
                "winners",
                "elect an N-winner committee (default: 1)",
                "N");
    opts.optopt("",
                "calc",
                "TYPE",
                &format!("number type to use for calculations (default: {})",
                         CALCS[0].calc));
    opts.optflag("", "help", "show this help message and exit");
    opts.optflag("", "version", "show the program version and exit");
    let matches = opts.parse(&args[1..]).map_err(|e| format!("{}: error: {}", program, e))?;

    if matches.opt_present("help") {
        print!("{}", opts.usage(USAGE));
        return Ok(());
    }

    if matches.opt_present("version") {
        println!("elect {}", env!("CARGO_PKG_VERSION"));
        return Ok(());
    }

    if matches.free.is_empty() {
        write!(&mut stderr(), "{}", opts.usage(USAGE)).expect("failed printing to stderr");
        exit(1)
    }

    let num_seats = matches.opt_str("w")
        .map(|s| s.parse().map_err(|e| format!("{}: error: -w argument: {}", program, e)))
        .unwrap_or(Ok(1))?;

    let calc = match matches.opt_str("calc") {
        Some(calc_opt) => {
            CALCS.iter()
                .find(|calc| calc.calc == calc_opt)
                .ok_or_else(|| format!("unknown number type {}", calc_opt))
        }
        None => Ok(&CALCS[0]),
    }?;
    (calc.run)(calc, program, num_seats, &matches.free)
}

fn run<W>(calc: &Calc, program: &str, num_seats: usize, filenames: &[String]) -> Result<(), String>
    where W: Display + FromStr + Weight,
          W::Err: Display,
          for<'w> &'w W: WeightOps<W>
{
    let bp = parse_ballot_files::<W, _>(filenames)?;
    if bp.ballots.is_empty() {
        return Err(format!("{}: error: No ballots found", program));
    }

    println!("Tallying Schulze STV election (calc={}).", calc.calc);
    println!("");

    println!("Candidates ({}):", bp.candidates.len());
    let mut candidates_sorted = bp.candidates.clone();
    candidates_sorted.sort();
    for candidate in &candidates_sorted {
        println!("  {}", candidate);
    }
    println!("");

    let total_weight = bp.ballots.iter().fold(W::zero(), |acc, &(_, ref w)| acc + w);
    println!("Ballots ({}):", total_weight);
    for &(ref groups, ref w) in &bp.ballots {
        println!("  {}: {}",
                 w,
                 groups.iter()
                     .map(|group| {
                         group.iter()
                             .map(|&c| &bp.candidates[c][..])
                             .collect::<Vec<_>>()
                             .join(" = ")
                     })
                     .collect::<Vec<_>>()
                     .join(" > "));
    }
    println!("");

    let mut winners = schulze_stv(bp.candidates.len(), num_seats, &bp.ballots);

    for set in winners.iter_mut() {
        set.sort_by(|&a, &b| bp.candidates[a].cmp(&bp.candidates[b]));
    }
    winners.sort_by(|a, b| {
        a.iter().map(|&i| &bp.candidates[i]).cmp(b.iter().map(|&i| &bp.candidates[i]))
    });

    let set_suffix = if num_seats == 1 { "" } else { " set" };
    if winners.len() == 1 {
        println!("Winner{}:", set_suffix);
    } else {
        println!("Tied winner{}s:", set_suffix);
    }
    for set in winners.iter() {
        println!("  {}",
                 set.iter().map(|&c| &bp.candidates[c][..]).collect::<Vec<_>>().join(", "));
    }
    Ok(())
}

fn main() {
    main_result().unwrap_or_else(|e| {
        writeln!(&mut stderr(), "{}", e).expect("failed printing to stderr");
        exit(1)
    })
}
<commit_msg>elect: Fix usage string for --calc<commit_after>extern crate getopts;
#[cfg(feature = "use-gmp")]
extern crate gmp;
#[cfg(feature = "use-num-rational")]
extern crate num_rational;
extern crate vote;

mod ballot_parser;

use ballot_parser::parse_ballot_files;
use getopts::Options;
use std::env;
use std::fmt::Display;
use std::io::{Write, stderr};
use std::process::exit;
use std::str::FromStr;
use vote::schulze_stv::schulze_stv;
use vote::traits::{Weight, WeightOps};

const USAGE: &'static str = include_str!("usage.txt");

struct Calc {
    calc: &'static str,
    run: fn(&Calc, &str, usize, &[String]) -> Result<(), String>,
}

const CALCS: &'static [Calc] = &[
    #[cfg(feature = "use-gmp")]
    Calc { calc: "mpq", run: run::<gmp::mpq::Mpq> },
    #[cfg(feature = "use-num-rational")]
    Calc { calc: "num", run: run::<num_rational::BigRational> },
    Calc { calc: "hw", run: run::<vote::hw_float::HwFloat> },
];

fn main_result() -> Result<(), String> {
    let args = env::args().collect::<Vec<_>>();
    let program = &args[0];

    let mut opts = Options::new();
    opts.optopt("w",
                "winners",
                "elect an N-winner committee (default: 1)",
                "N");
    opts.optopt("",
                "calc",
                &format!("number type to use for calculations (default: {})",
                         CALCS[0].calc),
                "TYPE");
    opts.optflag("", "help", "show this help message and exit");
    opts.optflag("", "version", "show the program version and exit");
    let matches = opts.parse(&args[1..]).map_err(|e| format!("{}: error: {}", program, e))?;

    if matches.opt_present("help") {
        print!("{}", opts.usage(USAGE));
        return Ok(());
    }

    if matches.opt_present("version") {
        println!("elect {}", env!("CARGO_PKG_VERSION"));
        return Ok(());
    }

    if matches.free.is_empty() {
        write!(&mut stderr(), "{}", opts.usage(USAGE)).expect("failed printing to stderr");
        exit(1)
    }

    let num_seats = matches.opt_str("w")
        .map(|s| s.parse().map_err(|e| format!("{}: error: -w argument: {}", program, e)))
        .unwrap_or(Ok(1))?;

    let calc = match matches.opt_str("calc") {
        Some(calc_opt) => {
            CALCS.iter()
                .find(|calc| calc.calc == calc_opt)
                .ok_or_else(|| format!("unknown number type {}", calc_opt))
        }
        None => Ok(&CALCS[0]),
    }?;
    (calc.run)(calc, program, num_seats, &matches.free)
}

fn run<W>(calc: &Calc, program: &str, num_seats: usize, filenames: &[String]) -> Result<(), String>
    where W: Display + FromStr + Weight,
          W::Err: Display,
          for<'w> &'w W: WeightOps<W>
{
    let bp = parse_ballot_files::<W, _>(filenames)?;
    if bp.ballots.is_empty() {
        return Err(format!("{}: error: No ballots found", program));
    }

    println!("Tallying Schulze STV election (calc={}).", calc.calc);
    println!("");

    println!("Candidates ({}):", bp.candidates.len());
    let mut candidates_sorted = bp.candidates.clone();
    candidates_sorted.sort();
    for candidate in &candidates_sorted {
        println!("  {}", candidate);
    }
    println!("");

    let total_weight = bp.ballots.iter().fold(W::zero(), |acc, &(_, ref w)| acc + w);
    println!("Ballots ({}):", total_weight);
    for &(ref groups, ref w) in &bp.ballots {
        println!("  {}: {}",
                 w,
                 groups.iter()
                     .map(|group| {
                         group.iter()
                             .map(|&c| &bp.candidates[c][..])
                             .collect::<Vec<_>>()
                             .join(" = ")
                     })
                     .collect::<Vec<_>>()
                     .join(" > "));
    }
    println!("");

    let mut winners = schulze_stv(bp.candidates.len(), num_seats, &bp.ballots);

    for set in winners.iter_mut() {
        set.sort_by(|&a, &b| bp.candidates[a].cmp(&bp.candidates[b]));
    }
    winners.sort_by(|a, b| {
        a.iter().map(|&i| &bp.candidates[i]).cmp(b.iter().map(|&i| &bp.candidates[i]))
    });

    let set_suffix = if num_seats == 1 { "" } else { " set" };
    if winners.len() == 1 {
        println!("Winner{}:", set_suffix);
    } else {
        println!("Tied winner{}s:", set_suffix);
    }
    for set in winners.iter() {
        println!("  {}",
                 set.iter().map(|&c| &bp.candidates[c][..]).collect::<Vec<_>>().join(", "));
    }
    Ok(())
}

fn main() {
    main_result().unwrap_or_else(|e| {
        writeln!(&mut stderr(), "{}", e).expect("failed printing to stderr");
        exit(1)
    })
}
<|endoftext|>


<commit_before>extern crate libc;

use libc::funcs::posix88::unistd;
use std::c_str;
use std::c_str::ToCStr;
use std::cmp;
use std::os;
use std::ptr;
use std::rand::Rng;

fn main() {
    let version = "0.1.0";
    match parse_args(os::args().as_slice().tail()) {
        Err(Exit::Usage) => {
            os::set_exit_status(1);
            print_usage(version);
        }
        Err(Exit::Help) =>
            print_usage(version),
        Err(Exit::Version) =>
            print_version(version),
        Ok(opts) => {
            if whack(&opts) {
                os::set_exit_status(1);
            } else {
                opts.exe.map_or((), |exe| {
                    execvp(exe.name, exe.args)
                });
            }
        }
    }
}

type ArgParse<T> = Result<T, Exit>;

#[derive(Show)]
struct Options<'a> {
    chance: int,
    exe: Option<Exe<'a>>,
}

#[derive(Show)]
struct Exe<'a> {
    name: &'a str,
    args: &'a[String],
}

#[derive(Show)]
enum Exit {
    Usage,
    Help,
    Version,
}

fn parse_args(args: &[String]) -> ArgParse<Options> {
    args.uncons().map_or(Err(Exit::Usage), |(s, args)| {
        match s.as_slice() {
            "--help"    | "-h" => Err(Exit::Help),
            "--version" | "-v" => Err(Exit::Version),
            "--chance"  | "-c" => {
                args.uncons().map_or(Err(Exit::Usage), |(s, args)| {
                    s.parse().map_or(Err(Exit::Usage), |val| {
                        args.skip("--").uncons().map_or(
                            Ok(Options {
                                chance: val,
                                exe: None
                            }), |(exe, args)| {
                                Ok(Options {
                                    chance: val,
                                    exe: Some(Exe {
                                        name: exe.as_slice(),
                                        args: args,
                                    })
                                })
                            })
                        })
                    })
                }
            _ => Err(Exit::Usage),
        }
    })
}

trait Uncons<'a, A> { fn uncons(&self) -> Option<(&'a A, &'a [A])>; }
trait Skip<'a, A, B> { fn skip(&self, x: A) -> &'a [B]; }

impl<'a, A> Uncons<'a, A> for &'a [A] {
    fn uncons(&self) -> Option<(&'a A, &'a [A])> {
        self.first().map(|x| (x, self.tail()))
    }
}

impl<'a > Skip<'a, &'a str, String> for &'a [String] {
    fn skip(&self, x: &'a str) -> &'a [String] {
        self.uncons().map_or(*self, |(y, ys)| { if x == y.as_slice() { ys } else { *self } })
    }
}

fn whack(opts: &Options) -> bool {
    std::rand::thread_rng().gen_range(0, 100) > cmp::min(cmp::max(opts.chance, 0), 100)
}

fn execvp(name: &str, args: &[String]) {
    let c_name: c_str::CString = name.to_c_str();
    let c_args: Vec<c_str::CString> = args.iter().map(|tmp| tmp.to_c_str()).collect();

    let mut xs: Vec<*const libc::c_char> = Vec::with_capacity(args.len() + 2);

    xs.push(c_name.as_ptr());
    xs.extend(c_args.iter().map(|tmp| tmp.as_ptr()));
    xs.push(ptr::null());

    let c_arg0 = xs[0];
    let c_argv = xs.as_mut_ptr();

    unsafe {
        unistd::execvp(c_arg0, c_argv);
    };

    panic!("execvp(3) failed with: {}", os::last_os_error());
}

fn print_usage(version: &str) {
    print_version(version);
    println!("\n\
        Usage: whacky (-c PERCENTAGE|--chance PERCENTAGE) [[--] COMMAND]\n\
          whacky, yet another randomly failing program\n\
        \n\
        Available options:\n\
          -h,--help           show this help text\n\
          -c,--chance         set success chance");
}

fn print_version(version: &str) {
    println!("whacky {}", version);
}
<commit_msg>int -> i32<commit_after>extern crate libc;

use libc::funcs::posix88::unistd;
use std::c_str;
use std::c_str::ToCStr;
use std::cmp;
use std::os;
use std::ptr;
use std::rand::Rng;

fn main() {
    let version = "0.1.0";
    match parse_args(os::args().as_slice().tail()) {
        Err(Exit::Usage) => {
            os::set_exit_status(1);
            print_usage(version);
        }
        Err(Exit::Help) =>
            print_usage(version),
        Err(Exit::Version) =>
            print_version(version),
        Ok(opts) => {
            if whack(&opts) {
                os::set_exit_status(1);
            } else {
                opts.exe.map_or((), |exe| {
                    execvp(exe.name, exe.args)
                });
            }
        }
    }
}

type ArgParse<T> = Result<T, Exit>;

#[derive(Show)]
struct Options<'a> {
    chance: i32,
    exe: Option<Exe<'a>>,
}

#[derive(Show)]
struct Exe<'a> {
    name: &'a str,
    args: &'a[String],
}

#[derive(Show)]
enum Exit {
    Usage,
    Help,
    Version,
}

fn parse_args(args: &[String]) -> ArgParse<Options> {
    args.uncons().map_or(Err(Exit::Usage), |(s, args)| {
        match s.as_slice() {
            "--help"    | "-h" => Err(Exit::Help),
            "--version" | "-v" => Err(Exit::Version),
            "--chance"  | "-c" => {
                args.uncons().map_or(Err(Exit::Usage), |(s, args)| {
                    s.parse().map_or(Err(Exit::Usage), |val| {
                        args.skip("--").uncons().map_or(
                            Ok(Options {
                                chance: val,
                                exe: None
                            }), |(exe, args)| {
                                Ok(Options {
                                    chance: val,
                                    exe: Some(Exe {
                                        name: exe.as_slice(),
                                        args: args,
                                    })
                                })
                            })
                        })
                    })
                }
            _ => Err(Exit::Usage),
        }
    })
}

trait Uncons<'a, A> { fn uncons(&self) -> Option<(&'a A, &'a [A])>; }
trait Skip<'a, A, B> { fn skip(&self, x: A) -> &'a [B]; }

impl<'a, A> Uncons<'a, A> for &'a [A] {
    fn uncons(&self) -> Option<(&'a A, &'a [A])> {
        self.first().map(|x| (x, self.tail()))
    }
}

impl<'a > Skip<'a, &'a str, String> for &'a [String] {
    fn skip(&self, x: &'a str) -> &'a [String] {
        self.uncons().map_or(*self, |(y, ys)| { if x == y.as_slice() { ys } else { *self } })
    }
}

fn whack(opts: &Options) -> bool {
    std::rand::thread_rng().gen_range(0, 100) > cmp::min(cmp::max(opts.chance, 0), 100)
}

fn execvp(name: &str, args: &[String]) {
    let c_name: c_str::CString = name.to_c_str();
    let c_args: Vec<c_str::CString> = args.iter().map(|tmp| tmp.to_c_str()).collect();

    let mut xs: Vec<*const libc::c_char> = Vec::with_capacity(args.len() + 2);

    xs.push(c_name.as_ptr());
    xs.extend(c_args.iter().map(|tmp| tmp.as_ptr()));
    xs.push(ptr::null());

    let c_arg0 = xs[0];
    let c_argv = xs.as_mut_ptr();

    unsafe {
        unistd::execvp(c_arg0, c_argv);
    };

    panic!("execvp(3) failed with: {}", os::last_os_error());
}

fn print_usage(version: &str) {
    print_version(version);
    println!("\n\
        Usage: whacky (-c PERCENTAGE|--chance PERCENTAGE) [[--] COMMAND]\n\
          whacky, yet another randomly failing program\n\
        \n\
        Available options:\n\
          -h,--help           show this help text\n\
          -c,--chance         set success chance");
}

fn print_version(version: &str) {
    println!("whacky {}", version);
}
<|endoftext|>