<commit_before>// This module loads the configuration file

use dailyschedule::{DailyEvent, Filter, Moment};
use std::convert::Into;
use std::error;
use std::fmt;
use std::fs;
use std::io;
use std::io::prelude::*;
use std::path;
use std::result;
use time::{Duration, at_utc};
use toml;
use daylight::calculate_daylight;

const CONFIG_HEAD: &'static str = "config";
const CONFIG_DEVICE: &'static str = "device";
const CONFIG_LATITUDE: &'static str = "latitude";
const CONFIG_LONGITUDE: &'static str = "longitude";
const CONFIG_NTP_SERVER: &'static str = "ntp";
const CIRCLE_MAC: &'static str = "mac";
const CIRCLE_DEFAULT: &'static str = "default";

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    MissingEventSpecifier(String),
    WrongEventSpecifier(String),
    MissingStartEvent(String),
    MissingEndEvent(String),
    ScheduleExpected(String),
    InvalidMac(String),
    InvalidDefault(String),
    MissingConfig,
    MissingNTP,
    LocationMissing,
    InvalidToml,
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Io(ref err) => fmt::Display::fmt(err, f),
            _ => write!(f, "Keeper configuraton error"),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Io(ref err) => error::Error::description(err),
            _ => "Keeper configuration error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Io(ref err) => err.cause(),
            _ => None,
        }
    }
}

#[derive(Debug)]
pub enum Event {
    Fixed(u8, u8),
    Fuzzy((u8, u8), (u8, u8)),
    Sunrise(u16),
    Sunset(u16)
}

impl Event {
    fn time_in_a_day(value: &toml::Value) -> Option<(u8, u8)> {
        let mapped: Option<Vec<i64>> = value.as_slice()
                                            .map(|arr| arr.iter()
                                                          .filter_map(|x|x.as_integer())
                                                          .collect());
        mapped.map_or(None, |v| {
            match v.len() {
                2 => {
                    let (h,m) = (v[0], v[1]);
                    if h < 0 || h >= 48 {
                        None
                    } else if m < 0 || m >= 60 {
                        None
                    } else {
                        Some((h as u8, m as u8))
                    }
                },
                _ => None
            }
        })
    }

    fn new(key: &str, value: &toml::Value) -> Result<Event> {
        let specifier = try!(key.split("_").last().ok_or(
                Error::MissingEventSpecifier(key.into())));

        match specifier {
            "fixed" => Event::time_in_a_day(value).map(|(f,s)| Event::Fixed(f,s)).ok_or(
                Error::WrongEventSpecifier("fixed must hold a array of two integers".into())),
            "fuzzy" => value.as_slice().map_or(None, |s| {
                    match s.len() {
                        2 => {
                            let first = Event::time_in_a_day(&s[0]);
                            let second = Event::time_in_a_day(&s[1]);
                            first.map_or(None, |f| second.map(|s| Event::Fuzzy(f,s)))
                        },
                        _ => None
                    }
                }).ok_or(Error::WrongEventSpecifier("fuzzy must hold a array of two arrays of two integers".into())),
            "sunrise" => value.as_integer().map(|i| Event::Sunrise(i as u16)).ok_or(
                Error::WrongEventSpecifier("sunrise must only hold one integer (variance in minutes)".into())),
            "sunset" => value.as_integer().map(|i| Event::Sunset(i as u16)).ok_or(
                Error::WrongEventSpecifier("sunset must only hold one integer (variance in minutes)".into())),
            _ => Err(Error::WrongEventSpecifier("unsupported specifier".into()))
        }
    }

    pub fn into_dailyevent(&self, device: &Device) -> DailyEvent {
        let latitude = device.latitude;
        let longitude = device.longitude;
        match self {
            &Event::Fixed(h,m) => DailyEvent::Fixed(Filter::Always, Moment::new(h,m,0)),
            &Event::Fuzzy((h1,m1),(h2,m2)) =>
                DailyEvent::Fuzzy(Filter::Always, Moment::new(h1,m1,0), Moment::new(h2,m2,0)),
            &Event::Sunrise(m) =>
                DailyEvent::ByClosure(
                    Filter::Always,
                    Box::new(move|t| {
                        let daylight = calculate_daylight(at_utc(t), latitude, longitude);
                        let dusk = Duration::seconds((daylight.sunrise -
                                                      daylight.twilight_morning).num_seconds() / 2);
                        Moment::new_from_timespec(daylight.twilight_morning + dusk)
                    }), Duration::minutes(m as i64)),
            &Event::Sunset(m) =>
                DailyEvent::ByClosure(
                    Filter::Always,
                    Box::new(move|t| {
                        let daylight = calculate_daylight(at_utc(t), latitude, longitude);
                        let dusk = Duration::seconds((daylight.sunset -
                                                      daylight.twilight_evening).num_seconds() / 2);
                        Moment::new_from_timespec(daylight.sunset + dusk)
                    }), Duration::minutes(m as i64)),
        }
    }
}

#[derive(Debug)]
pub struct Toggle {
    pub alias: String,
    pub start: Event,
    pub end: Event
}

impl Toggle {
    fn new(alias: &str, table: &toml::Table) -> Result<Toggle> {
        let start = try!(table.iter().find(|&(k,_)| k.starts_with("start_")).map_or(
                Err(Error::MissingStartEvent(alias.into())),
                |(k,v)| Event::new(&k[..], v)));
        let end = try!(table.iter().find(|&(k,_)| k.starts_with("end_")).map_or(
                Err(Error::MissingEndEvent(alias.into())),
                |(k,v)| Event::new(&k[..], v)));
        Ok(Toggle {
            alias: alias.into(),
            start: start,
            end: end
        })
    }
}

#[derive(Debug)]
pub enum CircleSetting {
    Off,
    On,
    Schedule
}

impl CircleSetting {
    fn new(setting_as_str: &str) -> Option<CircleSetting> {
        match setting_as_str {
            "off" => Some(CircleSetting::Off),
            "on" => Some(CircleSetting::On),
            "schedule" => Some(CircleSetting::Schedule),
            _ => None
        }
    }
}

#[derive(Debug)]
pub struct Circle {
    pub alias: String,
    pub mac: u64,
    pub default: CircleSetting,
    pub toggles: Vec<Toggle>
}

impl Circle {
    fn new(alias: &str, table: &toml::Table) -> Result<Circle> {
        let mut mac = None;
        let mut default = None;
        let mut toggles = vec![];

        for (k, v) in table {
            match &k[..] {
                CIRCLE_MAC => {
                    mac = v.as_str().map_or(None, |s| u64::from_str_radix(s, 16).ok());
                },
                CIRCLE_DEFAULT => {
                    default = v.as_str().map_or(None, |s| CircleSetting::new(s));
                },
                _ => {
                    let toggle = try!(v.as_table().map_or(
                            Err(Error::ScheduleExpected(alias.into())),
                            |t| Toggle::new(&k[..], t)));
                    toggles.push(toggle);
                }
            }
        }

        Ok(Circle {
            alias: alias.into(),
            mac: try!(mac.ok_or(Error::InvalidMac(alias.into()))),
            default: try!(default.ok_or(Error::InvalidDefault(alias.into()))),
            toggles: toggles
        })
    }
}

#[derive(Debug)]
pub struct Device {
    pub serial_device: Option<String>,
    pub latitude: f64,
    pub longitude: f64,
    pub ntp_server: String,
}

impl Device {
    fn new(table: &toml::Table) -> Result<Device> {
        let mut serial_device = None;
        let mut latitude = None;
        let mut longitude = None;
        let mut ntp = None;

        for (k, v) in table {
            match &k[..] {
                CONFIG_DEVICE => {
                    if let Some(string) = v.as_str() {
                        serial_device = Some(string.into());
                    }
                },
                CONFIG_LATITUDE => {
                    if let Some(lat) = v.as_float() {
                        latitude = Some(lat);
                    }
                },
                CONFIG_LONGITUDE => {
                    if let Some(long) = v.as_float() {
                        longitude = Some(long);
                    }
                },
                CONFIG_NTP_SERVER => {
                    if let Some(string) = v.as_str() {
                        ntp = Some(string.into());
                    }
                },
                _ => {}
            }
        }

        latitude.map_or(Err(Error::LocationMissing), |lat|
             longitude.map_or(Err(Error::LocationMissing), |long|
             ntp.map_or(Err(Error::MissingNTP), |ntp:String|
             serial_device.map_or(
                    Ok(Device{serial_device: None, latitude:lat, longitude:long, ntp_server:ntp.clone()}),
                    |dev| Ok(Device{serial_device: Some(dev), latitude:lat, longitude: long, ntp_server:ntp.clone()})))))
    }
}

#[derive(Debug)]
pub struct Config {
    pub device: Device,
    pub circles: Vec<Circle>
}

impl Config {
    pub fn new(configfile: &path::PathBuf) -> Result<Config> {
        let mut circles = vec![];
        let mut device = None;

        let mut config = String::new();
        let mut file = try!(fs::File::open(configfile));
        try!(file.read_to_string(&mut config));
        let config = try!(toml::Parser::new(&config).parse().ok_or(Error::InvalidToml));

        for (k,v) in config {
            if let Some(table) = v.as_table() {
                match &k[..] {
                    CONFIG_HEAD => {
                        device = Some(try!(Device::new(table)));
                    },
                    _ => {
                        circles.push(try!(Circle::new(&k[..], table)));
                    }
                }
            }
        }

        Ok(Config {
            device: try!(device.ok_or(Error::MissingConfig)),
            circles: circles
        })
    }
}
<commit_msg>config: fix sunset calculation<commit_after>// This module loads the configuration file

use dailyschedule::{DailyEvent, Filter, Moment};
use std::convert::Into;
use std::error;
use std::fmt;
use std::fs;
use std::io;
use std::io::prelude::*;
use std::path;
use std::result;
use time::{Duration, at_utc};
use toml;
use daylight::calculate_daylight;

const CONFIG_HEAD: &'static str = "config";
const CONFIG_DEVICE: &'static str = "device";
const CONFIG_LATITUDE: &'static str = "latitude";
const CONFIG_LONGITUDE: &'static str = "longitude";
const CONFIG_NTP_SERVER: &'static str = "ntp";
const CIRCLE_MAC: &'static str = "mac";
const CIRCLE_DEFAULT: &'static str = "default";

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    MissingEventSpecifier(String),
    WrongEventSpecifier(String),
    MissingStartEvent(String),
    MissingEndEvent(String),
    ScheduleExpected(String),
    InvalidMac(String),
    InvalidDefault(String),
    MissingConfig,
    MissingNTP,
    LocationMissing,
    InvalidToml,
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Io(ref err) => fmt::Display::fmt(err, f),
            _ => write!(f, "Keeper configuraton error"),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Io(ref err) => error::Error::description(err),
            _ => "Keeper configuration error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Io(ref err) => err.cause(),
            _ => None,
        }
    }
}

#[derive(Debug)]
pub enum Event {
    Fixed(u8, u8),
    Fuzzy((u8, u8), (u8, u8)),
    Sunrise(u16),
    Sunset(u16)
}

impl Event {
    fn time_in_a_day(value: &toml::Value) -> Option<(u8, u8)> {
        let mapped: Option<Vec<i64>> = value.as_slice()
                                            .map(|arr| arr.iter()
                                                          .filter_map(|x|x.as_integer())
                                                          .collect());
        mapped.map_or(None, |v| {
            match v.len() {
                2 => {
                    let (h,m) = (v[0], v[1]);
                    if h < 0 || h >= 48 {
                        None
                    } else if m < 0 || m >= 60 {
                        None
                    } else {
                        Some((h as u8, m as u8))
                    }
                },
                _ => None
            }
        })
    }

    fn new(key: &str, value: &toml::Value) -> Result<Event> {
        let specifier = try!(key.split("_").last().ok_or(
                Error::MissingEventSpecifier(key.into())));

        match specifier {
            "fixed" => Event::time_in_a_day(value).map(|(f,s)| Event::Fixed(f,s)).ok_or(
                Error::WrongEventSpecifier("fixed must hold a array of two integers".into())),
            "fuzzy" => value.as_slice().map_or(None, |s| {
                    match s.len() {
                        2 => {
                            let first = Event::time_in_a_day(&s[0]);
                            let second = Event::time_in_a_day(&s[1]);
                            first.map_or(None, |f| second.map(|s| Event::Fuzzy(f,s)))
                        },
                        _ => None
                    }
                }).ok_or(Error::WrongEventSpecifier("fuzzy must hold a array of two arrays of two integers".into())),
            "sunrise" => value.as_integer().map(|i| Event::Sunrise(i as u16)).ok_or(
                Error::WrongEventSpecifier("sunrise must only hold one integer (variance in minutes)".into())),
            "sunset" => value.as_integer().map(|i| Event::Sunset(i as u16)).ok_or(
                Error::WrongEventSpecifier("sunset must only hold one integer (variance in minutes)".into())),
            _ => Err(Error::WrongEventSpecifier("unsupported specifier".into()))
        }
    }

    pub fn into_dailyevent(&self, device: &Device) -> DailyEvent {
        let latitude = device.latitude;
        let longitude = device.longitude;
        match self {
            &Event::Fixed(h,m) => DailyEvent::Fixed(Filter::Always, Moment::new(h,m,0)),
            &Event::Fuzzy((h1,m1),(h2,m2)) =>
                DailyEvent::Fuzzy(Filter::Always, Moment::new(h1,m1,0), Moment::new(h2,m2,0)),
            &Event::Sunrise(m) =>
                DailyEvent::ByClosure(
                    Filter::Always,
                    Box::new(move|t| {
                        let daylight = calculate_daylight(at_utc(t), latitude, longitude);
                        let dusk = Duration::seconds((daylight.sunrise -
                                                      daylight.twilight_morning).num_seconds() / 2);
                        Moment::new_from_timespec(daylight.twilight_morning + dusk)
                    }), Duration::minutes(m as i64)),
            &Event::Sunset(m) =>
                DailyEvent::ByClosure(
                    Filter::Always,
                    Box::new(move|t| {
                        let daylight = calculate_daylight(at_utc(t), latitude, longitude);
                        let dusk = Duration::seconds((daylight.twilight_evening -
                                                      daylight.sunset).num_seconds() / 2);
                        Moment::new_from_timespec(daylight.sunset + dusk)
                    }), Duration::minutes(m as i64)),
        }
    }
}

#[derive(Debug)]
pub struct Toggle {
    pub alias: String,
    pub start: Event,
    pub end: Event
}

impl Toggle {
    fn new(alias: &str, table: &toml::Table) -> Result<Toggle> {
        let start = try!(table.iter().find(|&(k,_)| k.starts_with("start_")).map_or(
                Err(Error::MissingStartEvent(alias.into())),
                |(k,v)| Event::new(&k[..], v)));
        let end = try!(table.iter().find(|&(k,_)| k.starts_with("end_")).map_or(
                Err(Error::MissingEndEvent(alias.into())),
                |(k,v)| Event::new(&k[..], v)));
        Ok(Toggle {
            alias: alias.into(),
            start: start,
            end: end
        })
    }
}

#[derive(Debug)]
pub enum CircleSetting {
    Off,
    On,
    Schedule
}

impl CircleSetting {
    fn new(setting_as_str: &str) -> Option<CircleSetting> {
        match setting_as_str {
            "off" => Some(CircleSetting::Off),
            "on" => Some(CircleSetting::On),
            "schedule" => Some(CircleSetting::Schedule),
            _ => None
        }
    }
}

#[derive(Debug)]
pub struct Circle {
    pub alias: String,
    pub mac: u64,
    pub default: CircleSetting,
    pub toggles: Vec<Toggle>
}

impl Circle {
    fn new(alias: &str, table: &toml::Table) -> Result<Circle> {
        let mut mac = None;
        let mut default = None;
        let mut toggles = vec![];

        for (k, v) in table {
            match &k[..] {
                CIRCLE_MAC => {
                    mac = v.as_str().map_or(None, |s| u64::from_str_radix(s, 16).ok());
                },
                CIRCLE_DEFAULT => {
                    default = v.as_str().map_or(None, |s| CircleSetting::new(s));
                },
                _ => {
                    let toggle = try!(v.as_table().map_or(
                            Err(Error::ScheduleExpected(alias.into())),
                            |t| Toggle::new(&k[..], t)));
                    toggles.push(toggle);
                }
            }
        }

        Ok(Circle {
            alias: alias.into(),
            mac: try!(mac.ok_or(Error::InvalidMac(alias.into()))),
            default: try!(default.ok_or(Error::InvalidDefault(alias.into()))),
            toggles: toggles
        })
    }
}

#[derive(Debug)]
pub struct Device {
    pub serial_device: Option<String>,
    pub latitude: f64,
    pub longitude: f64,
    pub ntp_server: String,
}

impl Device {
    fn new(table: &toml::Table) -> Result<Device> {
        let mut serial_device = None;
        let mut latitude = None;
        let mut longitude = None;
        let mut ntp = None;

        for (k, v) in table {
            match &k[..] {
                CONFIG_DEVICE => {
                    if let Some(string) = v.as_str() {
                        serial_device = Some(string.into());
                    }
                },
                CONFIG_LATITUDE => {
                    if let Some(lat) = v.as_float() {
                        latitude = Some(lat);
                    }
                },
                CONFIG_LONGITUDE => {
                    if let Some(long) = v.as_float() {
                        longitude = Some(long);
                    }
                },
                CONFIG_NTP_SERVER => {
                    if let Some(string) = v.as_str() {
                        ntp = Some(string.into());
                    }
                },
                _ => {}
            }
        }

        latitude.map_or(Err(Error::LocationMissing), |lat|
             longitude.map_or(Err(Error::LocationMissing), |long|
             ntp.map_or(Err(Error::MissingNTP), |ntp:String|
             serial_device.map_or(
                    Ok(Device{serial_device: None, latitude:lat, longitude:long, ntp_server:ntp.clone()}),
                    |dev| Ok(Device{serial_device: Some(dev), latitude:lat, longitude: long, ntp_server:ntp.clone()})))))
    }
}

#[derive(Debug)]
pub struct Config {
    pub device: Device,
    pub circles: Vec<Circle>
}

impl Config {
    pub fn new(configfile: &path::PathBuf) -> Result<Config> {
        let mut circles = vec![];
        let mut device = None;

        let mut config = String::new();
        let mut file = try!(fs::File::open(configfile));
        try!(file.read_to_string(&mut config));
        let config = try!(toml::Parser::new(&config).parse().ok_or(Error::InvalidToml));

        for (k,v) in config {
            if let Some(table) = v.as_table() {
                match &k[..] {
                    CONFIG_HEAD => {
                        device = Some(try!(Device::new(table)));
                    },
                    _ => {
                        circles.push(try!(Circle::new(&k[..], table)));
                    }
                }
            }
        }

        Ok(Config {
            device: try!(device.ok_or(Error::MissingConfig)),
            circles: circles
        })
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "termcolor")]
use log::Level;
use log::LevelFilter;

pub use chrono::offset::{FixedOffset, Local, Offset, TimeZone, Utc};
use std::borrow::Cow;
#[cfg(feature = "termcolor")]
use termcolor::Color;

#[derive(Debug, Clone, Copy)]
/// Padding to be used for logging the level
pub enum LevelPadding {
    /// Add spaces on the left side
    Left,
    /// Add spaces on the right side
    Right,
    /// Do not pad the level
    Off,
}

#[derive(Debug, Clone, Copy)]
/// Padding to be used for logging the thread id/name
pub enum ThreadPadding {
    /// Add spaces on the left side, up to usize many
    Left(usize),
    /// Add spaces on the right side, up to usize many
    Right(usize),
    /// Do not pad the thread id/name
    Off,
}

#[derive(Debug, Clone, Copy, PartialEq)]
/// Mode for logging the thread name or id or both.
pub enum ThreadLogMode {
    /// Log thread ids only
    IDs,
    /// Log the thread names only
    Names,
    /// If this thread is named, log the name. Otherwise, log the thread id.
    Both,
}

/// Configuration for the Loggers
///
/// All loggers print the message in the following form:
/// `00:00:00 [LEVEL] crate::module: [lib.rs::100] your_message`
/// Every space delimited part except the actual message is optional.
///
/// Pass this struct to your logger to change when these information shall
/// be logged.
///
/// Construct using `Default` or using `ConfigBuilder`
#[derive(Debug, Clone)]
pub struct Config {
    pub(crate) time: LevelFilter,
    pub(crate) level: LevelFilter,
    pub(crate) level_padding: LevelPadding,
    pub(crate) thread: LevelFilter,
    pub(crate) thread_log_mode: ThreadLogMode,
    pub(crate) thread_padding: ThreadPadding,
    pub(crate) target: LevelFilter,
    pub(crate) location: LevelFilter,
    pub(crate) time_format: Cow<'static, str>,
    pub(crate) time_offset: FixedOffset,
    pub(crate) time_local: bool,
    pub(crate) filter_allow: Cow<'static, [Cow<'static, str>]>,
    pub(crate) filter_ignore: Cow<'static, [Cow<'static, str>]>,
    #[cfg(feature = "termcolor")]
    pub(crate) level_color: [Option<Color>; 6],
}

/// Builder for the Logger Configurations (`Config`)
///
/// All loggers print the message in the following form:
/// `00:00:00 [LEVEL] crate::module: [lib.rs::100] your_message`
/// Every space delimited part except the actual message is optional.
///
/// Use this struct to create a custom `Config` changing when these information shall
/// be logged. Every part can be enabled for a specific Level and is then
/// automatically enable for all lower levels as well.
///
/// The Result is that the logging gets more detailed the more verbose it gets.
/// E.g. to have one part shown always use `Level::Error`. But if you
/// want to show the source line only on `Trace` use that.
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct ConfigBuilder(Config);

impl ConfigBuilder {
    /// Create a new default ConfigBuilder
    pub fn new() -> ConfigBuilder {
        ConfigBuilder(Config::default())
    }

    /// Set at which level and above (more verbose) the level itself shall be logged (default is Error)
    pub fn set_max_level(&mut self, level: LevelFilter) -> &mut ConfigBuilder {
        self.0.level = level;
        self
    }

    /// Set at which level and  above (more verbose) the current time shall be logged (default is Error)
    pub fn set_time_level(&mut self, time: LevelFilter) -> &mut ConfigBuilder {
        self.0.time = time;
        self
    }

    /// Set at which level and above (more verbose) the thread id shall be logged. (default is Debug)
    pub fn set_thread_level(&mut self, thread: LevelFilter) -> &mut ConfigBuilder {
        self.0.thread = thread;
        self
    }

    /// Set at which level and above (more verbose) the target shall be logged. (default is Debug)
    pub fn set_target_level(&mut self, target: LevelFilter) -> &mut ConfigBuilder {
        self.0.target = target;
        self
    }

    /// Set at which level and above (more verbose) a source code reference shall be logged (default is Trace)
    pub fn set_location_level(&mut self, location: LevelFilter) -> &mut ConfigBuilder {
        self.0.location = location;
        self
    }

    /// Set how the levels should be padded, when logging (default is Left)
    pub fn set_level_padding(&mut self, padding: LevelPadding) -> &mut ConfigBuilder {
        self.0.level_padding = padding;
        self
    }

    /// Set how the thread should be padded
    pub fn set_thread_padding(&mut self, padding: ThreadPadding) -> &mut ConfigBuilder {
        self.0.thread_padding = padding;
        self
    }

    /// Set the mode for logging the thread
    pub fn set_thread_mode(&mut self, mode: ThreadLogMode) -> &mut ConfigBuilder {
        self.0.thread_log_mode = mode;
        self
    }

    /// Set the color used for printing the level (if the logger supports it),
    /// or None to use the default foreground color
    #[cfg(feature = "termcolor")]
    pub fn set_level_color(&mut self, level: Level, color: Option<Color>) -> &mut ConfigBuilder {
        self.0.level_color[level as usize] = color;
        self
    }

    /// Set time chrono [strftime] format string.
    ///
    /// [strftime]: https://docs.rs/chrono/0.4.0/chrono/format/strftime/index.html#specifiers
    pub fn set_time_format_str(&mut self, time_format: &'static str) -> &mut ConfigBuilder {
        self.0.time_format = Cow::Borrowed(time_format);
        self
    }

    /// Set time chrono [strftime] format string.
    ///
    /// [strftime]: https://docs.rs/chrono/0.4.0/chrono/format/strftime/index.html#specifiers
    pub fn set_time_format(&mut self, time_format: String) -> &mut ConfigBuilder {
        self.0.time_format = Cow::Owned(time_format);
        self
    }

    /// Set offset used for logging time (default is 0)
    pub fn set_time_offset(&mut self, time_offset: FixedOffset) -> &mut ConfigBuilder {
        self.0.time_offset = time_offset;
        self
    }

    /// set if you log in local timezone or UTC (default is UTC)
    pub fn set_time_to_local(&mut self, local: bool) -> &mut ConfigBuilder {
        self.0.time_local = local;
        self
    }

    /// Add allowed module filters.
    /// If any are specified, only records from modules starting with one of these entries will be printed
    ///
    /// For example, `add_filter_allow_str("tokio::uds")` would allow only logging from the `tokio` crates `uds` module.
    pub fn add_filter_allow_str(&mut self, filter_allow: &'static str) -> &mut ConfigBuilder {
        let mut list = Vec::from(&*self.0.filter_allow);
        list.push(Cow::Borrowed(filter_allow));
        self.0.filter_allow = Cow::Owned(list);
        self
    }

    /// Add allowed module filters.
    /// If any are specified, only records from modules starting with one of these entries will be printed
    ///
    /// For example, `add_filter_allow(format!("{}{}","tokio", "uds"))` would allow only logging from the `tokio` crates `uds` module.
    pub fn add_filter_allow(&mut self, filter_allow: String) -> &mut ConfigBuilder {
        let mut list = Vec::from(&*self.0.filter_allow);
        list.push(Cow::Owned(filter_allow));
        self.0.filter_allow = Cow::Owned(list);
        self
    }

    /// Clear allowed module filters.
    /// If none are specified, nothing is filtered out
    pub fn clear_filter_allow(&mut self) -> &mut ConfigBuilder {
        self.0.filter_allow = Cow::Borrowed(&[]);
        self
    }

    /// Add denied module filters.
    /// If any are specified, records from modules starting with one of these entries will be ignored
    ///
    /// For example, `add_filter_ignore_str("tokio::uds")` would deny logging from the `tokio` crates `uds` module.
    pub fn add_filter_ignore_str(&mut self, filter_ignore: &'static str) -> &mut ConfigBuilder {
        let mut list = Vec::from(&*self.0.filter_ignore);
        list.push(Cow::Borrowed(filter_ignore));
        self.0.filter_ignore = Cow::Owned(list);
        self
    }

    /// Add denied module filters.
    /// If any are specified, records from modules starting with one of these entries will be ignored
    ///
    /// For example, `add_filter_ignore(format!("{}{}","tokio", "uds"))` would deny logging from the `tokio` crates `uds` module.
    pub fn add_filter_ignore(&mut self, filter_ignore: String) -> &mut ConfigBuilder {
        let mut list = Vec::from(&*self.0.filter_ignore);
        list.push(Cow::Owned(filter_ignore));
        self.0.filter_ignore = Cow::Owned(list);
        self
    }

    /// Clear ignore module filters.
    /// If none are specified, nothing is filtered
    pub fn clear_filter_ignore(&mut self) -> &mut ConfigBuilder {
        self.0.filter_ignore = Cow::Borrowed(&[]);
        self
    }

    /// Build new `Config`
    pub fn build(&mut self) -> Config {
        self.0.clone()
    }
}

impl Default for ConfigBuilder {
    fn default() -> Self {
        ConfigBuilder::new()
    }
}

impl Default for Config {
    fn default() -> Config {
        Config {
            time: LevelFilter::Error,
            level: LevelFilter::Error,
            level_padding: LevelPadding::Off,
            thread: LevelFilter::Debug,
            thread_log_mode: ThreadLogMode::IDs,
            thread_padding: ThreadPadding::Off,
            target: LevelFilter::Debug,
            location: LevelFilter::Trace,
            time_format: Cow::Borrowed("%H:%M:%S"),
            time_offset: FixedOffset::east(0),
            time_local: false,
            filter_allow: Cow::Borrowed(&[]),
            filter_ignore: Cow::Borrowed(&[]),

            #[cfg(feature = "termcolor")]
            level_color: [
                None,                // Default foreground
                Some(Color::Red),    // Error
                Some(Color::Yellow), // Warn
                Some(Color::Blue),   // Info
                Some(Color::Cyan),   // Debug
                Some(Color::White),  // Trace
            ],
        }
    }
}
<commit_msg>Fix default level padding in docs<commit_after>#[cfg(feature = "termcolor")]
use log::Level;
use log::LevelFilter;

pub use chrono::offset::{FixedOffset, Local, Offset, TimeZone, Utc};
use std::borrow::Cow;
#[cfg(feature = "termcolor")]
use termcolor::Color;

#[derive(Debug, Clone, Copy)]
/// Padding to be used for logging the level
pub enum LevelPadding {
    /// Add spaces on the left side
    Left,
    /// Add spaces on the right side
    Right,
    /// Do not pad the level
    Off,
}

#[derive(Debug, Clone, Copy)]
/// Padding to be used for logging the thread id/name
pub enum ThreadPadding {
    /// Add spaces on the left side, up to usize many
    Left(usize),
    /// Add spaces on the right side, up to usize many
    Right(usize),
    /// Do not pad the thread id/name
    Off,
}

#[derive(Debug, Clone, Copy, PartialEq)]
/// Mode for logging the thread name or id or both.
pub enum ThreadLogMode {
    /// Log thread ids only
    IDs,
    /// Log the thread names only
    Names,
    /// If this thread is named, log the name. Otherwise, log the thread id.
    Both,
}

/// Configuration for the Loggers
///
/// All loggers print the message in the following form:
/// `00:00:00 [LEVEL] crate::module: [lib.rs::100] your_message`
/// Every space delimited part except the actual message is optional.
///
/// Pass this struct to your logger to change when these information shall
/// be logged.
///
/// Construct using `Default` or using `ConfigBuilder`
#[derive(Debug, Clone)]
pub struct Config {
    pub(crate) time: LevelFilter,
    pub(crate) level: LevelFilter,
    pub(crate) level_padding: LevelPadding,
    pub(crate) thread: LevelFilter,
    pub(crate) thread_log_mode: ThreadLogMode,
    pub(crate) thread_padding: ThreadPadding,
    pub(crate) target: LevelFilter,
    pub(crate) location: LevelFilter,
    pub(crate) time_format: Cow<'static, str>,
    pub(crate) time_offset: FixedOffset,
    pub(crate) time_local: bool,
    pub(crate) filter_allow: Cow<'static, [Cow<'static, str>]>,
    pub(crate) filter_ignore: Cow<'static, [Cow<'static, str>]>,
    #[cfg(feature = "termcolor")]
    pub(crate) level_color: [Option<Color>; 6],
}

/// Builder for the Logger Configurations (`Config`)
///
/// All loggers print the message in the following form:
/// `00:00:00 [LEVEL] crate::module: [lib.rs::100] your_message`
/// Every space delimited part except the actual message is optional.
///
/// Use this struct to create a custom `Config` changing when these information shall
/// be logged. Every part can be enabled for a specific Level and is then
/// automatically enable for all lower levels as well.
///
/// The Result is that the logging gets more detailed the more verbose it gets.
/// E.g. to have one part shown always use `Level::Error`. But if you
/// want to show the source line only on `Trace` use that.
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct ConfigBuilder(Config);

impl ConfigBuilder {
    /// Create a new default ConfigBuilder
    pub fn new() -> ConfigBuilder {
        ConfigBuilder(Config::default())
    }

    /// Set at which level and above (more verbose) the level itself shall be logged (default is Error)
    pub fn set_max_level(&mut self, level: LevelFilter) -> &mut ConfigBuilder {
        self.0.level = level;
        self
    }

    /// Set at which level and  above (more verbose) the current time shall be logged (default is Error)
    pub fn set_time_level(&mut self, time: LevelFilter) -> &mut ConfigBuilder {
        self.0.time = time;
        self
    }

    /// Set at which level and above (more verbose) the thread id shall be logged. (default is Debug)
    pub fn set_thread_level(&mut self, thread: LevelFilter) -> &mut ConfigBuilder {
        self.0.thread = thread;
        self
    }

    /// Set at which level and above (more verbose) the target shall be logged. (default is Debug)
    pub fn set_target_level(&mut self, target: LevelFilter) -> &mut ConfigBuilder {
        self.0.target = target;
        self
    }

    /// Set at which level and above (more verbose) a source code reference shall be logged (default is Trace)
    pub fn set_location_level(&mut self, location: LevelFilter) -> &mut ConfigBuilder {
        self.0.location = location;
        self
    }

    /// Set how the levels should be padded, when logging (default is Off)
    pub fn set_level_padding(&mut self, padding: LevelPadding) -> &mut ConfigBuilder {
        self.0.level_padding = padding;
        self
    }

    /// Set how the thread should be padded
    pub fn set_thread_padding(&mut self, padding: ThreadPadding) -> &mut ConfigBuilder {
        self.0.thread_padding = padding;
        self
    }

    /// Set the mode for logging the thread
    pub fn set_thread_mode(&mut self, mode: ThreadLogMode) -> &mut ConfigBuilder {
        self.0.thread_log_mode = mode;
        self
    }

    /// Set the color used for printing the level (if the logger supports it),
    /// or None to use the default foreground color
    #[cfg(feature = "termcolor")]
    pub fn set_level_color(&mut self, level: Level, color: Option<Color>) -> &mut ConfigBuilder {
        self.0.level_color[level as usize] = color;
        self
    }

    /// Set time chrono [strftime] format string.
    ///
    /// [strftime]: https://docs.rs/chrono/0.4.0/chrono/format/strftime/index.html#specifiers
    pub fn set_time_format_str(&mut self, time_format: &'static str) -> &mut ConfigBuilder {
        self.0.time_format = Cow::Borrowed(time_format);
        self
    }

    /// Set time chrono [strftime] format string.
    ///
    /// [strftime]: https://docs.rs/chrono/0.4.0/chrono/format/strftime/index.html#specifiers
    pub fn set_time_format(&mut self, time_format: String) -> &mut ConfigBuilder {
        self.0.time_format = Cow::Owned(time_format);
        self
    }

    /// Set offset used for logging time (default is 0)
    pub fn set_time_offset(&mut self, time_offset: FixedOffset) -> &mut ConfigBuilder {
        self.0.time_offset = time_offset;
        self
    }

    /// set if you log in local timezone or UTC (default is UTC)
    pub fn set_time_to_local(&mut self, local: bool) -> &mut ConfigBuilder {
        self.0.time_local = local;
        self
    }

    /// Add allowed module filters.
    /// If any are specified, only records from modules starting with one of these entries will be printed
    ///
    /// For example, `add_filter_allow_str("tokio::uds")` would allow only logging from the `tokio` crates `uds` module.
    pub fn add_filter_allow_str(&mut self, filter_allow: &'static str) -> &mut ConfigBuilder {
        let mut list = Vec::from(&*self.0.filter_allow);
        list.push(Cow::Borrowed(filter_allow));
        self.0.filter_allow = Cow::Owned(list);
        self
    }

    /// Add allowed module filters.
    /// If any are specified, only records from modules starting with one of these entries will be printed
    ///
    /// For example, `add_filter_allow(format!("{}{}","tokio", "uds"))` would allow only logging from the `tokio` crates `uds` module.
    pub fn add_filter_allow(&mut self, filter_allow: String) -> &mut ConfigBuilder {
        let mut list = Vec::from(&*self.0.filter_allow);
        list.push(Cow::Owned(filter_allow));
        self.0.filter_allow = Cow::Owned(list);
        self
    }

    /// Clear allowed module filters.
    /// If none are specified, nothing is filtered out
    pub fn clear_filter_allow(&mut self) -> &mut ConfigBuilder {
        self.0.filter_allow = Cow::Borrowed(&[]);
        self
    }

    /// Add denied module filters.
    /// If any are specified, records from modules starting with one of these entries will be ignored
    ///
    /// For example, `add_filter_ignore_str("tokio::uds")` would deny logging from the `tokio` crates `uds` module.
    pub fn add_filter_ignore_str(&mut self, filter_ignore: &'static str) -> &mut ConfigBuilder {
        let mut list = Vec::from(&*self.0.filter_ignore);
        list.push(Cow::Borrowed(filter_ignore));
        self.0.filter_ignore = Cow::Owned(list);
        self
    }

    /// Add denied module filters.
    /// If any are specified, records from modules starting with one of these entries will be ignored
    ///
    /// For example, `add_filter_ignore(format!("{}{}","tokio", "uds"))` would deny logging from the `tokio` crates `uds` module.
    pub fn add_filter_ignore(&mut self, filter_ignore: String) -> &mut ConfigBuilder {
        let mut list = Vec::from(&*self.0.filter_ignore);
        list.push(Cow::Owned(filter_ignore));
        self.0.filter_ignore = Cow::Owned(list);
        self
    }

    /// Clear ignore module filters.
    /// If none are specified, nothing is filtered
    pub fn clear_filter_ignore(&mut self) -> &mut ConfigBuilder {
        self.0.filter_ignore = Cow::Borrowed(&[]);
        self
    }

    /// Build new `Config`
    pub fn build(&mut self) -> Config {
        self.0.clone()
    }
}

impl Default for ConfigBuilder {
    fn default() -> Self {
        ConfigBuilder::new()
    }
}

impl Default for Config {
    fn default() -> Config {
        Config {
            time: LevelFilter::Error,
            level: LevelFilter::Error,
            level_padding: LevelPadding::Off,
            thread: LevelFilter::Debug,
            thread_log_mode: ThreadLogMode::IDs,
            thread_padding: ThreadPadding::Off,
            target: LevelFilter::Debug,
            location: LevelFilter::Trace,
            time_format: Cow::Borrowed("%H:%M:%S"),
            time_offset: FixedOffset::east(0),
            time_local: false,
            filter_allow: Cow::Borrowed(&[]),
            filter_ignore: Cow::Borrowed(&[]),

            #[cfg(feature = "termcolor")]
            level_color: [
                None,                // Default foreground
                Some(Color::Red),    // Error
                Some(Color::Yellow), // Warn
                Some(Color::Blue),   // Info
                Some(Color::Cyan),   // Debug
                Some(Color::White),  // Trace
            ],
        }
    }
}
<|endoftext|>


<commit_before>fn isqrt(n: u64) -> u64 {
    let mut (min, max) = (0u64, n);
    while min < max {
        let mid = (min + max + 1u64) / 2u64;
        if (mid * mid) == n {
            ret mid;
        } else if (mid * mid) >= n {
            max = mid - 1u64;
        } else {
            min = mid;
        }
    }
    ret min;
}

<commit_msg>Add euler::calc::each_fib()<commit_after>fn isqrt(n: u64) -> u64 {
    let mut (min, max) = (0u64, n);
    while min < max {
        let mid = (min + max + 1u64) / 2u64;
        if (mid * mid) == n {
            ret mid;
        } else if (mid * mid) >= n {
            max = mid - 1u64;
        } else {
            min = mid;
        }
    }
    ret min;
}

fn each_fib(f: fn(&&u64)->bool) {
    let mut (prev, cur) = (0u64, 1u64);
    loop {
        if !f(cur) { break; }
        let next = prev + cur;
        prev = cur;
        cur  = next;
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_each_fib() {
        let fib = [ 1u64, 1u64, 2u64, 3u64, 5u64, 8u64, 13u64, 21u64, 34u64, 55u64, 89u64, 144u64, 233u64 ];
        let mut calc = [];
        for each_fib {|f|
            if f > fib.last() { break; }
            calc += [ f ];
        };
        assert fib == calc;
    }
}
<|endoftext|>


<commit_before>use keyboard::Key;
use keymap::{ KeyMap, KeyMapState };
use buffer::{ Direction, Mark, WordEdgeMatch };
use textobject::{ TextObject, Reference, Kind, Anchor };
use overlay::OverlayType;

/// Instructions for the Editor.
/// These do NOT alter the text, but may change editor/view state
#[derive(Copy, Show)]
#[allow(dead_code)]
pub enum Instruction {
    SaveBuffer,
    //FindFile,
    ExitEditor,

    SetMark(Mark),
    SetOverlay(OverlayType),
    // SetMode(...)
}

/// Operations on the Buffer.
/// These DO alter the text, but otherwise may NOT change editor/view state
/// Note that these differ from log::Change in that they are higher-level
/// operations dependent on state (cursor/mark locations, etc.), as opposed
/// to concrete operations on absolute indexes (insert 'a' at index 158, etc.)
#[derive(Copy, Show)]
#[allow(dead_code)]
pub enum Operation {
    Insert,     // insert text
    Delete,     // delete some object

    Undo,       // rewind buffer transaction log
    Redo,       // replay buffer transaction log
}

/// Fragments that can be combined to specify a command
#[derive(Copy, Show)]
#[allow(dead_code)]
pub enum Partial {
    Kind(Kind),
    Anchor(Anchor),
    Reference(Reference),
    Object(TextObject),
    Action(Action),
}

#[derive(Copy, Show)]
#[allow(dead_code)]
pub enum Action {
    Operation(Operation),
    Instruction(Instruction),
}

/// A complete, actionable command
#[derive(Copy, Show)]
pub struct Command {
    pub number: i32,        // numeric paramter, line number, repeat count, etc.
    pub action: Action,     // what to do
    pub object: TextObject, // where to do it
}

pub struct Builder {
    number: Option<i32>,
    repeat: Option<uint>,

    action: Option<Action>,
    mark: Option<Mark>,
    kind: Option<Kind>,
    anchor: Option<Anchor>,
    reference: Option<Reference>,
    object: Option<TextObject>,

    reading_number: bool,
    keymap: KeyMap<Partial>,
}

#[derive(Copy, Show)]
pub enum BuilderEvent {
    Invalid,            // cannot find a valid interpretation
    Incomplete,         // needs more information
    Complete(Command),  // command is finished
}

impl Builder {
    pub fn new() -> Builder {
        Builder {
            number: None,
            repeat: None,
            action: None,
            mark: None,
            kind: None,
            anchor: None,
            reference: None,
            object: None,
            reading_number: false,
            keymap: default_keymap()
        }
    }

    pub fn reset(&mut self) {
        self.number = None;
        self.repeat = None;
        self.action = None;
        self.mark = None;
        self.kind = None;
        self.anchor = None;
        self.object = None;
        self.reference = None;
        self.reading_number = false;
    }

    pub fn check_key(&mut self, key: Key) -> BuilderEvent {
        if let Key::Char(c) = key {
            // '0' might be bound (start of line), and cannot be the start of a number sequence
            if c.is_digit(10) && (self.reading_number || c != '0') {
                let n = c.to_digit(10).unwrap();
                self.reading_number = true;
                self.append_digit(n);
                return BuilderEvent::Incomplete;
            } else if self.reading_number {

                self.reading_number = false;
            }
        }

        match self.keymap.check_key(key) {
            KeyMapState::Match(partial) => self.apply_partial(partial),
            KeyMapState::None           => { self.reset(); return BuilderEvent::Invalid; }
            _ => {},
        }

        if let Some(c) = self.complete_command() {
            self.reset();
            return BuilderEvent::Complete(c)
        } else {
            return BuilderEvent::Incomplete
        }
    }

    fn complete_object(&mut self) -> Option<TextObject> {
        if let Some(to) = self.object {
            // we have a whole object ready
            return Some(to)
        } else if let Some(reference) = self.reference {
            // we have a particular object in mind, use number as index/offset
            let reference = if let Some(n) = self.number {
                // set the reference index to n, or multiply offset by n
                // also, reset the 'outer' number, since index/offset is separate from repeat counter
                self.number = None;
                match reference {
                    Reference::Index(k, _) => Reference::Index(k, n as u32),
                    Reference::Offset(m, k, i) => Reference::Offset(m, k, i * n),
                    Reference::Mark(m, k) => Reference::Mark(m, k)
                }
            } else { reference };
            self.reference = Some(reference);

            return Some(TextObject { anchor: self.anchor.unwrap_or(Anchor::default()),
                                     reference: reference })
        } else if let Some(kind) = self.kind {
            // we have a particular kind...
            if let Some(mark) = self.mark {
                // and a specific mark, return the object of that kind, at that mark
                return Some(TextObject { anchor: self.anchor.unwrap_or(Anchor::default()),
                                         reference: Reference::Mark(mark, kind) })
            } else if let Some(n) = self.number {
                // and a particular number, return the nth of that kind
                return Some(TextObject { anchor: self.anchor.unwrap_or(Anchor::default()),
                                         reference: Reference::Index(kind, n as u32) })
            }
        }
        None
    }

    fn complete_command(&mut self) -> Option<Command> {
        /* rules for completing commands:
              | action            | number | object | reference    | kind |   | result                                                            |
              | -                 | -      | -      | -            | -    | - | -                                                                 |
              | no                | no     | no     | no           | yes  |   | move cursor to next (default) text object with kind               |
              | no                | no     | no     | yes          | -    |   | move cursor to text object with reference + default anchor        |
              | no                | no     | yes    | -            | -    |   | move cursor to text object                                        |
              | no                | yes    | no     | no           | no   |   | incomplete                                                        |
              | no                | yes    | no     | no           | yes  |   | move cursor to nth instance of kind (from start of buffer)        |
              | no                | yes    | no     | yes (index)  | -    |   | set index to number, cursor to ref + default anchor               |
              | no                | yes    | no     | yes (offset) | -    |   | multiply offset by number, cursor to ref + default anchor         |
              | no                | yes    | no     | yes (mark)   | -    |   | incomplete                                                        |
              | yes (instruction) | -      | -      | -            | -    |   | send instruction to editor with whatever parameters are available |
              | yes (operation)   | no     | no     | no           | no   |   | incomplete                                                        |
              | yes (operation)   | no     | no     | no           | yes  |   | apply operation to kind at cursor (default anchor)                |
              | yes (operation)   | no     | no     | yes          | -    |   | apply operation to reference with default anchor                  |
              | yes (operation)   | no     | yes    | -            | -    |   | apply operation to object                                         |
              | yes (operation)   | yes    | no     | no           | no   |   | incomplete                                                        |
              | yes (operation)   | yes    | no     | no           | yes  |   | apply operation to kind at cursor n times                         |
        */

        // editor instructions may not need a text object, go ahead and return immediately
        if let Some(Action::Instruction(i)) = self.action {
            return Some(Command {
                number: self.repeat.unwrap_or(0) as i32,
                action: Action::Instruction(i),
                object: self.complete_object().unwrap_or(TextObject {
                    anchor: Anchor::default(),
                    reference: Reference::default()
                })
            });
        }

        if let Some(to) = self.complete_object() {
            if let Some(Action::Operation(o)) = self.action {
                // we have an object, and an operation
                return Some(Command {
                    number: self.repeat.unwrap_or(0) as i32,
                    action: Action::Operation(o),
                    object: to
                });
            } else {
                // we have just an object, assume move cursor instruction
                return Some(Command {
                    number: self.repeat.unwrap_or(0) as i32,
                    action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
                    object: to
                });
            }
        }
        None
    }

    fn append_digit(&mut self, n: uint) {
        if let Some(current) = self.number {
            self.number = Some((current*10) + n as i32);
        } else {
            self.number = Some(n as i32);
        }
    }

    fn apply_partial(&mut self, partial: Partial) {
        match partial {
            Partial::Kind(k)      => self.kind = Some(k),
            Partial::Anchor(a)    => self.anchor = Some(a),
            Partial::Reference(r) => self.reference = Some(r),
            Partial::Object(o)    => self.object = Some(o),
            Partial::Action(a)    => {
                self.action = Some(a);
                if !self.reading_number && self.number.is_some() && self.repeat.is_none() {
                    self.repeat = Some(self.number.unwrap() as uint);
                    self.number = None;
                }
            }
        }
    }
}

fn default_keymap() -> KeyMap<Partial> {
    let mut keymap = KeyMap::new();

    // next/previous char
    keymap.bind_key(Key::Char('l'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Char,  1)));
    keymap.bind_key(Key::Char('h'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Char, -1)));

    // next/previous word
    keymap.bind_key(Key::Char('w'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Word(WordEdgeMatch::Alphabet),  1)));
    keymap.bind_key(Key::Char('b'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Word(WordEdgeMatch::Alphabet), -1)));
    keymap.bind_key(Key::Char('W'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Word(WordEdgeMatch::Whitespace),  1)));
    keymap.bind_key(Key::Char('B'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Word(WordEdgeMatch::Whitespace), -1)));

    // next/previous line
    keymap.bind_key(Key::Char('j'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Line,  1)));
    keymap.bind_key(Key::Char('k'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Line, -1)));

    // start/end of line
    keymap.bind_key(Key::Char('0'), Partial::Object(TextObject { anchor: Anchor::Before,
                                                                 reference: Reference::Mark(Mark::Cursor(0), Kind::Line) }));
    keymap.bind_key(Key::Char('$'), Partial::Object(TextObject { anchor: Anchor::After,
                                                                 reference: Reference::Mark(Mark::Cursor(0), Kind::Line) }));

    // kinds
    keymap.bind_keys(&[Key::Char('`'), Key::Char('c')], Partial::Kind(Kind::Char));
    keymap.bind_keys(&[Key::Char('`'), Key::Char('w')], Partial::Kind(Kind::Word(WordEdgeMatch::Alphabet)));
    keymap.bind_keys(&[Key::Char('`'), Key::Char('W')], Partial::Kind(Kind::Word(WordEdgeMatch::Whitespace)));
    keymap.bind_keys(&[Key::Char('`'), Key::Char('l')], Partial::Kind(Kind::Line));

    // anchors
    keymap.bind_key(Key::Char(','), Partial::Anchor(Anchor::Before));
    keymap.bind_key(Key::Char('.'), Partial::Anchor(Anchor::After));

    // actions
    keymap.bind_key(Key::Char('d'), Partial::Action(Action::Operation(Operation::Delete)));
    keymap.bind_key(Key::Char('g'), Partial::Action(Action::Instruction(Instruction::SetMark(Mark::Cursor(0)))));

    keymap.bind_key(Key::Char(':'), Partial::Action(Action::Instruction(Instruction::SetOverlay(OverlayType::Prompt))));

    keymap
}
<commit_msg>Fix comment and behavior for operations on raw kinds<commit_after>use keyboard::Key;
use keymap::{ KeyMap, KeyMapState };
use buffer::{ Direction, Mark, WordEdgeMatch };
use textobject::{ TextObject, Reference, Kind, Anchor };
use overlay::OverlayType;

/// Instructions for the Editor.
/// These do NOT alter the text, but may change editor/view state
#[derive(Copy, Show)]
#[allow(dead_code)]
pub enum Instruction {
    SaveBuffer,
    //FindFile,
    ExitEditor,

    SetMark(Mark),
    SetOverlay(OverlayType),
    // SetMode(...)
}

/// Operations on the Buffer.
/// These DO alter the text, but otherwise may NOT change editor/view state
/// Note that these differ from log::Change in that they are higher-level
/// operations dependent on state (cursor/mark locations, etc.), as opposed
/// to concrete operations on absolute indexes (insert 'a' at index 158, etc.)
#[derive(Copy, Show)]
#[allow(dead_code)]
pub enum Operation {
    Insert,     // insert text
    Delete,     // delete some object

    Undo,       // rewind buffer transaction log
    Redo,       // replay buffer transaction log
}

/// Fragments that can be combined to specify a command
#[derive(Copy, Show)]
#[allow(dead_code)]
pub enum Partial {
    Kind(Kind),
    Anchor(Anchor),
    Reference(Reference),
    Object(TextObject),
    Action(Action),
}

#[derive(Copy, Show)]
#[allow(dead_code)]
pub enum Action {
    Operation(Operation),
    Instruction(Instruction),
}

/// A complete, actionable command
#[derive(Copy, Show)]
pub struct Command {
    pub number: i32,        // numeric paramter, line number, repeat count, etc.
    pub action: Action,     // what to do
    pub object: TextObject, // where to do it
}

pub struct Builder {
    number: Option<i32>,
    repeat: Option<uint>,

    action: Option<Action>,
    mark: Option<Mark>,
    kind: Option<Kind>,
    anchor: Option<Anchor>,
    reference: Option<Reference>,
    object: Option<TextObject>,

    reading_number: bool,
    keymap: KeyMap<Partial>,
}

#[derive(Copy, Show)]
pub enum BuilderEvent {
    Invalid,            // cannot find a valid interpretation
    Incomplete,         // needs more information
    Complete(Command),  // command is finished
}

impl Builder {
    pub fn new() -> Builder {
        Builder {
            number: None,
            repeat: None,
            action: None,
            mark: None,
            kind: None,
            anchor: None,
            reference: None,
            object: None,
            reading_number: false,
            keymap: default_keymap()
        }
    }

    pub fn reset(&mut self) {
        self.number = None;
        self.repeat = None;
        self.action = None;
        self.mark = None;
        self.kind = None;
        self.anchor = None;
        self.object = None;
        self.reference = None;
        self.reading_number = false;
    }

    pub fn check_key(&mut self, key: Key) -> BuilderEvent {
        if let Key::Char(c) = key {
            // '0' might be bound (start of line), and cannot be the start of a number sequence
            if c.is_digit(10) && (self.reading_number || c != '0') {
                let n = c.to_digit(10).unwrap();
                self.reading_number = true;
                self.append_digit(n);
                return BuilderEvent::Incomplete;
            } else if self.reading_number {

                self.reading_number = false;
            }
        }

        match self.keymap.check_key(key) {
            KeyMapState::Match(partial) => self.apply_partial(partial),
            KeyMapState::None           => { self.reset(); return BuilderEvent::Invalid; }
            _ => {},
        }

        if let Some(c) = self.complete_command() {
            self.reset();
            return BuilderEvent::Complete(c)
        } else {
            return BuilderEvent::Incomplete
        }
    }

    fn complete_object(&mut self) -> Option<TextObject> {
        if let Some(to) = self.object {
            // we have a whole object ready
            return Some(to)
        } else if let Some(reference) = self.reference {
            // we have a particular object in mind, use number as index/offset
            let reference = if let Some(n) = self.number {
                // set the reference index to n, or multiply offset by n
                // also, reset the 'outer' number, since index/offset is separate from repeat counter
                self.number = None;
                match reference {
                    Reference::Index(k, _) => Reference::Index(k, n as u32),
                    Reference::Offset(m, k, i) => Reference::Offset(m, k, i * n),
                    Reference::Mark(m, k) => Reference::Mark(m, k)
                }
            } else { reference };
            self.reference = Some(reference);

            return Some(TextObject { anchor: self.anchor.unwrap_or(Anchor::default()),
                                     reference: reference })
        } else if let Some(kind) = self.kind {
            // we have a particular kind...
            if let Some(mark) = self.mark {
                // and a specific mark, return the object of that kind, at that mark
                return Some(TextObject { anchor: self.anchor.unwrap_or(Anchor::default()),
                                         reference: Reference::Mark(mark, kind) })
            } else if let Some(n) = self.number {
                // and a particular number, return the nth of that kind
                return Some(TextObject { anchor: self.anchor.unwrap_or(Anchor::default()),
                                         reference: Reference::Index(kind, n as u32) })
            } else {
                // just the kind, nothing else, find next instance from cursor
                return Some(TextObject { anchor: self.anchor.unwrap_or(Anchor::default()),
                                         reference: Reference::Offset(Mark::Cursor(0), kind, 1) })
            }
        }
        None
    }

    fn complete_command(&mut self) -> Option<Command> {
        /* rules for completing commands:
              | action            | number | object | reference    | kind |   | result                                                            |
              | -                 | -      | -      | -            | -    | - | -                                                                 |
              | no                | no     | no     | no           | yes  |   | move cursor to next (default) text object with kind               |
              | no                | no     | no     | yes          | -    |   | move cursor to text object with reference + default anchor        |
              | no                | no     | yes    | -            | -    |   | move cursor to text object                                        |
              | no                | yes    | no     | no           | no   |   | incomplete                                                        |
              | no                | yes    | no     | no           | yes  |   | move cursor to nth instance of kind (from start of buffer)        |
              | no                | yes    | no     | yes (index)  | -    |   | set index to number, cursor to ref + default anchor               |
              | no                | yes    | no     | yes (offset) | -    |   | multiply offset by number, cursor to ref + default anchor         |
              | no                | yes    | no     | yes (mark)   | -    |   | incomplete                                                        |
              | yes (instruction) | -      | -      | -            | -    |   | send instruction to editor with whatever parameters are available |
              | yes (operation)   | no     | no     | no           | no   |   | incomplete                                                        |
              | yes (operation)   | no     | no     | no           | yes  |   | apply operation to kind at cursor (default anchor)                |
              | yes (operation)   | no     | no     | yes          | -    |   | apply operation to reference with default anchor                  |
              | yes (operation)   | no     | yes    | -            | -    |   | apply operation to object                                         |
              | yes (operation)   | yes    | no     | no           | no   |   | incomplete                                                        |
              | yes (operation)   | yes    | no     | no           | yes  |   | apply operation to nth instance of kind                           |
        */

        // editor instructions may not need a text object, go ahead and return immediately
        if let Some(Action::Instruction(i)) = self.action {
            return Some(Command {
                number: self.repeat.unwrap_or(0) as i32,
                action: Action::Instruction(i),
                object: self.complete_object().unwrap_or(TextObject {
                    anchor: Anchor::default(),
                    reference: Reference::default()
                })
            });
        }

        if let Some(to) = self.complete_object() {
            if let Some(Action::Operation(o)) = self.action {
                // we have an object, and an operation
                return Some(Command {
                    number: self.repeat.unwrap_or(0) as i32,
                    action: Action::Operation(o),
                    object: to
                });
            } else {
                // we have just an object, assume move cursor instruction
                return Some(Command {
                    number: self.repeat.unwrap_or(0) as i32,
                    action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
                    object: to
                });
            }
        }
        None
    }

    fn append_digit(&mut self, n: uint) {
        if let Some(current) = self.number {
            self.number = Some((current*10) + n as i32);
        } else {
            self.number = Some(n as i32);
        }
    }

    fn apply_partial(&mut self, partial: Partial) {
        match partial {
            Partial::Kind(k)      => self.kind = Some(k),
            Partial::Anchor(a)    => self.anchor = Some(a),
            Partial::Reference(r) => self.reference = Some(r),
            Partial::Object(o)    => self.object = Some(o),
            Partial::Action(a)    => {
                self.action = Some(a);
                if !self.reading_number && self.number.is_some() && self.repeat.is_none() {
                    self.repeat = Some(self.number.unwrap() as uint);
                    self.number = None;
                }
            }
        }
    }
}

fn default_keymap() -> KeyMap<Partial> {
    let mut keymap = KeyMap::new();

    // next/previous char
    keymap.bind_key(Key::Char('l'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Char,  1)));
    keymap.bind_key(Key::Char('h'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Char, -1)));

    // next/previous word
    keymap.bind_key(Key::Char('w'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Word(WordEdgeMatch::Alphabet),  1)));
    keymap.bind_key(Key::Char('b'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Word(WordEdgeMatch::Alphabet), -1)));
    keymap.bind_key(Key::Char('W'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Word(WordEdgeMatch::Whitespace),  1)));
    keymap.bind_key(Key::Char('B'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Word(WordEdgeMatch::Whitespace), -1)));

    // next/previous line
    keymap.bind_key(Key::Char('j'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Line,  1)));
    keymap.bind_key(Key::Char('k'), Partial::Reference(Reference::Offset(Mark::Cursor(0), Kind::Line, -1)));

    // start/end of line
    keymap.bind_key(Key::Char('0'), Partial::Object(TextObject { anchor: Anchor::Before,
                                                                 reference: Reference::Mark(Mark::Cursor(0), Kind::Line) }));
    keymap.bind_key(Key::Char('$'), Partial::Object(TextObject { anchor: Anchor::After,
                                                                 reference: Reference::Mark(Mark::Cursor(0), Kind::Line) }));

    // kinds
    keymap.bind_keys(&[Key::Char('`'), Key::Char('c')], Partial::Kind(Kind::Char));
    keymap.bind_keys(&[Key::Char('`'), Key::Char('w')], Partial::Kind(Kind::Word(WordEdgeMatch::Alphabet)));
    keymap.bind_keys(&[Key::Char('`'), Key::Char('W')], Partial::Kind(Kind::Word(WordEdgeMatch::Whitespace)));
    keymap.bind_keys(&[Key::Char('`'), Key::Char('l')], Partial::Kind(Kind::Line));

    // anchors
    keymap.bind_key(Key::Char(','), Partial::Anchor(Anchor::Before));
    keymap.bind_key(Key::Char('.'), Partial::Anchor(Anchor::After));

    // actions
    keymap.bind_key(Key::Char('d'), Partial::Action(Action::Operation(Operation::Delete)));
    keymap.bind_key(Key::Char('g'), Partial::Action(Action::Instruction(Instruction::SetMark(Mark::Cursor(0)))));

    keymap.bind_key(Key::Char(':'), Partial::Action(Action::Instruction(Instruction::SetOverlay(OverlayType::Prompt))));

    keymap
}
<|endoftext|>


<commit_before>use std::str::FromStr;

#[derive(Debug)]
pub enum Command {
    Nick,
    User,
    Join,
    Quit,
    Ping,
    Mode,
    Pong,
    Pass,
    Privmsg,
    Numeric(u32),
    Unknown(String)
}

impl Command {
    pub fn as_string(&self) -> String {
        match self {
            &Command::Nick => "NICK".to_string(),
            &Command::Join => "JOIN".to_string(),
            &Command::Pong => "PONG".to_string(),
            &Command::Privmsg => "PRIVMSG".to_string(),
            &Command::User => "USER".to_string(),
            &Command::Quit => "QUIT".to_string(),
            &Command::Ping => "PING".to_string(),
            &Command::Mode => "MODE".to_string(),
            &Command::Pass => "PASS".to_string(),
            &Command::Numeric(n)=> format!("{:0>3}", n),
            &Command::Unknown(ref s) => s.clone()
        }
    }
}

impl Message {
    pub fn to_string(&self) -> String {
        let mut ret = String::new();
        match self.prefix {
            Some(ref pfx) => {
                ret.push(':');
                ret.push_str(pfx.trim());
                ret.push(' ');
            },
            None => ()
        };
        ret.push_str(self.command.as_string().trim());
        for ref arg in self.args.iter() {
            ret.push(' ');
            ret.push_str(arg.trim());
        }

        return ret;
    }
}

impl From<Command> for Message {
    fn from(c: Command) -> Message {
        Message {
            prefix: None,
            command: c,
            args: vec![],
            suffix: None
        }
    }
}

impl FromStr for Command {
    type Err = Command;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "NICK" => Ok(Command::Nick),
            "USER" => Ok(Command::User),
            "JOIN" => Ok(Command::Join),
            "QUIT" => Ok(Command::Quit),
            "PING" => Ok(Command::Ping),
            "MODE" => Ok(Command::Mode),
            "PASS" => Ok(Command::Pass),
            _ => Ok(Command::Unknown(s.to_string()))
        }
    }
}

#[derive(Debug)]
pub struct Message {
    pub prefix: Option<String>,
    pub command: Command,
    pub args: Vec<String>,
    pub suffix: Option<String>
}
<commit_msg>irc: protocol: command: parse PRIVMSG into command<commit_after>use std::str::FromStr;

#[derive(Debug)]
pub enum Command {
    Nick,
    User,
    Join,
    Quit,
    Ping,
    Mode,
    Pong,
    Pass,
    Privmsg,
    Numeric(u32),
    Unknown(String)
}

impl Command {
    pub fn as_string(&self) -> String {
        match self {
            &Command::Nick => "NICK".to_string(),
            &Command::Join => "JOIN".to_string(),
            &Command::Pong => "PONG".to_string(),
            &Command::Privmsg => "PRIVMSG".to_string(),
            &Command::User => "USER".to_string(),
            &Command::Quit => "QUIT".to_string(),
            &Command::Ping => "PING".to_string(),
            &Command::Mode => "MODE".to_string(),
            &Command::Pass => "PASS".to_string(),
            &Command::Numeric(n)=> format!("{:0>3}", n),
            &Command::Unknown(ref s) => s.clone()
        }
    }
}

impl Message {
    pub fn to_string(&self) -> String {
        let mut ret = String::new();
        match self.prefix {
            Some(ref pfx) => {
                ret.push(':');
                ret.push_str(pfx.trim());
                ret.push(' ');
            },
            None => ()
        };
        ret.push_str(self.command.as_string().trim());
        for ref arg in self.args.iter() {
            ret.push(' ');
            ret.push_str(arg.trim());
        }

        return ret;
    }
}

impl From<Command> for Message {
    fn from(c: Command) -> Message {
        Message {
            prefix: None,
            command: c,
            args: vec![],
            suffix: None
        }
    }
}

impl FromStr for Command {
    type Err = Command;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "NICK" => Ok(Command::Nick),
            "USER" => Ok(Command::User),
            "JOIN" => Ok(Command::Join),
            "QUIT" => Ok(Command::Quit),
            "PING" => Ok(Command::Ping),
            "MODE" => Ok(Command::Mode),
            "PASS" => Ok(Command::Pass),
            "PRIVMSG" => Ok(Command::Privmsg),
            _ => Ok(Command::Unknown(s.to_string()))
        }
    }
}

#[derive(Debug)]
pub struct Message {
    pub prefix: Option<String>,
    pub command: Command,
    pub args: Vec<String>,
    pub suffix: Option<String>
}
<|endoftext|>


<commit_before>use std::thread;

/// Parallelizes an `operation` over a mutable slice
///
/// The `data` will be divided in chunks of `granularity` size. If `granularity` is None,
/// then the chunk sise will depend on the number of processors available to rust.
///  A new thread will be spawned to "operate" over each chunk.
///
/// `operation` will receive two arguments:
///
/// - The mutable chunk of data, and
/// - The offset of this chunk from the start of `data`
///
/// # Panics
///
/// Panics if any of the underlying threads panics
///
/// # Example
///
/// Parallel map
///
/// ```
/// extern crate parallel;
/// extern crate rand;
///
/// use rand::{Rng, XorShiftRng};
/// use std::num::Float;
///
/// # fn main() {
/// let ref mut rng: XorShiftRng = rand::thread_rng().gen();
/// let mut v = (0..1_000).map(|_| rng.gen::<f32>()).collect::<Vec<_>>();
/// # let w = v.iter().map(|x| x.sin()).collect::<Vec<_>>();
/// parallel::divide(v.as_mut_slice(), 100, |data, _| {
///     for x in data.iter_mut() {
///         *x = x.sin();
///     }
/// });
/// # assert_eq!(v, w);
/// # }
/// ```
pub fn divide<T, F>(data: &mut [T], granularity: usize, operation: F) where
    T: Send,
    F: Fn(&mut [T], usize) + Sync,
{
    assert!(granularity > 0);

    let operation = &operation;
    let guards: Vec<_> = data.chunks_mut(granularity).zip(0..).map(|(chunk, i)| {
        thread::scoped(move || {
            (*operation)(chunk, i * granularity)
        })
    }).collect();

    for guard in guards {
        guard.join();
    }
}

#[cfg(test)]
mod test {
    use quickcheck::TestResult;
    use rand::{Rng, XorShiftRng, self};
    use std::iter;

    #[quickcheck]
    fn clone(size: usize, granularity: usize) -> TestResult {
        if granularity == 0 {
            return TestResult::discard();
        }

        let mut rng: XorShiftRng = rand::thread_rng().gen();
        let original = (0..size).map(|_| rng.gen::<f64>()).collect::<Vec<_>>();
        let mut clone = iter::repeat(0f64).take(size).collect::<Vec<_>>();

        let original_slice = &*original;
        super::divide(&mut *clone, granularity, |data, offset| {
            for (i, x) in data.iter_mut().enumerate() {
                *x = original_slice[offset + i]
            }
        });

        TestResult::from_bool(original == clone)
    }

    #[quickcheck]
    fn new(size: usize, granularity: usize) -> TestResult {
        if granularity == 0 {
            return TestResult::discard();
        }

        let mut v = iter::repeat(None::<f64>).take(size).collect::<Vec<_>>();

        super::divide(&mut *v, granularity, |data, _| {
            let mut rng: XorShiftRng = rand::thread_rng().gen();

            for x in data.iter_mut() {
                *x = Some(rng.gen())
            }
        });

        TestResult::from_bool(v.iter().all(|&x| match x {
            None => false,
            Some(x) => x > 0. && x < 1.
        }))
    }
}
<commit_msg>reverted change in documentation<commit_after>use std::thread;

/// Parallelizes an `operation` over a mutable slice
///
/// The `data` will be divided in chunks of `granularity` size.
///  A new thread will be spawned to "operate" over each chunk.
///
/// `operation` will receive two arguments:
///
/// - The mutable chunk of data, and
/// - The offset of this chunk from the start of `data`
///
/// # Panics
///
/// Panics if any of the underlying threads panics
///
/// # Example
///
/// Parallel map
///
/// ```
/// extern crate parallel;
/// extern crate rand;
///
/// use rand::{Rng, XorShiftRng};
/// use std::num::Float;
///
/// # fn main() {
/// let ref mut rng: XorShiftRng = rand::thread_rng().gen();
/// let mut v = (0..1_000).map(|_| rng.gen::<f32>()).collect::<Vec<_>>();
/// # let w = v.iter().map(|x| x.sin()).collect::<Vec<_>>();
/// parallel::divide(v.as_mut_slice(), 100, |data, _| {
///     for x in data.iter_mut() {
///         *x = x.sin();
///     }
/// });
/// # assert_eq!(v, w);
/// # }
/// ```
pub fn divide<T, F>(data: &mut [T], granularity: usize, operation: F) where
    T: Send,
    F: Fn(&mut [T], usize) + Sync,
{
    assert!(granularity > 0);

    let operation = &operation;
    let guards: Vec<_> = data.chunks_mut(granularity).zip(0..).map(|(chunk, i)| {
        thread::scoped(move || {
            (*operation)(chunk, i * granularity)
        })
    }).collect();

    for guard in guards {
        guard.join();
    }
}

#[cfg(test)]
mod test {
    use quickcheck::TestResult;
    use rand::{Rng, XorShiftRng, self};
    use std::iter;

    #[quickcheck]
    fn clone(size: usize, granularity: usize) -> TestResult {
        if granularity == 0 {
            return TestResult::discard();
        }

        let mut rng: XorShiftRng = rand::thread_rng().gen();
        let original = (0..size).map(|_| rng.gen::<f64>()).collect::<Vec<_>>();
        let mut clone = iter::repeat(0f64).take(size).collect::<Vec<_>>();

        let original_slice = &*original;
        super::divide(&mut *clone, granularity, |data, offset| {
            for (i, x) in data.iter_mut().enumerate() {
                *x = original_slice[offset + i]
            }
        });

        TestResult::from_bool(original == clone)
    }

    #[quickcheck]
    fn new(size: usize, granularity: usize) -> TestResult {
        if granularity == 0 {
            return TestResult::discard();
        }

        let mut v = iter::repeat(None::<f64>).take(size).collect::<Vec<_>>();

        super::divide(&mut *v, granularity, |data, _| {
            let mut rng: XorShiftRng = rand::thread_rng().gen();

            for x in data.iter_mut() {
                *x = Some(rng.gen())
            }
        });

        TestResult::from_bool(v.iter().all(|&x| match x {
            None => false,
            Some(x) => x > 0. && x < 1.
        }))
    }
}
<|endoftext|>