<commit_before>use glob::glob;
use serde_json;
use std;
use std::collections::HashMap;
use std::fs::File;
use std::io::prelude::*;
use structs::{CliError, Config, Member, PublicKey, Repo, Sector, SectorGroup, Team};

use futures::future::Future;
use futures::stream::Stream;
use hyper::{header, Client, Method, Request};
use hyper_rustls::HttpsConnector;
use tokio_core::reactor;

pub struct GithubClient {
    conf: Config,
}

impl GithubClient {
    pub fn new(config: &Config) -> GithubClient {
        if std::env::var("SSL_CERT_FILE").is_err() {
            std::env::set_var("SSL_CERT_FILE", &config.cert_path);
        }
        GithubClient { conf: config.clone() }
    }

    fn get_cache_path(url: &str) -> std::path::PathBuf {
        let mut path = std::env::temp_dir();
        path.push("sectora-cache");
        path.push(url);
        path
    }

    fn load_content_from_cache(&self, url: &str) -> Result<(std::fs::Metadata, String), CliError> {
        let path = Self::get_cache_path(url);
        let metadata = std::fs::metadata(path.to_str().unwrap())?;
        let mut f = File::open(path.to_str().unwrap())?;
        let mut content = String::new();
        f.read_to_string(&mut content)?;
        Ok((metadata, content))
    }

    fn store_content_to_cache(&self, url: &str, content: &str) -> Result<(), CliError> {
        let path = Self::get_cache_path(url);
        std::fs::create_dir_all(path.parent().unwrap())?;
        let mut f = File::create(path.to_str().unwrap())?;
        f.write(content.as_bytes())?;
        Ok(())
    }

    fn get_content_from_url(&self, url: &str) -> Result<String, CliError> {
        let mut all_contents: Vec<serde_json::value::Value> = Vec::new();
        let mut page = 1;
        loop {
            let mut new_array = self.get_content_from_url_page(url, page)?;
            if new_array.is_empty() {
                break;
            }
            all_contents.append(&mut new_array);
            page += 1;
        }
        let content = serde_json::ser::to_string(&all_contents)?;
        self.store_content_to_cache(url, &content)?;
        Ok(content)
    }

    fn build_page_request(&self, url: &str, page: u64) -> Request {
        let token = String::from("token ") + &self.conf.token;
        let sep = if url.contains("?") { "&" } else { "?" };
        let url_p = format!("{}{}page={}", url, sep, page);
        let mut req: Request = Request::new(Method::Get, url_p.parse().unwrap());
        req.headers_mut().set(header::Authorization(token));
        req.headers_mut().set(header::UserAgent::new("sectora"));
        req
    }

    fn get_content_from_url_page(&self, url: &str, page: u64) -> Result<Vec<serde_json::value::Value>, CliError> {
        let req = self.build_page_request(url, page);
        let mut core = reactor::Core::new()?;
        let client = Client::configure().connector(HttpsConnector::new(4, &core.handle()))
                                        .build(&core.handle());
        let work = client.request(req).and_then(|res| {
            res.body().concat2().and_then(move |body| {
                let v =
                    serde_json::from_slice::<Vec<serde_json::value::Value>>(&body).map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, format!("output:{:?}", body)))?;
                Ok(v)
            })
        });
        Ok(core.run(work)?)
    }

    fn get_content(&self, url: &str) -> Result<String, CliError> {
        match self.load_content_from_cache(url) {
            Ok((metadata, cache_content)) => match std::time::SystemTime::now().duration_since(metadata.modified()?) {
                Ok(caching_duration) => {
                    if caching_duration.as_secs() > self.conf.cache_duration {
                        match self.get_content_from_url(url) {
                            Ok(content_from_url) => Ok(content_from_url),
                            Err(_) => Ok(cache_content),
                        }
                    } else {
                        Ok(cache_content)
                    }
                }
                Err(_) => Ok(cache_content),
            },
            Err(_) => self.get_content_from_url(url),
        }
    }

    #[allow(dead_code)]
    pub fn print_user_public_key(&self, user: &str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user: &str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint, user);
        let content = self.get_content(&url)?;
        let keys = serde_json::from_str::<Vec<PublicKey>>(&content)?;
        Ok(keys.iter().map(|k| k.key.clone()).collect::<Vec<String>>().join("\n"))
    }

    #[allow(dead_code)]
    pub fn check_pam(&self, user: &str) -> Result<bool, CliError> {
        let sectors = self.get_sectors()?;
        Ok(sectors.iter().any(|team| team.members.contains_key(user)))
    }

    pub fn get_sectors(&self) -> Result<Vec<SectorGroup>, CliError> {
        let mut sectors: Vec<SectorGroup> = self.get_teams_result()?;
        sectors.append(&mut self.get_repos_result()?);
        Ok(sectors)
    }

    fn get_teams_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let gh_teams = self.get_team_map()?;
        let mut teams = Vec::new();
        for team_conf in &self.conf.team {
            if let &Some(gh_team) = &gh_teams.get(&team_conf.name) {
                teams.push(SectorGroup { sector: Sector::from(gh_team.clone()),
                                         gid: team_conf.gid.clone(),
                                         group: team_conf.group.clone(),
                                         members: self.get_team_members(gh_team.id)?, });
            }
        }
        Ok(teams)
    }

    fn get_team_map(&self) -> Result<HashMap<String, Team>, CliError> {
        let url = format!("{}/orgs/{}/teams", self.conf.endpoint, self.conf.org);
        let content = self.get_content(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(&content)?;
        Ok(teams.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_team_members(&self, mid: u64) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/teams/{}/members", self.conf.endpoint, mid);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&content)?;
        Ok(members.iter().map(|m| (m.login.clone(), m.clone())).collect())
    }

    fn get_repos_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let gh_repos = self.get_repo_map()?;
        let mut repos = Vec::new();
        for repo_conf in &self.conf.repo {
            if let &Some(gh_repo) = &gh_repos.get(&repo_conf.name) {
                repos.push(SectorGroup { sector: Sector::from(gh_repo.clone()),
                                         gid: repo_conf.gid.clone(),
                                         group: repo_conf.group.clone(),
                                         members: self.get_repo_collaborators(&gh_repo.name)?, });
            }
        }
        Ok(repos)
    }

    fn get_repo_map(&self) -> Result<HashMap<String, Repo>, CliError> {
        let url = format!("{}/orgs/{}/repos", self.conf.endpoint, self.conf.org);
        let content = self.get_content(&url)?;
        let repos = serde_json::from_str::<Vec<Repo>>(&content)?;
        Ok(repos.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_repo_collaborators(&self, repo_name: &str) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/repos/{}/{}/collaborators?affiliation=outside",
                          self.conf.endpoint, self.conf.org, repo_name);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&content)?;
        Ok(members.iter().map(|m| (m.login.clone(), m.clone())).collect())
    }

    #[allow(dead_code)]
    pub fn clear_all_caches(&self) -> Result<(), CliError> {
        let mut path = std::env::temp_dir();
        path.push("sectora-cache/**/*");
        for entry in glob(&path.to_str().unwrap()).unwrap() {
            match entry {
                Ok(path) => {
                    if path.is_file() {
                        std::fs::remove_file(path)?
                    }
                }
                Err(e) => println!("{:?}", e),
            }
        }
        Ok(())
    }
}
<commit_msg>Change to be able to use root for cache path<commit_after>use glob::glob;
use serde_json;
use std;
use std::collections::HashMap;
use std::fs::File;
use std::io::prelude::*;
use structs::{CliError, Config, Member, PublicKey, Repo, Sector, SectorGroup, Team};

use futures::future::Future;
use futures::stream::Stream;
use hyper::{header, Client, Method, Request};
use hyper_rustls::HttpsConnector;
use tokio_core::reactor;

pub struct GithubClient {
    conf: Config,
}

impl GithubClient {
    pub fn new(config: &Config) -> GithubClient {
        if std::env::var("SSL_CERT_FILE").is_err() {
            std::env::set_var("SSL_CERT_FILE", &config.cert_path);
        }
        GithubClient { conf: config.clone() }
    }

    fn get_cache_path(url: &str) -> std::path::PathBuf {
        let mut path = std::env::temp_dir();
        path.push("sectora-cache");
        path.push(url);
        path
    }

    fn load_content_from_cache(&self, url: &str) -> Result<(std::fs::Metadata, String), CliError> {
        let path = Self::get_cache_path(url);
        let metadata = std::fs::metadata(path.to_str().unwrap())?;
        let mut f = File::open(path.to_str().unwrap())?;
        let mut content = String::new();
        f.read_to_string(&mut content)?;
        Ok((metadata, content))
    }

    fn store_content_to_cache(&self, url: &str, content: &str) -> Result<(), CliError> {
        let path = Self::get_cache_path(url);
        std::fs::create_dir_all(path.parent().unwrap_or(std::path::Path::new("/")))?;
        let mut f = File::create(path.to_str().unwrap())?;
        f.write(content.as_bytes())?;
        Ok(())
    }

    fn get_content_from_url(&self, url: &str) -> Result<String, CliError> {
        let mut all_contents: Vec<serde_json::value::Value> = Vec::new();
        let mut page = 1;
        loop {
            let mut new_array = self.get_content_from_url_page(url, page)?;
            if new_array.is_empty() {
                break;
            }
            all_contents.append(&mut new_array);
            page += 1;
        }
        let content = serde_json::ser::to_string(&all_contents)?;
        self.store_content_to_cache(url, &content)?;
        Ok(content)
    }

    fn build_page_request(&self, url: &str, page: u64) -> Request {
        let token = String::from("token ") + &self.conf.token;
        let sep = if url.contains("?") { "&" } else { "?" };
        let url_p = format!("{}{}page={}", url, sep, page);
        let mut req: Request = Request::new(Method::Get, url_p.parse().unwrap());
        req.headers_mut().set(header::Authorization(token));
        req.headers_mut().set(header::UserAgent::new("sectora"));
        req
    }

    fn get_content_from_url_page(&self, url: &str, page: u64) -> Result<Vec<serde_json::value::Value>, CliError> {
        let req = self.build_page_request(url, page);
        let mut core = reactor::Core::new()?;
        let client = Client::configure().connector(HttpsConnector::new(4, &core.handle()))
                                        .build(&core.handle());
        let work = client.request(req).and_then(|res| {
            res.body().concat2().and_then(move |body| {
                let v =
                    serde_json::from_slice::<Vec<serde_json::value::Value>>(&body).map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, format!("output:{:?}", body)))?;
                Ok(v)
            })
        });
        Ok(core.run(work)?)
    }

    fn get_content(&self, url: &str) -> Result<String, CliError> {
        match self.load_content_from_cache(url) {
            Ok((metadata, cache_content)) => match std::time::SystemTime::now().duration_since(metadata.modified()?) {
                Ok(caching_duration) => {
                    if caching_duration.as_secs() > self.conf.cache_duration {
                        match self.get_content_from_url(url) {
                            Ok(content_from_url) => Ok(content_from_url),
                            Err(_) => Ok(cache_content),
                        }
                    } else {
                        Ok(cache_content)
                    }
                }
                Err(_) => Ok(cache_content),
            },
            Err(_) => self.get_content_from_url(url),
        }
    }

    #[allow(dead_code)]
    pub fn print_user_public_key(&self, user: &str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user: &str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint, user);
        let content = self.get_content(&url)?;
        let keys = serde_json::from_str::<Vec<PublicKey>>(&content)?;
        Ok(keys.iter().map(|k| k.key.clone()).collect::<Vec<String>>().join("\n"))
    }

    #[allow(dead_code)]
    pub fn check_pam(&self, user: &str) -> Result<bool, CliError> {
        let sectors = self.get_sectors()?;
        Ok(sectors.iter().any(|team| team.members.contains_key(user)))
    }

    pub fn get_sectors(&self) -> Result<Vec<SectorGroup>, CliError> {
        let mut sectors: Vec<SectorGroup> = self.get_teams_result()?;
        sectors.append(&mut self.get_repos_result()?);
        Ok(sectors)
    }

    fn get_teams_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let gh_teams = self.get_team_map()?;
        let mut teams = Vec::new();
        for team_conf in &self.conf.team {
            if let &Some(gh_team) = &gh_teams.get(&team_conf.name) {
                teams.push(SectorGroup { sector: Sector::from(gh_team.clone()),
                                         gid: team_conf.gid.clone(),
                                         group: team_conf.group.clone(),
                                         members: self.get_team_members(gh_team.id)?, });
            }
        }
        Ok(teams)
    }

    fn get_team_map(&self) -> Result<HashMap<String, Team>, CliError> {
        let url = format!("{}/orgs/{}/teams", self.conf.endpoint, self.conf.org);
        let content = self.get_content(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(&content)?;
        Ok(teams.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_team_members(&self, mid: u64) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/teams/{}/members", self.conf.endpoint, mid);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&content)?;
        Ok(members.iter().map(|m| (m.login.clone(), m.clone())).collect())
    }

    fn get_repos_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let gh_repos = self.get_repo_map()?;
        let mut repos = Vec::new();
        for repo_conf in &self.conf.repo {
            if let &Some(gh_repo) = &gh_repos.get(&repo_conf.name) {
                repos.push(SectorGroup { sector: Sector::from(gh_repo.clone()),
                                         gid: repo_conf.gid.clone(),
                                         group: repo_conf.group.clone(),
                                         members: self.get_repo_collaborators(&gh_repo.name)?, });
            }
        }
        Ok(repos)
    }

    fn get_repo_map(&self) -> Result<HashMap<String, Repo>, CliError> {
        let url = format!("{}/orgs/{}/repos", self.conf.endpoint, self.conf.org);
        let content = self.get_content(&url)?;
        let repos = serde_json::from_str::<Vec<Repo>>(&content)?;
        Ok(repos.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_repo_collaborators(&self, repo_name: &str) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/repos/{}/{}/collaborators?affiliation=outside",
                          self.conf.endpoint, self.conf.org, repo_name);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&content)?;
        Ok(members.iter().map(|m| (m.login.clone(), m.clone())).collect())
    }

    #[allow(dead_code)]
    pub fn clear_all_caches(&self) -> Result<(), CliError> {
        let mut path = std::env::temp_dir();
        path.push("sectora-cache/**/*");
        for entry in glob(&path.to_str().unwrap()).unwrap() {
            match entry {
                Ok(path) => {
                    if path.is_file() {
                        std::fs::remove_file(path)?
                    }
                }
                Err(e) => println!("{:?}", e),
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>pub mod gcra;
pub mod leaky_bucket;

pub use self::gcra::*;
pub use self::leaky_bucket::*;

use evmap::ShallowCopy;
use std::fmt;
use std::num::NonZeroU32;
use std::time::{Duration, Instant};
use {InconsistentCapacity, NegativeMultiDecision, NonConformance};

/// The trait that implementations of metered rate-limiter algorithms
/// have to implement.
///
/// This is a stateless trait, which should allow for a variety of
/// rate-limiting schemes, like Redis or keyed vs. un-keyed
/// rate-limiting (one bucket per user vs. one bucket for the entire
/// API).
pub trait Algorithm {
    /// The state of a single rate limiting bucket.
    type BucketState: Default
        + Send
        + Sync
        + Eq
        + ShallowCopy
        + fmt::Debug
        + RateLimitState<Self::BucketParams>;

    /// The immutable parameters of the rate limiting bucket (e.g.,
    /// maximum capacity).
    type BucketParams: Send + Sync + fmt::Debug;

    fn params_from_constructor(
        capacity: NonZeroU32,
        cell_weight: NonZeroU32,
        per_time_unit: Duration,
    ) -> Result<Self::BucketParams, InconsistentCapacity>;

    /// Tests if `n` cells can be accommodated in the rate limiter at
    /// the instant `at` and updates the rate-limiter to account for
    /// the weight of the cells and updates the ratelimiter state.
    ///
    /// The update is all or nothing: Unless all n cells can be
    /// accommodated, the state of the rate limiter will not be
    /// updated.
    fn test_n_and_update(
        state: &Self::BucketState,
        params: &Self::BucketParams,
        n: u32,
        at: Instant,
    ) -> Result<(), NegativeMultiDecision>;

    /// Tests if a single cell can be accommodated in the rate limiter
    /// at the instant `at` and updates the rate-limiter to account
    /// for the weight of the cell.
    ///
    /// This method is provided by default, using the `n` test&update
    /// method.
    fn test_and_update(
        state: &Self::BucketState,
        params: &Self::BucketParams,
        at: Instant,
    ) -> Result<(), NonConformance> {
        match Self::test_n_and_update(state, params, 1, at) {
            Ok(()) => Ok(()),
            Err(NegativeMultiDecision::BatchNonConforming(1, nc)) => Err(nc),
            Err(other) => panic!("bug: There's a non-conforming batch: {:?}", other),
        }
    }
}

/// Trait that all rate limit states have to implement around
/// housekeeping in keyed rate limiters.
pub trait RateLimitState<P> {
    /// Returns the last time instant that the state had any relevance
    /// (i.e. the rate limiter would behave exactly as if it was a new
    /// rate limiter after this time).
    ///
    /// If the state has not been touched for a given amount of time,
    /// the keyed rate limiter will expire it.
    ///
    /// # Thread safety
    /// This uses a bucket state snapshot to determine eligibility;
    /// race conditions can occur.
    fn last_touched(&self, params: &P) -> Instant;
}
<commit_msg>More docs for the Algorithm trait<commit_after>pub mod gcra;
pub mod leaky_bucket;

pub use self::gcra::*;
pub use self::leaky_bucket::*;

use evmap::ShallowCopy;
use std::fmt;
use std::num::NonZeroU32;
use std::time::{Duration, Instant};
use {InconsistentCapacity, NegativeMultiDecision, NonConformance};

/// The trait that implementations of metered rate-limiter algorithms
/// have to implement.
///
/// This is a stateless trait, which should allow for a variety of
/// rate-limiting schemes, like Redis or keyed vs. un-keyed
/// rate-limiting (one bucket per user vs. one bucket for the entire
/// API).
pub trait Algorithm {
    /// The state of a single rate limiting bucket.
    ///
    /// Every new rate limiting state is initialized as `Default`. The
    /// states must be safe to share across threads (this crate uses a
    /// `parking_lot` Mutex to allow that).
    type BucketState: RateLimitState<Self::BucketParams>
        + Default
        + Send
        + Sync
        + Eq
        + ShallowCopy
        + fmt::Debug;

    /// The immutable parameters of the rate limiting bucket (e.g.,
    /// maximum capacity). The bucket parameters are unique per rate
    /// limiter instance (there are currently no per-user/per-IP rate
    /// limiter parameters).
    type BucketParams: Send + Sync + fmt::Debug;

    /// Constructs a set of rate limiter parameters from the given
    /// parameters: `capacity` is the number of cells, weighhing
    /// `cell_weight`, to allow `per_time_unit`.
    fn params_from_constructor(
        capacity: NonZeroU32,
        cell_weight: NonZeroU32,
        per_time_unit: Duration,
    ) -> Result<Self::BucketParams, InconsistentCapacity>;

    /// Tests if `n` cells can be accommodated in the rate limiter at
    /// the instant `at` and updates the rate-limiter to account for
    /// the weight of the cells and updates the ratelimiter state.
    ///
    /// The update is all or nothing: Unless all n cells can be
    /// accommodated, the state of the rate limiter will not be
    /// updated.
    fn test_n_and_update(
        state: &Self::BucketState,
        params: &Self::BucketParams,
        n: u32,
        at: Instant,
    ) -> Result<(), NegativeMultiDecision>;

    /// Tests if a single cell can be accommodated in the rate limiter
    /// at the instant `at` and updates the rate-limiter to account
    /// for the weight of the cell.
    ///
    /// This method is provided by default, using the `n` test&update
    /// method.
    fn test_and_update(
        state: &Self::BucketState,
        params: &Self::BucketParams,
        at: Instant,
    ) -> Result<(), NonConformance> {
        match Self::test_n_and_update(state, params, 1, at) {
            Ok(()) => Ok(()),
            Err(NegativeMultiDecision::BatchNonConforming(1, nc)) => Err(nc),
            Err(other) => panic!("bug: There's a non-conforming batch: {:?}", other),
        }
    }
}

/// Trait that all rate limit states have to implement around
/// housekeeping in keyed rate limiters.
pub trait RateLimitState<P> {
    /// Returns the last time instant that the state had any relevance
    /// (i.e. the rate limiter would behave exactly as if it was a new
    /// rate limiter after this time).
    ///
    /// If the state has not been touched for a given amount of time,
    /// the keyed rate limiter will expire it.
    ///
    /// # Thread safety
    /// This uses a bucket state snapshot to determine eligibility;
    /// race conditions can occur.
    fn last_touched(&self, params: &P) -> Instant;
}
<|endoftext|>


<commit_before>extern crate num;
extern crate rand;

#[macro_use]
extern crate serde_derive;
extern crate serde_yaml;

extern crate tcod;
use tcod::RootConsole;
use tcod::{Console};
use tcod::console::{FontLayout, FontType, Offscreen};
use tcod::input::{Key, KeyCode};

mod traits;
use traits::{Renderable, Movable, Position};

mod point;
use point::Point;

mod rectangle;

mod units;
mod map;

const SCREEN_WIDTH: u8 = 80;
const SCREEN_HEIGHT: u8 = 50;
const PANEL_HEIGHT: u8 = 5;

const FOV_RADIUS: u8 = 10;

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
enum GameState {
    Playing,
    NewMap,
    Menu,
    Exit,
}

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
enum PlayerAction {
    Moved,
    Turn,
    NoTurn,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Direction {
    Up,
    Down,
    Left,
    Right
}

impl Direction {
    fn to_rel_point(self) -> Point<i16> {
        match self {
            Direction::Up       => Point::new(0, -1),
            Direction::Down     => Point::new(0, 1),
            Direction::Left     => Point::new(-1, 0),
            Direction::Right    => Point::new(1, 0),
        }
    }
}

#[derive(Debug)]
enum KeyType {
    Movement(Direction),
    Exit,
    NewGame,
    Other,
}

fn key_type(key: &Key) -> KeyType {
    match key.code {
        KeyCode::Right  =>  KeyType::Movement(Direction::Right),
        KeyCode::Left   =>  KeyType::Movement(Direction::Left),
        KeyCode::Up     =>  KeyType::Movement(Direction::Up),
        KeyCode::Down   =>  KeyType::Movement(Direction::Down),
        KeyCode::Escape =>  KeyType::Exit,
        KeyCode::F1     =>  KeyType::NewGame,
        _ => KeyType::Other,
    }
}

fn render_all<'a>(root: &mut RootConsole, buffer_console: &mut Offscreen, map: &map::Map, npcs: &Vec<units::Unit<'a>>, player: &units::Unit) {
    buffer_console.clear();
    root.clear();

    // With the scrolling map, we need to try to centre the player on the screen
    // without going past the bounds of the buffer.
    let (map_width, map_height) = map.get_map_size();
    let draw_left = player.get_x() - SCREEN_WIDTH as i16 / 2;
    let draw_top = player.get_y() - SCREEN_HEIGHT as i16 / 2;

    let mut view_port = rectangle::Rectangle::new(Point{x: draw_left, y: draw_top}, (SCREEN_WIDTH, SCREEN_HEIGHT - PANEL_HEIGHT));
    view_port.clamp_to((0,0), (map_width as i16, map_height as i16));

    map.render_map(buffer_console);

    for unit in npcs.iter() {
        if map.point_in_fov(unit.get_position()) {
            unit.render(buffer_console);
        }
    }

    player.render(buffer_console);

    tcod::console::blit(buffer_console, (view_port.top_left.x as i32, view_port.top_left.y as i32), (SCREEN_WIDTH as i32, (SCREEN_HEIGHT - PANEL_HEIGHT) as i32), root, (0,0), 1.0, 1.0);
    root.flush();
}

fn handle_input<'a>(root: &mut RootConsole, cur_game_state: GameState, map: &map::Map, npcs: &mut Vec<units::Unit<'a>>, player: &mut units::Unit) -> (PlayerAction, GameState) {
    let key = root.wait_for_keypress(true);

    let mut player_action: PlayerAction = PlayerAction::NoTurn;
    let mut new_game_state: GameState = GameState::Playing;

    match key_type(&key) {
        KeyType::Movement(dir) if cur_game_state == GameState::Playing => {
            let pos = player.get_position();
            let new_pos = pos + dir.to_rel_point();

            player_action = match map.can_move_to(new_pos) {
                map::CanMoveResponse::Open => {
                    if let Some(enemy) = npcs.iter_mut().filter(|n| n.get_position() == new_pos).next() {
                        player.attack(enemy);
                        PlayerAction::Turn
                    } else {
                        player.move_to(new_pos);
                        PlayerAction::Moved
                    }
                },
                map::CanMoveResponse::Scenery => {
                    PlayerAction::NoTurn
                } // Nothing to do.
            };
        },
        KeyType::Movement(_) if cur_game_state == GameState::Menu => {} // Will likely be used for menus
        KeyType::Movement(_) => unreachable!(),

        KeyType::Exit           => {
            new_game_state = GameState::Exit;
        },
        KeyType::NewGame        => {
            new_game_state = GameState::NewMap;
        }
        KeyType::Other          => println!("{:?}", key),
    }

    (player_action, new_game_state)
}

fn main() {
    let mut root = RootConsole::initializer()
                    .size(SCREEN_WIDTH as i32, SCREEN_HEIGHT as i32)
                    .title("Roguelike Tutorial")
                    .fullscreen(false)
                    .font("arial10x10.png", FontLayout::Tcod)
                    .font_type(FontType::Greyscale)
                    .init();

    let mut buffer_console = Offscreen::new(map::MAP_MAX_WIDTH as i32, map::MAP_MAX_HEIGHT as i32);
    root.set_default_foreground(tcod::colors::WHITE);

    let unit_types = units::load_unit_types();
    let (mut map, mut npcs, start_coord) = map::Map::init(&unit_types);

    let player_type = units::UnitType::new("Player", '@', tcod::colors::WHITE);
    let mut player = units::Unit::new(start_coord, &player_type);

    map.update_fov(player.get_position(), FOV_RADIUS);

    let mut game_state = GameState::Playing;

    while !root.window_closed() {
        render_all(&mut root, &mut buffer_console, &map, &npcs, &player);

        let (player_action, new_game_state) = handle_input(&mut root, game_state, &map, &mut npcs, &mut player);
        game_state = new_game_state;

        if player_action == PlayerAction::Moved {
            map.update_fov(player.get_position(), FOV_RADIUS);
        }

        match (game_state, player_action) {
            (GameState::Exit, _) => break,
            (GameState::NewMap, _) => {
                let (new_map, units, start_coord) = map::Map::init(&unit_types);
                map = new_map;
                npcs = units;
                player.move_to(start_coord);
                map.update_fov(start_coord, FOV_RADIUS);
                game_state = GameState::Playing;
            }
            (GameState::Playing, PlayerAction::Moved) | (GameState::Playing, PlayerAction::Turn) => {
                for enemy in npcs.iter_mut() {
                    enemy.take_turn(&map, &mut player);
                }
            }
            _ => {} // Don't update AI.
        }
    }
}
<commit_msg>Include Item module.<commit_after>extern crate num;
extern crate rand;

#[macro_use]
extern crate serde_derive;
extern crate serde_yaml;

extern crate tcod;
use tcod::RootConsole;
use tcod::{Console};
use tcod::console::{FontLayout, FontType, Offscreen};
use tcod::input::{Key, KeyCode};

mod traits;
use traits::{Renderable, Movable, Position};

mod point;
use point::Point;

mod rectangle;
mod item;
mod units;
mod map;

const SCREEN_WIDTH: u8 = 80;
const SCREEN_HEIGHT: u8 = 50;
const PANEL_HEIGHT: u8 = 5;

const FOV_RADIUS: u8 = 10;

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
enum GameState {
    Playing,
    NewMap,
    Menu,
    Exit,
}

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
enum PlayerAction {
    Moved,
    Turn,
    NoTurn,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Direction {
    Up,
    Down,
    Left,
    Right
}

impl Direction {
    fn to_rel_point(self) -> Point<i16> {
        match self {
            Direction::Up       => Point::new(0, -1),
            Direction::Down     => Point::new(0, 1),
            Direction::Left     => Point::new(-1, 0),
            Direction::Right    => Point::new(1, 0),
        }
    }
}

#[derive(Debug)]
enum KeyType {
    Movement(Direction),
    Exit,
    NewGame,
    Other,
}

fn key_type(key: &Key) -> KeyType {
    match key.code {
        KeyCode::Right  =>  KeyType::Movement(Direction::Right),
        KeyCode::Left   =>  KeyType::Movement(Direction::Left),
        KeyCode::Up     =>  KeyType::Movement(Direction::Up),
        KeyCode::Down   =>  KeyType::Movement(Direction::Down),
        KeyCode::Escape =>  KeyType::Exit,
        KeyCode::F1     =>  KeyType::NewGame,
        _ => KeyType::Other,
    }
}

fn render_all<'a>(root: &mut RootConsole, buffer_console: &mut Offscreen, map: &map::Map, npcs: &Vec<units::Unit<'a>>, player: &units::Unit) {
    buffer_console.clear();
    root.clear();

    // With the scrolling map, we need to try to centre the player on the screen
    // without going past the bounds of the buffer.
    let (map_width, map_height) = map.get_map_size();
    let draw_left = player.get_x() - SCREEN_WIDTH as i16 / 2;
    let draw_top = player.get_y() - SCREEN_HEIGHT as i16 / 2;

    let mut view_port = rectangle::Rectangle::new(Point{x: draw_left, y: draw_top}, (SCREEN_WIDTH, SCREEN_HEIGHT - PANEL_HEIGHT));
    view_port.clamp_to((0,0), (map_width as i16, map_height as i16));

    map.render_map(buffer_console);

    for unit in npcs.iter() {
        if map.point_in_fov(unit.get_position()) {
            unit.render(buffer_console);
        }
    }

    player.render(buffer_console);

    tcod::console::blit(buffer_console, (view_port.top_left.x as i32, view_port.top_left.y as i32), (SCREEN_WIDTH as i32, (SCREEN_HEIGHT - PANEL_HEIGHT) as i32), root, (0,0), 1.0, 1.0);
    root.flush();
}

fn handle_input<'a>(root: &mut RootConsole, cur_game_state: GameState, map: &map::Map, npcs: &mut Vec<units::Unit<'a>>, player: &mut units::Unit) -> (PlayerAction, GameState) {
    let key = root.wait_for_keypress(true);

    let mut player_action: PlayerAction = PlayerAction::NoTurn;
    let mut new_game_state: GameState = GameState::Playing;

    match key_type(&key) {
        KeyType::Movement(dir) if cur_game_state == GameState::Playing => {
            let pos = player.get_position();
            let new_pos = pos + dir.to_rel_point();

            player_action = match map.can_move_to(new_pos) {
                map::CanMoveResponse::Open => {
                    if let Some(enemy) = npcs.iter_mut().filter(|n| n.get_position() == new_pos).next() {
                        player.attack(enemy);
                        PlayerAction::Turn
                    } else {
                        player.move_to(new_pos);
                        PlayerAction::Moved
                    }
                },
                map::CanMoveResponse::Scenery => {
                    PlayerAction::NoTurn
                } // Nothing to do.
            };
        },
        KeyType::Movement(_) if cur_game_state == GameState::Menu => {} // Will likely be used for menus
        KeyType::Movement(_) => unreachable!(),

        KeyType::Exit           => {
            new_game_state = GameState::Exit;
        },
        KeyType::NewGame        => {
            new_game_state = GameState::NewMap;
        }
        KeyType::Other          => println!("{:?}", key),
    }

    (player_action, new_game_state)
}

fn main() {
    let mut root = RootConsole::initializer()
                    .size(SCREEN_WIDTH as i32, SCREEN_HEIGHT as i32)
                    .title("Roguelike Tutorial")
                    .fullscreen(false)
                    .font("arial10x10.png", FontLayout::Tcod)
                    .font_type(FontType::Greyscale)
                    .init();

    let mut buffer_console = Offscreen::new(map::MAP_MAX_WIDTH as i32, map::MAP_MAX_HEIGHT as i32);
    root.set_default_foreground(tcod::colors::WHITE);

    let unit_types = units::load_unit_types();
    let (mut map, mut npcs, start_coord) = map::Map::init(&unit_types);

    let player_type = units::UnitType::new("Player", '@', tcod::colors::WHITE);
    let mut player = units::Unit::new(start_coord, &player_type);

    map.update_fov(player.get_position(), FOV_RADIUS);

    let mut game_state = GameState::Playing;

    while !root.window_closed() {
        render_all(&mut root, &mut buffer_console, &map, &npcs, &player);

        let (player_action, new_game_state) = handle_input(&mut root, game_state, &map, &mut npcs, &mut player);
        game_state = new_game_state;

        if player_action == PlayerAction::Moved {
            map.update_fov(player.get_position(), FOV_RADIUS);
        }

        match (game_state, player_action) {
            (GameState::Exit, _) => break,
            (GameState::NewMap, _) => {
                let (new_map, units, start_coord) = map::Map::init(&unit_types);
                map = new_map;
                npcs = units;
                player.move_to(start_coord);
                map.update_fov(start_coord, FOV_RADIUS);
                game_state = GameState::Playing;
            }
            (GameState::Playing, PlayerAction::Moved) | (GameState::Playing, PlayerAction::Turn) => {
                for enemy in npcs.iter_mut() {
                    enemy.take_turn(&map, &mut player);
                }
            }
            _ => {} // Don't update AI.
        }
    }
}
<|endoftext|>


<commit_before>use regex::Regex;
use std::io;
use std::io::prelude::*;
use super::event_stream::{Action, HandlerAction, Response, EventStream};

static MODE_WALLOPS: u16 = 4;
static MODE_INVISIBLE: u16 = 8;

fn mode_for(invisible: bool, wallops: bool) -> u16 {
    (if invisible { MODE_WALLOPS } else { 0 }) + (if wallops { MODE_INVISIBLE } else { 0 })
}

pub fn pong_handler(line: &str) -> Response {
    //debug!("pong_handler considering message \"{}\"", s);
    if line.starts_with("PING") {
        let resp = format!("PONG {}\r\n", line.split(' ').skip(1).next().or(Some("")).unwrap());
        //debug!("pong_handler responding \"{}\"", resp);
        Response::respond(resp.to_string())
    } else {
        //debug!("pong_handler returning Continue");
        Response::nothing()
    }
}

pub fn timeout_handler(line: &str) -> Response {
    if line.starts_with("ERROR :Closing Link:") {
        Response(None, HandlerAction::Keep, Action::Stop)
    } else {
        Response::nothing()
    }
}

pub fn login(stream: &mut EventStream, nick: &str,
             user: &str, realname: &str,
             invisible: bool, wallops: bool) -> io::Result<String> {
    let re = Regex::new(r"^([^\s]+)\s+001").unwrap();
    let server_responses = stream.await_lines(vec![re.clone()]);
    let login_responses = stream.await_lines(vec![Regex::new(&format!(r"MODE {} :\+[iswx]+$", nick))
                                                  .ok().expect("Regex compilation failure: bad username?")]);

    try!(write!(stream, "NICK {}\r\n", nick));
    try!(write!(stream, "USER {} {} unused {}\r\n", user, mode_for(invisible, wallops), realname));

    login_responses.into_iter().map(|mut f| f.get()).next().expect("Didn't get login response.");

    Ok(server_responses.into_iter().map(|mut f| {
        re.captures(&f.get())
            .expect("Regex match was bad")
            .at(1).expect("Regex didn't capture").to_string()
    }).next().expect("Didn't get server response"))
}

pub fn join(stream: &mut EventStream, server: &str, channels: &[&str]) -> io::Result<()> {
    let regexes = channels.iter().map(|chan| Regex::new(&format!(r"JOIN\s+:?{}", chan)).unwrap()).collect();
    let responses = stream.await_lines(regexes);

    for chan in channels.iter() {
        info!("Joining channel {}...", chan);
        try!(write!(stream, "{} JOIN {}\r\n", server, chan));
    }
    let re = Regex::new(r"JOIN\s+:?([^\s]+)").unwrap();
    responses.into_iter().map(|f| {
        info!("Joined channel {}!", re.captures(&f.into_inner()).unwrap().at(1).unwrap());
    }).count();
    Ok(())
}

pub struct UserInfo<'a> {
    pub nick: &'a str,
    pub user: Option<&'a str>,
    pub host: Option<&'a str>,
}

impl<'a> UserInfo<'a> {

    pub fn parse(s: &'a str) -> Option<UserInfo<'a>> {
        Regex::new(r"^([][\\`_^{|}a-zA-Z][][\\`_^{|}a-zA-Z0-9-]*)((!([^ @]+))?@(.*))?$").unwrap()
            .captures(s).map(|c| {
                UserInfo{
                    nick: c.at(1).expect("Bad match group"),
                    user: c.at(4),
                    host: c.at(5),
                }
            })
    }

}

pub enum Source<'a> {
    Server(&'a str),
    User(UserInfo<'a>),
}

impl<'a> Source<'a> {

    pub fn parse(s: &'a str) -> Option<Source<'a>> {
        UserInfo::parse(s).map(|u| Source::User(u))
            .or(Some(Source::Server(s)))
    }

}

pub enum Dest<'a> {
    Nick(&'a str),
    Chan(&'a str),
}

impl<'a> Dest<'a> {

    pub fn parse(s: &'a str) -> Option<Dest<'a>> {
        let chan_re = Regex::new(r"^[#+&!][^,:]+$").unwrap();
        if chan_re.is_match(s) {
            Some(Dest::Chan(s))
        } else {
            Some(Dest::Nick(s))
        }
    }

    pub fn format(&self) -> String {
        match self {
            &Dest::Nick(n) => n.to_string(),
            &Dest::Chan(c) => c.to_string(),
        }
    }

}

pub struct Privmsg<'a> {
    pub src: Option<Source<'a>>,
    pub dst: Dest<'a>,
    pub msg: &'a str,
}

impl<'a> Privmsg<'a> {

    pub fn parse(line: &'a str) -> Option<Privmsg<'a>> {
        Regex::new(r"^:([^\s]+)\s+PRIVMSG\s+([^\s]+)\s+:?(.*)$").unwrap()
            .captures(line).map(
                |c| Source::parse(c.at(1).expect("Bad match group")).map(
                    |src| Dest::parse(c.at(2).expect("Bad match group")).map(
                        |dst| Privmsg{
                            src: Some(src),
                            dst: dst,
                            msg: c.at(3).expect("Bad match group"),
                        })
                        .unwrap())
                    .unwrap())
    }

    pub fn new(dst: Dest<'a>, msg: &'a str) -> Privmsg<'a> {
        Privmsg{
            src: None,
            dst: dst,
            msg: msg,
        }
    }

    pub fn format(&self) -> String {
        format!("PRIVMSG {} :{}", self.dst.format(), self.msg)
    }

    pub fn reply_target(&'a self, nick: &str) -> Option<Dest<'a>> {
        match self.dst {
            Dest::Nick(ref n) if *n == nick => {
                // This is a PM, we should respond directly to the user that sent it.
                if let Some(Source::User(ref user_info)) = self.src {
                    Some(Dest::Nick(user_info.nick))
                } else {
                    None
                }
            },
            Dest::Chan(ref chan) => Some(Dest::Chan(chan)),
            _ => {
                //error!("How'd we get this message? \"{}\"", line);
                None
            },
        }
    }

    pub fn targeted_msg(self, nick: &str) -> Option<Privmsg<'a>> {
        if let Some(Source::User(_)) = self.src {
            Some(self)
        } else if let Some(c) = Regex::new(&format!(r"^{}[:,]?\s+(.*)\s*$", nick)).ok().expect("bad regex").captures(self.msg) {
            Some(Privmsg{
                src: self.src,
                dst: self.dst,
                msg: c.at(1).expect("Bad regex group"),
            })
        } else {
            None
        }
    }

}
<commit_msg>targeted messages to us with /msg have us as dest<commit_after>use regex::Regex;
use std::io;
use std::io::prelude::*;
use super::event_stream::{Action, HandlerAction, Response, EventStream};

static MODE_WALLOPS: u16 = 4;
static MODE_INVISIBLE: u16 = 8;

fn mode_for(invisible: bool, wallops: bool) -> u16 {
    (if invisible { MODE_WALLOPS } else { 0 }) + (if wallops { MODE_INVISIBLE } else { 0 })
}

pub fn pong_handler(line: &str) -> Response {
    //debug!("pong_handler considering message \"{}\"", s);
    if line.starts_with("PING") {
        let resp = format!("PONG {}\r\n", line.split(' ').skip(1).next().or(Some("")).unwrap());
        //debug!("pong_handler responding \"{}\"", resp);
        Response::respond(resp.to_string())
    } else {
        //debug!("pong_handler returning Continue");
        Response::nothing()
    }
}

pub fn timeout_handler(line: &str) -> Response {
    if line.starts_with("ERROR :Closing Link:") {
        Response(None, HandlerAction::Keep, Action::Stop)
    } else {
        Response::nothing()
    }
}

pub fn login(stream: &mut EventStream, nick: &str,
             user: &str, realname: &str,
             invisible: bool, wallops: bool) -> io::Result<String> {
    let re = Regex::new(r"^([^\s]+)\s+001").unwrap();
    let server_responses = stream.await_lines(vec![re.clone()]);
    let login_responses = stream.await_lines(vec![Regex::new(&format!(r"MODE {} :\+[iswx]+$", nick))
                                                  .ok().expect("Regex compilation failure: bad username?")]);

    try!(write!(stream, "NICK {}\r\n", nick));
    try!(write!(stream, "USER {} {} unused {}\r\n", user, mode_for(invisible, wallops), realname));

    login_responses.into_iter().map(|mut f| f.get()).next().expect("Didn't get login response.");

    Ok(server_responses.into_iter().map(|mut f| {
        re.captures(&f.get())
            .expect("Regex match was bad")
            .at(1).expect("Regex didn't capture").to_string()
    }).next().expect("Didn't get server response"))
}

pub fn join(stream: &mut EventStream, server: &str, channels: &[&str]) -> io::Result<()> {
    let regexes = channels.iter().map(|chan| Regex::new(&format!(r"JOIN\s+:?{}", chan)).unwrap()).collect();
    let responses = stream.await_lines(regexes);

    for chan in channels.iter() {
        info!("Joining channel {}...", chan);
        try!(write!(stream, "{} JOIN {}\r\n", server, chan));
    }
    let re = Regex::new(r"JOIN\s+:?([^\s]+)").unwrap();
    responses.into_iter().map(|f| {
        info!("Joined channel {}!", re.captures(&f.into_inner()).unwrap().at(1).unwrap());
    }).count();
    Ok(())
}

pub struct UserInfo<'a> {
    pub nick: &'a str,
    pub user: Option<&'a str>,
    pub host: Option<&'a str>,
}

impl<'a> UserInfo<'a> {

    pub fn parse(s: &'a str) -> Option<UserInfo<'a>> {
        Regex::new(r"^([][\\`_^{|}a-zA-Z][][\\`_^{|}a-zA-Z0-9-]*)((!([^ @]+))?@(.*))?$").unwrap()
            .captures(s).map(|c| {
                UserInfo{
                    nick: c.at(1).expect("Bad match group"),
                    user: c.at(4),
                    host: c.at(5),
                }
            })
    }

}

pub enum Source<'a> {
    Server(&'a str),
    User(UserInfo<'a>),
}

impl<'a> Source<'a> {

    pub fn parse(s: &'a str) -> Option<Source<'a>> {
        UserInfo::parse(s).map(|u| Source::User(u))
            .or(Some(Source::Server(s)))
    }

}

pub enum Dest<'a> {
    Nick(&'a str),
    Chan(&'a str),
}

impl<'a> Dest<'a> {

    pub fn parse(s: &'a str) -> Option<Dest<'a>> {
        let chan_re = Regex::new(r"^[#+&!][^,:]+$").unwrap();
        if chan_re.is_match(s) {
            Some(Dest::Chan(s))
        } else {
            Some(Dest::Nick(s))
        }
    }

    pub fn format(&self) -> String {
        match self {
            &Dest::Nick(n) => n.to_string(),
            &Dest::Chan(c) => c.to_string(),
        }
    }

}

pub struct Privmsg<'a> {
    pub src: Option<Source<'a>>,
    pub dst: Dest<'a>,
    pub msg: &'a str,
}

impl<'a> Privmsg<'a> {

    pub fn parse(line: &'a str) -> Option<Privmsg<'a>> {
        Regex::new(r"^:([^\s]+)\s+PRIVMSG\s+([^\s]+)\s+:?(.*)$").unwrap()
            .captures(line).map(
                |c| Source::parse(c.at(1).expect("Bad match group")).map(
                    |src| Dest::parse(c.at(2).expect("Bad match group")).map(
                        |dst| Privmsg{
                            src: Some(src),
                            dst: dst,
                            msg: c.at(3).expect("Bad match group"),
                        })
                        .unwrap())
                    .unwrap())
    }

    pub fn new(dst: Dest<'a>, msg: &'a str) -> Privmsg<'a> {
        Privmsg{
            src: None,
            dst: dst,
            msg: msg,
        }
    }

    pub fn format(&self) -> String {
        format!("PRIVMSG {} :{}", self.dst.format(), self.msg)
    }

    pub fn reply_target(&'a self, nick: &str) -> Option<Dest<'a>> {
        match self.dst {
            Dest::Nick(ref n) if *n == nick => {
                // This is a PM, we should respond directly to the user that sent it.
                if let Some(Source::User(ref user_info)) = self.src {
                    Some(Dest::Nick(user_info.nick))
                } else {
                    None
                }
            },
            Dest::Chan(ref chan) => Some(Dest::Chan(chan)),
            _ => {
                //error!("How'd we get this message? \"{}\"", line);
                None
            },
        }
    }

    pub fn targeted_msg(self, nick: &str) -> Option<Privmsg<'a>> {
        if let Dest::Nick(n) = self.dst {
            assert_eq!(n, nick);
            Some(self)
        } else if let Some(c) = Regex::new(&format!(r"^{}[:,]?\s+(.*)\s*$", nick)).ok().expect("bad regex").captures(self.msg) {
            Some(Privmsg{
                src: self.src,
                dst: self.dst,
                msg: c.at(1).expect("Bad regex group"),
            })
        } else {
            None
        }
    }

}
<|endoftext|>


<commit_before>use rustc_serialize::json::ToJson;
use std::path::{Path};
use hyper::Client;
use hyper::http::h2::Http2Protocol;
use hyper::net::{HttpsConnector, Openssl};
use notification::*;
use response::*;

static DEVELOPMENT: &'static str = "https://api.development.push.apple.com";
static PRODUCTION:  &'static str = "https://api.push.apple.com";

// Request headers
header! { (APNSId, "apns-id") => [String] }
header! { (APNSExpiration, "apns-expiration") => [String] }
header! { (APNSPriority, "apns-priority") => [String] }
header! { (APNSContentLength, "content-length") => [String] }
header! { (APNSTopic, "apns-topic") => [String] }

pub struct Provider {
    pub client: Client,
    pub path: String,
}

impl Provider {
    pub fn new(sandbox: bool, certificate_path: &str, private_key_path: &str) -> Provider {
        let ssl = Openssl::with_cert_and_key(Path::new(certificate_path), Path::new(private_key_path)).unwrap();
        let ssl_connector = HttpsConnector::new(ssl);
        let client = Client::with_protocol(Http2Protocol::with_connector(ssl_connector));
        let path = if sandbox {
            format!("{}{}", DEVELOPMENT, "/3/device/")
        } else {
            format!("{}{}", PRODUCTION, "/3/device/")
        };
        Provider {client: client, path: path}
    }

    pub fn push(&self, notification: Notification) -> Response {
        let url = format!("{}{}", self.path, notification.device_token);
        let url_str: &str = &url;   // .as_str() waiting on RFC revision (see issue #27729)
        let pay = notification.payload.to_json().to_string();
        let pay_str: &str = &pay;
        println!("{}", pay_str);
        let res = self.client.post(url_str)
            .body(pay_str)
            .send().unwrap();
        println!("{:?}", res);

        Response {status: APNSStatus::Success, reason: Some(APNSError::PayloadEmpty), timestamp: None, apns_id: None}
    }
}
<commit_msg>Add Headers<commit_after>use rustc_serialize::json::ToJson;
use std::path::{Path};
use hyper::Client;
use hyper::header::Headers;
use hyper::http::h2::Http2Protocol;
use hyper::net::{HttpsConnector, Openssl};
use notification::*;
use response::*;

static DEVELOPMENT: &'static str = "https://api.development.push.apple.com";
static PRODUCTION:  &'static str = "https://api.push.apple.com";

// Request headers
header! { (APNSId, "apns-id") => [String] }
header! { (APNSExpiration, "apns-expiration") => [String] }
header! { (APNSPriority, "apns-priority") => [String] }
header! { (APNSTopic, "apns-topic") => [String] }
header! { (APNSContentLength, "content-length") => [String] }

pub struct Provider {
    pub client: Client,
    pub path: String,
}

impl Provider {
    pub fn new(sandbox: bool, certificate_path: &str, private_key_path: &str) -> Provider {
        let ssl = Openssl::with_cert_and_key(Path::new(certificate_path), Path::new(private_key_path)).unwrap();
        let ssl_connector = HttpsConnector::new(ssl);
        let client = Client::with_protocol(Http2Protocol::with_connector(ssl_connector));
        let path = if sandbox {
            format!("{}{}", DEVELOPMENT, "/3/device/")
        } else {
            format!("{}{}", PRODUCTION, "/3/device/")
        };

        Provider {client: client, path: path}
    }

    pub fn push(&self, notification: Notification) -> Response {
        let url = format!("{}{}", self.path, notification.device_token);
        let url_str: &str = url.as_str();
        let pay = notification.payload.to_json().to_string();
        let pay_str: &str = pay.as_str();
        println!("{}", pay_str);

        // Add Headers
        let mut headers = Headers::new();
        let content_length = pay.len();
        headers.set(APNSContentLength(format!("{}", content_length)));
        if let Some(apns_id) = notification.apns_id {
            headers.set(APNSId(apns_id));
        }
        if let Some(apns_expiration) = notification.apns_expiration {
            headers.set(APNSExpiration(apns_expiration));
        }
        if let Some(apns_priority) = notification.apns_priority {
            headers.set(APNSExpiration(format!("{}", apns_priority)));
        }
        if let Some(apns_topic) = notification.apns_topic {
            headers.set(APNSExpiration(apns_topic));
        }

        // Send request to APNS server
        let res = self.client.post(url_str)
            .body(pay_str)
            .headers(headers)
            .send().unwrap();
        println!("{:?}", res);

        Response {status: APNSStatus::Success, reason: Some(APNSError::PayloadEmpty), timestamp: None, apns_id: None}
    }
}
<|endoftext|>


<commit_before>#![crate_type = "dylib"]
#![feature(plugin_registrar, quote, globs)]

extern crate rustc;
extern crate syntax;

use syntax::ast;
use syntax::codemap;
use syntax::ext::base::{ExtCtxt, MacResult, MacItems, DummyResult};
use syntax::parse;
use syntax::parse::token;
use syntax::fold::Folder;
use rustc::plugin::Registry;
use std::io::fs::File;
use std::str;

use rustast::{AstBuilder, DUMMY_SP};

mod translate;
mod grammar;
mod rustast;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
            token::intern("peg"),
            syntax::ext::base::IdentTT(box expand_peg_str, None));

    reg.register_syntax_extension(
            token::intern("peg_file"),
            syntax::ext::base::IdentTT(box expand_peg_file, None));
}

fn expand_peg_str<'s>(cx: &'s mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<ast::TokenTree>) -> Box<MacResult + 's> {
    let source = match parse_arg(cx, tts.as_slice()) {
        Some(source) => source,
        None => return DummyResult::any(sp),
    };

    expand_peg(cx, sp, ident, source.as_slice())
}

fn expand_peg_file<'s>(cx: &'s mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<ast::TokenTree>) -> Box<MacResult + 's> {
    let fname = match parse_arg(cx, tts.as_slice()) {
        Some(fname) => fname,
        None => return DummyResult::any(sp),
    };

    let path = Path::new(cx.codemap().span_to_filename(sp)).dir_path().join(fname);

    let source_utf8 = match File::open(&path).read_to_end() {
      Ok(source_utf8) => source_utf8,
      Err(e) => {
        cx.span_err(sp, e.to_string().as_slice());
        return DummyResult::any(sp)
      }
    };

    let source = str::from_utf8(source_utf8.as_slice()).unwrap();

    cx.codemap().new_filemap(path.as_str().unwrap().to_string(), "".to_string());

    expand_peg(cx, sp, ident, source.as_slice())
}

fn expand_peg(cx: &mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, source: &str) -> Box<MacResult + 'static> {
    let grammar_def = grammar::grammar(source);

    let grammar_def = match grammar_def {
      Ok(grammar_def) => grammar_def,
      Err(msg) => {
        cx.span_err(sp, msg.as_slice());
        return DummyResult::any(sp)
      }
    };

    let ast = translate::compile_grammar(cx, &grammar_def);

    // #![allow(non_snake_case_functions, unused_variable)]
    let attr = cx.attribute(DUMMY_SP, cx.meta_list(DUMMY_SP, token::InternedString::new("allow"), vec!(
        cx.meta_word(DUMMY_SP, token::InternedString::new("non_snake_case")),
        cx.meta_word(DUMMY_SP, token::InternedString::new("unused")),
    )));

    MacItems::new(Some(cx.item_mod(sp, sp, ident, vec!(attr), ast.view_items.clone(), ast.items.clone())).into_iter())
}

fn parse_arg(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Option<String> {
    use syntax::print::pprust;

    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_vec());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.
    let arg = cx.expander().fold_expr(parser.parse_expr());
    match arg.node {
        ast::ExprLit(ref spanned) => {
            match spanned.node {
                ast::LitStr(ref n, _) => {
                    if !parser.eat(&token::EOF) {
                        cx.span_err(parser.span,
                                    "expected only one string literal");
                        return None
                    }
                    return Some(n.get().to_string())
                }
                _ => {}
            }
        }
        _ => {}
    }

    let err = format!("expected string literal but got `{}`",
                      pprust::expr_to_string(&*arg));
    cx.span_err(parser.span, err.as_slice());
    None
}
<commit_msg>rust: EOF -> Eof<commit_after>#![crate_type = "dylib"]
#![feature(plugin_registrar, quote, globs)]

extern crate rustc;
extern crate syntax;

use syntax::ast;
use syntax::codemap;
use syntax::ext::base::{ExtCtxt, MacResult, MacItems, DummyResult};
use syntax::parse;
use syntax::parse::token;
use syntax::fold::Folder;
use rustc::plugin::Registry;
use std::io::fs::File;
use std::str;

use rustast::{AstBuilder, DUMMY_SP};

mod translate;
mod grammar;
mod rustast;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
            token::intern("peg"),
            syntax::ext::base::IdentTT(box expand_peg_str, None));

    reg.register_syntax_extension(
            token::intern("peg_file"),
            syntax::ext::base::IdentTT(box expand_peg_file, None));
}

fn expand_peg_str<'s>(cx: &'s mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<ast::TokenTree>) -> Box<MacResult + 's> {
    let source = match parse_arg(cx, tts.as_slice()) {
        Some(source) => source,
        None => return DummyResult::any(sp),
    };

    expand_peg(cx, sp, ident, source.as_slice())
}

fn expand_peg_file<'s>(cx: &'s mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<ast::TokenTree>) -> Box<MacResult + 's> {
    let fname = match parse_arg(cx, tts.as_slice()) {
        Some(fname) => fname,
        None => return DummyResult::any(sp),
    };

    let path = Path::new(cx.codemap().span_to_filename(sp)).dir_path().join(fname);

    let source_utf8 = match File::open(&path).read_to_end() {
      Ok(source_utf8) => source_utf8,
      Err(e) => {
        cx.span_err(sp, e.to_string().as_slice());
        return DummyResult::any(sp)
      }
    };

    let source = str::from_utf8(source_utf8.as_slice()).unwrap();

    cx.codemap().new_filemap(path.as_str().unwrap().to_string(), "".to_string());

    expand_peg(cx, sp, ident, source.as_slice())
}

fn expand_peg(cx: &mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, source: &str) -> Box<MacResult + 'static> {
    let grammar_def = grammar::grammar(source);

    let grammar_def = match grammar_def {
      Ok(grammar_def) => grammar_def,
      Err(msg) => {
        cx.span_err(sp, msg.as_slice());
        return DummyResult::any(sp)
      }
    };

    let ast = translate::compile_grammar(cx, &grammar_def);

    // #![allow(non_snake_case_functions, unused_variable)]
    let attr = cx.attribute(DUMMY_SP, cx.meta_list(DUMMY_SP, token::InternedString::new("allow"), vec!(
        cx.meta_word(DUMMY_SP, token::InternedString::new("non_snake_case")),
        cx.meta_word(DUMMY_SP, token::InternedString::new("unused")),
    )));

    MacItems::new(Some(cx.item_mod(sp, sp, ident, vec!(attr), ast.view_items.clone(), ast.items.clone())).into_iter())
}

fn parse_arg(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Option<String> {
    use syntax::print::pprust;

    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_vec());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.
    let arg = cx.expander().fold_expr(parser.parse_expr());
    match arg.node {
        ast::ExprLit(ref spanned) => {
            match spanned.node {
                ast::LitStr(ref n, _) => {
                    if !parser.eat(&token::Eof) {
                        cx.span_err(parser.span,
                                    "expected only one string literal");
                        return None
                    }
                    return Some(n.get().to_string())
                }
                _ => {}
            }
        }
        _ => {}
    }

    let err = format!("expected string literal but got `{}`",
                      pprust::expr_to_string(&*arg));
    cx.span_err(parser.span, err.as_slice());
    None
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]

use partition::TxSize;
use std::mem;

extern {
  static dc_qlookup_Q3: [i16; 256];
  static dc_qlookup_10_Q3: [i16; 256];
  static dc_qlookup_12_Q3: [i16; 256];

  static ac_qlookup_Q3: [i16; 256];
  static ac_qlookup_10_Q3: [i16; 256];
  static ac_qlookup_12_Q3: [i16; 256];
}

fn get_log_tx_scale(tx_size: TxSize) -> i32 {
  match tx_size {
    TxSize::TX_64X64 => 2,
    TxSize::TX_32X32 => 1,
    _ => 0
  }
}

pub fn dc_q(qindex: usize, bit_depth: usize) -> i16 {
  let &table = match bit_depth {
    8 => &dc_qlookup_Q3,
    10 => &dc_qlookup_10_Q3,
    12 => &dc_qlookup_12_Q3,
    _ => unimplemented!()
  };

  table[qindex]
}

pub fn ac_q(qindex: usize, bit_depth: usize) -> i16 {
  let &table = match bit_depth {
    8 => &ac_qlookup_Q3,
    10 => &ac_qlookup_10_Q3,
    12 => &ac_qlookup_12_Q3,
    _ => unimplemented!()
  };

  table[qindex]
}

#[derive(Debug, Default, Clone, Copy)]
pub struct QuantizationContext {
  log_tx_scale: i32,
  dc_quant: u32,
  dc_offset: i32,
  dc_mul_add: (u32, u32, u32),

  ac_quant: u32,
  ac_offset: i32,
  ac_mul_add: (u32, u32, u32)
}

fn divu_gen(d: u32) -> (u32, u32, u32) {
  let nbits = (mem::size_of_val(&d) as u64) * 8;
  let m = nbits - d.leading_zeros() as u64 - 1;
  if (d & (d - 1)) == 0 {
    (0xFFFFFFFF, 0xFFFFFFFF, m as u32)
  } else {
    let d = d as u64;
    let t = (1u64 << (m + nbits)) / d;
    let r = (t * d + d) & ((1 << nbits) - 1);
    if r <= 1u64 << m {
      (t as u32 + 1, 0u32, m as u32)
    } else {
      (t as u32, t as u32, m as u32)
    }
  }
}

#[inline]
fn divu_pair(x: i32, d: (u32, u32, u32)) -> i32 {
  let y = if x < 0 { -x } else { x } as u64;
  let (a, b, shift) = d;
  let shift = shift as u64;
  let a = a as u64;
  let b = b as u64;

  let y = (((a * y + b) >> 32) >> shift) as i32;
  if x < 0 {
    -y
  } else {
    y
  }
}

#[cfg(test)]
mod test {
  use super::*;
  #[test]
  fn test_divu_pair() {
    for d in 1..1024 {
      for x in -1000..1000 {
        let ab = divu_gen(d as u32);
        assert_eq!(x / d, divu_pair(x, ab));
      }
    }
  }
  #[test]
  fn gen_divu_table() {
    let b: Vec<(u32, u32, u32)> =
      dc_qlookup_Q3.iter().map(|&v| divu_gen(v as u32)).collect();

    println!("{:?}", b);
  }
}

impl QuantizationContext {
  pub fn update(&mut self, qindex: usize, tx_size: TxSize, is_intra: bool, bit_depth: usize) {
    self.log_tx_scale = get_log_tx_scale(tx_size);

    self.dc_quant = dc_q(qindex, bit_depth) as u32;
    self.dc_mul_add = divu_gen(self.dc_quant);

    self.ac_quant = ac_q(qindex, bit_depth) as u32;
    self.ac_mul_add = divu_gen(self.ac_quant);

    self.dc_offset = self.dc_quant as i32 * (if is_intra {21} else {15}) / 64;
    self.ac_offset = self.ac_quant as i32 * (if is_intra {21} else {15}) / 64;
  }

  #[inline]
  pub fn quantize(&self, coeffs: &mut [i32]) {
    coeffs[0] <<= self.log_tx_scale;
    coeffs[0] += coeffs[0].signum() * self.dc_offset;
    coeffs[0] = divu_pair(coeffs[0], self.dc_mul_add);

    for c in coeffs[1..].iter_mut() {
      *c <<= self.log_tx_scale;
      *c += c.signum() * self.ac_offset;
      *c = divu_pair(*c, self.ac_mul_add);
    }
  }
}

pub fn quantize_in_place(qindex: usize, coeffs: &mut [i32], tx_size: TxSize, bit_depth: usize) {
  let log_tx_scale = get_log_tx_scale(tx_size);

  let dc_quant = dc_q(qindex, bit_depth) as i32;
  let ac_quant = ac_q(qindex, bit_depth) as i32;

  // using 21/64=0.328125 as rounding offset. To be tuned
  let dc_offset = dc_quant * 21 / 64 as i32;
  let ac_offset = ac_quant * 21 / 64 as i32;

  coeffs[0] <<= log_tx_scale;
  coeffs[0] += coeffs[0].signum() * dc_offset;
  coeffs[0] /= dc_quant;

  for c in coeffs[1..].iter_mut() {
    *c <<= log_tx_scale;
    *c += c.signum() * ac_offset;
    *c /= ac_quant;
  }
}

pub fn dequantize(
  qindex: usize, coeffs: &[i32], rcoeffs: &mut [i32], tx_size: TxSize, bit_depth: usize
) {
  let log_tx_scale = get_log_tx_scale(tx_size) as i32;

  let val = coeffs[0] * dc_q(qindex, bit_depth) as i32;
  rcoeffs[0] = (val + if val < 0 { (1 << log_tx_scale) - 1 } else { 0 }) >> log_tx_scale;

  let ac_quant = ac_q(qindex, bit_depth) as i32;

  for (r, &c) in rcoeffs.iter_mut().zip(coeffs.iter()).skip(1) {
    *r = (c * ac_quant + if c < 0 { (1 << log_tx_scale) - 1 } else { 0 }) >> log_tx_scale;
  }
}
<commit_msg>Speed up dequantize function<commit_after>// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]

use partition::TxSize;
use std::mem;

extern {
  static dc_qlookup_Q3: [i16; 256];
  static dc_qlookup_10_Q3: [i16; 256];
  static dc_qlookup_12_Q3: [i16; 256];

  static ac_qlookup_Q3: [i16; 256];
  static ac_qlookup_10_Q3: [i16; 256];
  static ac_qlookup_12_Q3: [i16; 256];
}

fn get_log_tx_scale(tx_size: TxSize) -> i32 {
  match tx_size {
    TxSize::TX_64X64 => 2,
    TxSize::TX_32X32 => 1,
    _ => 0
  }
}

pub fn dc_q(qindex: usize, bit_depth: usize) -> i16 {
  let &table = match bit_depth {
    8 => &dc_qlookup_Q3,
    10 => &dc_qlookup_10_Q3,
    12 => &dc_qlookup_12_Q3,
    _ => unimplemented!()
  };

  table[qindex]
}

pub fn ac_q(qindex: usize, bit_depth: usize) -> i16 {
  let &table = match bit_depth {
    8 => &ac_qlookup_Q3,
    10 => &ac_qlookup_10_Q3,
    12 => &ac_qlookup_12_Q3,
    _ => unimplemented!()
  };

  table[qindex]
}

#[derive(Debug, Default, Clone, Copy)]
pub struct QuantizationContext {
  log_tx_scale: i32,
  dc_quant: u32,
  dc_offset: i32,
  dc_mul_add: (u32, u32, u32),

  ac_quant: u32,
  ac_offset: i32,
  ac_mul_add: (u32, u32, u32)
}

fn divu_gen(d: u32) -> (u32, u32, u32) {
  let nbits = (mem::size_of_val(&d) as u64) * 8;
  let m = nbits - d.leading_zeros() as u64 - 1;
  if (d & (d - 1)) == 0 {
    (0xFFFFFFFF, 0xFFFFFFFF, m as u32)
  } else {
    let d = d as u64;
    let t = (1u64 << (m + nbits)) / d;
    let r = (t * d + d) & ((1 << nbits) - 1);
    if r <= 1u64 << m {
      (t as u32 + 1, 0u32, m as u32)
    } else {
      (t as u32, t as u32, m as u32)
    }
  }
}

#[inline]
fn divu_pair(x: i32, d: (u32, u32, u32)) -> i32 {
  let y = if x < 0 { -x } else { x } as u64;
  let (a, b, shift) = d;
  let shift = shift as u64;
  let a = a as u64;
  let b = b as u64;

  let y = (((a * y + b) >> 32) >> shift) as i32;
  if x < 0 {
    -y
  } else {
    y
  }
}

#[cfg(test)]
mod test {
  use super::*;
  #[test]
  fn test_divu_pair() {
    for d in 1..1024 {
      for x in -1000..1000 {
        let ab = divu_gen(d as u32);
        assert_eq!(x / d, divu_pair(x, ab));
      }
    }
  }
  #[test]
  fn gen_divu_table() {
    let b: Vec<(u32, u32, u32)> =
      dc_qlookup_Q3.iter().map(|&v| divu_gen(v as u32)).collect();

    println!("{:?}", b);
  }
}

impl QuantizationContext {
  pub fn update(&mut self, qindex: usize, tx_size: TxSize, is_intra: bool, bit_depth: usize) {
    self.log_tx_scale = get_log_tx_scale(tx_size);

    self.dc_quant = dc_q(qindex, bit_depth) as u32;
    self.dc_mul_add = divu_gen(self.dc_quant);

    self.ac_quant = ac_q(qindex, bit_depth) as u32;
    self.ac_mul_add = divu_gen(self.ac_quant);

    self.dc_offset = self.dc_quant as i32 * (if is_intra {21} else {15}) / 64;
    self.ac_offset = self.ac_quant as i32 * (if is_intra {21} else {15}) / 64;
  }

  #[inline]
  pub fn quantize(&self, coeffs: &mut [i32]) {
    coeffs[0] <<= self.log_tx_scale;
    coeffs[0] += coeffs[0].signum() * self.dc_offset;
    coeffs[0] = divu_pair(coeffs[0], self.dc_mul_add);

    for c in coeffs[1..].iter_mut() {
      *c <<= self.log_tx_scale;
      *c += c.signum() * self.ac_offset;
      *c = divu_pair(*c, self.ac_mul_add);
    }
  }
}

pub fn quantize_in_place(qindex: usize, coeffs: &mut [i32], tx_size: TxSize, bit_depth: usize) {
  let log_tx_scale = get_log_tx_scale(tx_size);

  let dc_quant = dc_q(qindex, bit_depth) as i32;
  let ac_quant = ac_q(qindex, bit_depth) as i32;

  // using 21/64=0.328125 as rounding offset. To be tuned
  let dc_offset = dc_quant * 21 / 64 as i32;
  let ac_offset = ac_quant * 21 / 64 as i32;

  coeffs[0] <<= log_tx_scale;
  coeffs[0] += coeffs[0].signum() * dc_offset;
  coeffs[0] /= dc_quant;

  for c in coeffs[1..].iter_mut() {
    *c <<= log_tx_scale;
    *c += c.signum() * ac_offset;
    *c /= ac_quant;
  }
}

pub fn dequantize(
  qindex: usize, coeffs: &[i32], rcoeffs: &mut [i32], tx_size: TxSize, bit_depth: usize
) {
  let log_tx_scale = get_log_tx_scale(tx_size) as i32;
  let offset = (1 << log_tx_scale) - 1;

  let dc_quant = dc_q(qindex, bit_depth) as i32;
  let ac_quant = ac_q(qindex, bit_depth) as i32;

  for (i, (r, &c)) in rcoeffs.iter_mut().zip(coeffs.iter()).enumerate() {
    let quant = if i == 0 { dc_quant } else { ac_quant };
    *r = (c * quant + ((c >> 31) & offset)) >> log_tx_scale;
  }
}
<|endoftext|>


<commit_before>#![cfg(target_os = "macos")]

use std::os::raw::c_void;

use crate::{
    dpi::LogicalSize,
    event_loop::{EventLoop, EventLoopWindowTarget},
    monitor::MonitorHandle,
    window::{Window, WindowBuilder},
};

/// Corresponds to `NSRequestUserAttentionType`.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum RequestUserAttentionType {
    /// Corresponds to `NSCriticalRequest`.
    ///
    /// Dock icon will bounce until the application is focused.
    Critical,

    /// Corresponds to `NSInformationalRequest`.
    ///
    /// Dock icon will bounce once.
    Informational,
}

impl Default for RequestUserAttentionType {
    fn default() -> Self {
        RequestUserAttentionType::Critical
    }
}

/// Additional methods on `Window` that are specific to MacOS.
pub trait WindowExtMacOS {
    /// Returns a pointer to the cocoa `NSWindow` that is used by this window.
    ///
    /// The pointer will become invalid when the `Window` is destroyed.
    fn ns_window(&self) -> *mut c_void;

    /// Returns a pointer to the cocoa `NSView` that is used by this window.
    ///
    /// The pointer will become invalid when the `Window` is destroyed.
    fn ns_view(&self) -> *mut c_void;

    /// Request user attention, causing the application's dock icon to bounce.
    /// Note that this has no effect if the application is already focused.
    fn request_user_attention(&self, request_type: RequestUserAttentionType);

    /// Returns whether or not the window is in simple fullscreen mode.
    fn simple_fullscreen(&self) -> bool;

    /// Toggles a fullscreen mode that doesn't require a new macOS space.
    /// Returns a boolean indicating whether the transition was successful (this
    /// won't work if the window was already in the native fullscreen).
    ///
    /// This is how fullscreen used to work on macOS in versions before Lion.
    /// And allows the user to have a fullscreen window without using another
    /// space or taking control over the entire monitor.
    fn set_simple_fullscreen(&self, fullscreen: bool) -> bool;
}

impl WindowExtMacOS for Window {
    #[inline]
    fn ns_window(&self) -> *mut c_void {
        self.window.ns_window()
    }

    #[inline]
    fn ns_view(&self) -> *mut c_void {
        self.window.ns_view()
    }

    #[inline]
    fn request_user_attention(&self, request_type: RequestUserAttentionType) {
        self.window.request_user_attention(request_type)
    }

    #[inline]
    fn simple_fullscreen(&self) -> bool {
        self.window.simple_fullscreen()
    }

    #[inline]
    fn set_simple_fullscreen(&self, fullscreen: bool) -> bool {
        self.window.set_simple_fullscreen(fullscreen)
    }
}

/// Corresponds to `NSApplicationActivationPolicy`.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ActivationPolicy {
    /// Corresponds to `NSApplicationActivationPolicyRegular`.
    Regular,
    /// Corresponds to `NSApplicationActivationPolicyAccessory`.
    Accessory,
    /// Corresponds to `NSApplicationActivationPolicyProhibited`.
    Prohibited,
}

impl Default for ActivationPolicy {
    fn default() -> Self {
        ActivationPolicy::Regular
    }
}

/// Additional methods on `WindowBuilder` that are specific to MacOS.
///
/// **Note:** Properties dealing with the titlebar will be overwritten by the `with_decorations` method
/// on the base `WindowBuilder`:
///
///  - `with_titlebar_transparent`
///  - `with_title_hidden`
///  - `with_titlebar_hidden`
///  - `with_titlebar_buttons_hidden`
///  - `with_fullsize_content_view`
pub trait WindowBuilderExtMacOS {
    /// Sets the activation policy for the window being built.
    fn with_activation_policy(self, activation_policy: ActivationPolicy) -> WindowBuilder;
    /// Enables click-and-drag behavior for the entire window, not just the titlebar.
    fn with_movable_by_window_background(self, movable_by_window_background: bool)
        -> WindowBuilder;
    /// Makes the titlebar transparent and allows the content to appear behind it.
    fn with_titlebar_transparent(self, titlebar_transparent: bool) -> WindowBuilder;
    /// Hides the window title.
    fn with_title_hidden(self, title_hidden: bool) -> WindowBuilder;
    /// Hides the window titlebar.
    fn with_titlebar_hidden(self, titlebar_hidden: bool) -> WindowBuilder;
    /// Hides the window titlebar buttons.
    fn with_titlebar_buttons_hidden(self, titlebar_buttons_hidden: bool) -> WindowBuilder;
    /// Makes the window content appear behind the titlebar.
    fn with_fullsize_content_view(self, fullsize_content_view: bool) -> WindowBuilder;
    /// Build window with `resizeIncrements` property. Values must not be 0.
    fn with_resize_increments(self, increments: LogicalSize<f64>) -> WindowBuilder;
    fn with_disallow_hidpi(self, disallow_hidpi: bool) -> WindowBuilder;
}

impl WindowBuilderExtMacOS for WindowBuilder {
    #[inline]
    fn with_activation_policy(mut self, activation_policy: ActivationPolicy) -> WindowBuilder {
        self.platform_specific.activation_policy = activation_policy;
        self
    }

    #[inline]
    fn with_movable_by_window_background(
        mut self,
        movable_by_window_background: bool,
    ) -> WindowBuilder {
        self.platform_specific.movable_by_window_background = movable_by_window_background;
        self
    }

    #[inline]
    fn with_titlebar_transparent(mut self, titlebar_transparent: bool) -> WindowBuilder {
        self.platform_specific.titlebar_transparent = titlebar_transparent;
        self
    }

    #[inline]
    fn with_titlebar_hidden(mut self, titlebar_hidden: bool) -> WindowBuilder {
        self.platform_specific.titlebar_hidden = titlebar_hidden;
        self
    }

    #[inline]
    fn with_titlebar_buttons_hidden(mut self, titlebar_buttons_hidden: bool) -> WindowBuilder {
        self.platform_specific.titlebar_buttons_hidden = titlebar_buttons_hidden;
        self
    }

    #[inline]
    fn with_title_hidden(mut self, title_hidden: bool) -> WindowBuilder {
        self.platform_specific.title_hidden = title_hidden;
        self
    }

    #[inline]
    fn with_fullsize_content_view(mut self, fullsize_content_view: bool) -> WindowBuilder {
        self.platform_specific.fullsize_content_view = fullsize_content_view;
        self
    }

    #[inline]
    fn with_resize_increments(mut self, increments: LogicalSize<f64>) -> WindowBuilder {
        self.platform_specific.resize_increments = Some(increments.into());
        self
    }

    #[inline]
    fn with_disallow_hidpi(mut self, disallow_hidpi: bool) -> WindowBuilder {
        self.platform_specific.disallow_hidpi = disallow_hidpi;
        self
    }
}

/// Additional methods on `MonitorHandle` that are specific to MacOS.
pub trait MonitorHandleExtMacOS {
    /// Returns the identifier of the monitor for Cocoa.
    fn native_id(&self) -> u32;
    /// Returns a pointer to the NSScreen representing this monitor.
    fn ns_screen(&self) -> Option<*mut c_void>;
}

impl MonitorHandleExtMacOS for MonitorHandle {
    #[inline]
    fn native_id(&self) -> u32 {
        self.inner.native_identifier()
    }

    fn ns_screen(&self) -> Option<*mut c_void> {
        self.inner.ns_screen().map(|s| s as *mut c_void)
    }
}

/// Additional methods on `EventLoopWindowTarget` that are specific to macOS.
pub trait EventLoopWindowTargetExtMacOS {
    /// Hide the entire application. In most applications this is typically triggered with Command-H.
    fn hide_application(&self);
}

impl<T> EventLoopWindowTargetExtMacOS for EventLoopWindowTarget<T> {
    fn hide_application(&self) {
        let cls = objc::runtime::Class::get("NSApplication").unwrap();
        let app: cocoa::base::id = unsafe { msg_send![cls, sharedApplication] };
        unsafe { msg_send![app, hide: 0] }
    }
}
<commit_msg>Fix warnings on macos (#1419)<commit_after>#![cfg(target_os = "macos")]

use std::os::raw::c_void;

use crate::{
    dpi::LogicalSize,
    event_loop::EventLoopWindowTarget,
    monitor::MonitorHandle,
    window::{Window, WindowBuilder},
};

/// Corresponds to `NSRequestUserAttentionType`.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum RequestUserAttentionType {
    /// Corresponds to `NSCriticalRequest`.
    ///
    /// Dock icon will bounce until the application is focused.
    Critical,

    /// Corresponds to `NSInformationalRequest`.
    ///
    /// Dock icon will bounce once.
    Informational,
}

impl Default for RequestUserAttentionType {
    fn default() -> Self {
        RequestUserAttentionType::Critical
    }
}

/// Additional methods on `Window` that are specific to MacOS.
pub trait WindowExtMacOS {
    /// Returns a pointer to the cocoa `NSWindow` that is used by this window.
    ///
    /// The pointer will become invalid when the `Window` is destroyed.
    fn ns_window(&self) -> *mut c_void;

    /// Returns a pointer to the cocoa `NSView` that is used by this window.
    ///
    /// The pointer will become invalid when the `Window` is destroyed.
    fn ns_view(&self) -> *mut c_void;

    /// Request user attention, causing the application's dock icon to bounce.
    /// Note that this has no effect if the application is already focused.
    fn request_user_attention(&self, request_type: RequestUserAttentionType);

    /// Returns whether or not the window is in simple fullscreen mode.
    fn simple_fullscreen(&self) -> bool;

    /// Toggles a fullscreen mode that doesn't require a new macOS space.
    /// Returns a boolean indicating whether the transition was successful (this
    /// won't work if the window was already in the native fullscreen).
    ///
    /// This is how fullscreen used to work on macOS in versions before Lion.
    /// And allows the user to have a fullscreen window without using another
    /// space or taking control over the entire monitor.
    fn set_simple_fullscreen(&self, fullscreen: bool) -> bool;
}

impl WindowExtMacOS for Window {
    #[inline]
    fn ns_window(&self) -> *mut c_void {
        self.window.ns_window()
    }

    #[inline]
    fn ns_view(&self) -> *mut c_void {
        self.window.ns_view()
    }

    #[inline]
    fn request_user_attention(&self, request_type: RequestUserAttentionType) {
        self.window.request_user_attention(request_type)
    }

    #[inline]
    fn simple_fullscreen(&self) -> bool {
        self.window.simple_fullscreen()
    }

    #[inline]
    fn set_simple_fullscreen(&self, fullscreen: bool) -> bool {
        self.window.set_simple_fullscreen(fullscreen)
    }
}

/// Corresponds to `NSApplicationActivationPolicy`.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ActivationPolicy {
    /// Corresponds to `NSApplicationActivationPolicyRegular`.
    Regular,
    /// Corresponds to `NSApplicationActivationPolicyAccessory`.
    Accessory,
    /// Corresponds to `NSApplicationActivationPolicyProhibited`.
    Prohibited,
}

impl Default for ActivationPolicy {
    fn default() -> Self {
        ActivationPolicy::Regular
    }
}

/// Additional methods on `WindowBuilder` that are specific to MacOS.
///
/// **Note:** Properties dealing with the titlebar will be overwritten by the `with_decorations` method
/// on the base `WindowBuilder`:
///
///  - `with_titlebar_transparent`
///  - `with_title_hidden`
///  - `with_titlebar_hidden`
///  - `with_titlebar_buttons_hidden`
///  - `with_fullsize_content_view`
pub trait WindowBuilderExtMacOS {
    /// Sets the activation policy for the window being built.
    fn with_activation_policy(self, activation_policy: ActivationPolicy) -> WindowBuilder;
    /// Enables click-and-drag behavior for the entire window, not just the titlebar.
    fn with_movable_by_window_background(self, movable_by_window_background: bool)
        -> WindowBuilder;
    /// Makes the titlebar transparent and allows the content to appear behind it.
    fn with_titlebar_transparent(self, titlebar_transparent: bool) -> WindowBuilder;
    /// Hides the window title.
    fn with_title_hidden(self, title_hidden: bool) -> WindowBuilder;
    /// Hides the window titlebar.
    fn with_titlebar_hidden(self, titlebar_hidden: bool) -> WindowBuilder;
    /// Hides the window titlebar buttons.
    fn with_titlebar_buttons_hidden(self, titlebar_buttons_hidden: bool) -> WindowBuilder;
    /// Makes the window content appear behind the titlebar.
    fn with_fullsize_content_view(self, fullsize_content_view: bool) -> WindowBuilder;
    /// Build window with `resizeIncrements` property. Values must not be 0.
    fn with_resize_increments(self, increments: LogicalSize<f64>) -> WindowBuilder;
    fn with_disallow_hidpi(self, disallow_hidpi: bool) -> WindowBuilder;
}

impl WindowBuilderExtMacOS for WindowBuilder {
    #[inline]
    fn with_activation_policy(mut self, activation_policy: ActivationPolicy) -> WindowBuilder {
        self.platform_specific.activation_policy = activation_policy;
        self
    }

    #[inline]
    fn with_movable_by_window_background(
        mut self,
        movable_by_window_background: bool,
    ) -> WindowBuilder {
        self.platform_specific.movable_by_window_background = movable_by_window_background;
        self
    }

    #[inline]
    fn with_titlebar_transparent(mut self, titlebar_transparent: bool) -> WindowBuilder {
        self.platform_specific.titlebar_transparent = titlebar_transparent;
        self
    }

    #[inline]
    fn with_titlebar_hidden(mut self, titlebar_hidden: bool) -> WindowBuilder {
        self.platform_specific.titlebar_hidden = titlebar_hidden;
        self
    }

    #[inline]
    fn with_titlebar_buttons_hidden(mut self, titlebar_buttons_hidden: bool) -> WindowBuilder {
        self.platform_specific.titlebar_buttons_hidden = titlebar_buttons_hidden;
        self
    }

    #[inline]
    fn with_title_hidden(mut self, title_hidden: bool) -> WindowBuilder {
        self.platform_specific.title_hidden = title_hidden;
        self
    }

    #[inline]
    fn with_fullsize_content_view(mut self, fullsize_content_view: bool) -> WindowBuilder {
        self.platform_specific.fullsize_content_view = fullsize_content_view;
        self
    }

    #[inline]
    fn with_resize_increments(mut self, increments: LogicalSize<f64>) -> WindowBuilder {
        self.platform_specific.resize_increments = Some(increments.into());
        self
    }

    #[inline]
    fn with_disallow_hidpi(mut self, disallow_hidpi: bool) -> WindowBuilder {
        self.platform_specific.disallow_hidpi = disallow_hidpi;
        self
    }
}

/// Additional methods on `MonitorHandle` that are specific to MacOS.
pub trait MonitorHandleExtMacOS {
    /// Returns the identifier of the monitor for Cocoa.
    fn native_id(&self) -> u32;
    /// Returns a pointer to the NSScreen representing this monitor.
    fn ns_screen(&self) -> Option<*mut c_void>;
}

impl MonitorHandleExtMacOS for MonitorHandle {
    #[inline]
    fn native_id(&self) -> u32 {
        self.inner.native_identifier()
    }

    fn ns_screen(&self) -> Option<*mut c_void> {
        self.inner.ns_screen().map(|s| s as *mut c_void)
    }
}

/// Additional methods on `EventLoopWindowTarget` that are specific to macOS.
pub trait EventLoopWindowTargetExtMacOS {
    /// Hide the entire application. In most applications this is typically triggered with Command-H.
    fn hide_application(&self);
}

impl<T> EventLoopWindowTargetExtMacOS for EventLoopWindowTarget<T> {
    fn hide_application(&self) {
        let cls = objc::runtime::Class::get("NSApplication").unwrap();
        let app: cocoa::base::id = unsafe { msg_send![cls, sharedApplication] };
        unsafe { msg_send![app, hide: 0] }
    }
}
<|endoftext|>


<commit_before>use glib::object::Cast;
use glib::translate::ToGlibPtr;
use gtk::{self, BoxExt, ButtonSignals, ContainerExt, DialogExt, ScrolledWindowExt};
use gtk::{WidgetExt, WindowExt};
use gtk_sys;
use pango_sys::PangoWrapMode;
use sysinfo;

pub fn create_process_dialog(process: &sysinfo::Process, window: &gtk::Window,
                             start_time: u64, running_since: u64) {
    let flags = gtk_sys::GTK_DIALOG_DESTROY_WITH_PARENT |
                gtk_sys::GTK_DIALOG_USE_HEADER_BAR;
    let scroll = gtk::ScrolledWindow::new(None, None);
    let close_button = gtk::Button::new_with_label("Close");
    let vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0);
    scroll.set_policy(gtk::PolicyType::Never, gtk::PolicyType::Automatic);
    let popup = gtk::Dialog::new_with_buttons(Some(&format!("Information about {}", process.name)),
                                              Some(window),
                                              flags,
                                              &[]);
    let area = popup.get_content_area();
    let running_since = if start_time > process.start_time {
        start_time - process.start_time + running_since
    } else {
        process.start_time - start_time + running_since
    };
    let mut text = format!("name: {}\n\
                            pid: {}\n\
                            command: {}\n\
                            executable path: {}\n\
                            current working directory: {}\n\
                            root directory: {}\n\
                            memory usage: {} kB\n\
                            cpu usage: {}%\n\n\
                            Running since {} seconds\n\n\
                            environment:",
                            process.name,
                            process.pid,
                            process.cmd,
                            process.exe,
                            process.cwd,
                            process.root,
                            process.memory,
                            process.cpu_usage,
                            running_since);
    for env in process.environ.iter() {
        text.push_str(&format!("\n{:?}", env));
    }
    let label = gtk::Label::new(Some(&text));
    label.set_selectable(true);
    label.set_line_wrap(true);
    //label.set_line_wrap_mode(gtk::WrapMode::Char);
    unsafe { gtk_sys::gtk_label_set_line_wrap_mode(label.to_glib_none().0, PangoWrapMode::Char) };
    scroll.add(&label);
    vertical_layout.pack_start(&scroll, true, true, 0);
    vertical_layout.pack_start(&close_button, false, true, 0);
    vertical_layout.set_spacing(10);
    area.pack_start(&vertical_layout, true, true, 0);
    popup.set_size_request(400, 600);
    let popup = popup.upcast::<gtk::Window>();
    popup.set_resizable(false);
    popup.show_all();
    close_button.connect_clicked(move |_| {
        popup.destroy();
    });
}
<commit_msg>Fix "running since" miscalculation<commit_after>use glib::object::Cast;
use glib::translate::ToGlibPtr;
use gtk::{self, BoxExt, ButtonSignals, ContainerExt, DialogExt, ScrolledWindowExt};
use gtk::{WidgetExt, WindowExt};
use gtk_sys;
use pango_sys::PangoWrapMode;
use sysinfo;

pub fn create_process_dialog(process: &sysinfo::Process, window: &gtk::Window,
                             start_time: u64, running_since: u64) {
    let flags = gtk_sys::GTK_DIALOG_DESTROY_WITH_PARENT |
                gtk_sys::GTK_DIALOG_USE_HEADER_BAR;
    let scroll = gtk::ScrolledWindow::new(None, None);
    let close_button = gtk::Button::new_with_label("Close");
    let vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0);
    scroll.set_policy(gtk::PolicyType::Never, gtk::PolicyType::Automatic);
    let popup = gtk::Dialog::new_with_buttons(Some(&format!("Information about {}", process.name)),
                                              Some(window),
                                              flags,
                                              &[]);
    let area = popup.get_content_area();
    let running_since = if start_time > process.start_time {
        start_time - process.start_time + running_since
    } else {
        start_time + running_since - process.start_time
    };
    let mut text = format!("name: {}\n\
                            pid: {}\n\
                            command: {}\n\
                            executable path: {}\n\
                            current working directory: {}\n\
                            root directory: {}\n\
                            memory usage: {} kB\n\
                            cpu usage: {}%\n\n\
                            Running since {} seconds\n\n\
                            environment:",
                            process.name,
                            process.pid,
                            process.cmd,
                            process.exe,
                            process.cwd,
                            process.root,
                            process.memory,
                            process.cpu_usage,
                            running_since);
    for env in process.environ.iter() {
        text.push_str(&format!("\n{:?}", env));
    }
    let label = gtk::Label::new(Some(&text));
    label.set_selectable(true);
    label.set_line_wrap(true);
    //label.set_line_wrap_mode(gtk::WrapMode::Char);
    unsafe { gtk_sys::gtk_label_set_line_wrap_mode(label.to_glib_none().0, PangoWrapMode::Char) };
    scroll.add(&label);
    vertical_layout.pack_start(&scroll, true, true, 0);
    vertical_layout.pack_start(&close_button, false, true, 0);
    vertical_layout.set_spacing(10);
    area.pack_start(&vertical_layout, true, true, 0);
    popup.set_size_request(400, 600);
    let popup = popup.upcast::<gtk::Window>();
    popup.set_resizable(false);
    popup.show_all();
    close_button.connect_clicked(move |_| {
        popup.destroy();
    });
}
<|endoftext|>


<commit_before>use search::Search;
use text::Text;

pub struct Renderer;

impl Renderer {
    pub fn render(&self, search: &Search) -> Vec<Text> {
        let mut result = Vec::new();
        result.push(Text::Normal(self.header(search)));

        let selection = search.selection.clone().unwrap_or("".to_string());

        for position in 0..(search.config.visible_limit) {
            if position >= search.result.len() {
                result.push(Text::Blank);
                continue;
            }

            let choice = search.result[position].clone();

            if choice == selection {
                result.push(Text::Highlight(choice));
            } else {
                result.push(Text::Normal(choice))
            }
        }
        result
    }

    pub fn header(&self, search: &Search) -> String {
        format!("{} > {}", search.result.len(), search.query)
    }
}

#[cfg(test)]
mod tests {
    use search::Search;
    use text::Text;
    use configuration::Configuration;
    use super::*;

    #[test]
    fn it_renderes_selected_matches_with_a_highlight() {
        let config = Configuration::from_inputs(vec!["one".to_string(),
                                                     "two".to_string(),
                                                     "three".to_string()], None, Some(2));
        let search = Search::blank(config).down();
        let renderer = Renderer;

        let output = renderer.render(&search);

        assert_eq!(vec![Text::Normal("3 > ".to_string()),
                        Text::Normal("one".to_string()),
                        Text::Highlight("two".to_string())], output);
    }

    #[test]
    fn it_renders_a_missmatch() {
        let config = Configuration::from_inputs(vec!["one".to_string(),
                                                     "two".to_string(),
                                                     "three".to_string()], None, Some(2));

        let search = Search::blank(config).append_to_search("z");
        let renderer = Renderer;

        let output = renderer.render(&search);

        assert_eq!(vec![Text::Normal("0 > z".to_string()),
                        Text::Blank,
                        Text::Blank], output);
    }
}
<commit_msg>Make Renderer#render more rusty using a match.<commit_after>use search::Search;
use text::Text;

pub struct Renderer;

impl Renderer {
    pub fn render(&self, search: &Search) -> Vec<Text> {
        let mut result = Vec::new();
        result.push(Text::Normal(self.header(search)));

        let selection = search.selection.clone().unwrap_or("".to_string());

        for position in 0..search.config.visible_limit {
            let element = match search.result.get(position) {
                Some(choice) if *choice == selection => Text::Highlight(choice.clone()),
                Some(choice) => Text::Normal(choice.clone()),
                None => Text::Blank
            };
            result.push(element);
        }
        result
    }

    pub fn header(&self, search: &Search) -> String {
        format!("{} > {}", search.result.len(), search.query)
    }
}

#[cfg(test)]
mod tests {
    use search::Search;
    use text::Text;
    use configuration::Configuration;
    use super::*;

    #[test]
    fn it_renderes_selected_matches_with_a_highlight() {
        let config = Configuration::from_inputs(vec!["one".to_string(),
                                                     "two".to_string(),
                                                     "three".to_string()], None, Some(2));
        let search = Search::blank(config).down();
        let renderer = Renderer;

        let output = renderer.render(&search);

        assert_eq!(vec![Text::Normal("3 > ".to_string()),
                        Text::Normal("one".to_string()),
                        Text::Highlight("two".to_string())], output);
    }

    #[test]
    fn it_renders_a_missmatch() {
        let config = Configuration::from_inputs(vec!["one".to_string(),
                                                     "two".to_string(),
                                                     "three".to_string()], None, Some(2));

        let search = Search::blank(config).append_to_search("z");
        let renderer = Renderer;

        let output = renderer.render(&search);

        assert_eq!(vec![Text::Normal("0 > z".to_string()),
                        Text::Blank,
                        Text::Blank], output);
    }
}
<|endoftext|>