Add support for XEP-0092: Software Version

[?]
Apr 21, 2019, 3:19 PM
YEMBT7TB3QXWE2HZOWEBYCXBUZQIWQZI5KKNMLB77CMAXVNBQSFAC

Dependencies

  • [2] DCMDASHV Mention XEP-0050 and XEP-0203 support
  • [3] LNUU5R56 Support disco#info from XEP-0030 Service Discovery
  • [4] 6UKCVM6E Use new iq processng for initial roster
  • [5] DYRPAV6T Update dependencies
  • [6] AEH7WP42 Make element processors static
  • [7] RRLRZTMR Use element processor for iq
  • [8] 2THKW66M Ignore .orig files
  • [9] X6L47BHQ Use different structure for established xmpp connection
  • [10] OFLAP2G2 Fix possible utf8 errors
  • [11] JY4F7VBC Use element processor for incoming iq set
  • [12] Z3NQEYVI Rename IqSetHandler to IqResuestHandler as it should provide both get and set handling
  • [13] 4IPZTMFI Update dependencies
  • [14] QDHDTOLM Starting support for commands XEP-0050: Ad-Hoc Commands (there no support in xmpp_parsers still)
  • [15] PLWPCM47 Add id to initital presence
  • [16] CCLGGFKR Move out XmppConnection into own file
  • [17] BYJPYYSM Process iq ping response
  • [18] LL3D5CXK Staring using element processor
  • [19] ZFBPXPAD Cleanup timeouted iq requests with ping Output elapsed time. Refactor iq handling.
  • [20] FV6BJ5K6 Send self-presence and store account info in Rc so it willbe used in some future in parallel
  • [21] PJV5HPIF Starting to imlements timeouts for iqs
  • [22] WDCZNZOP Fix rustdoc
  • [23] VS6AHRWI Move XMPP to separate dir
  • [24] HDLI2X4H Ignore delayed XEP-0203 messages
  • [25] GVZ4JAR5 Process self-presence with incoming stanza processor
  • [26] YTN366WA Support disco#items
  • [27] LQXBWNFT Remove unneeded requirement
  • [28] ZT3YEIVX Consume connection on processing command
  • [29] OB3HA2MD Use Client::new_with_jid to parse jid only once
  • [30] 5A5UVGNM Move receiver closing logic out of xmpp processing
  • [31] GXQCDLYQ Use element processor for incoming iq get
  • [32] FVVPKFTL Initial commit
  • [33] S754Y5DF Refactor IQ processing Always answer to set and get requests. Use XML encoding for stanzas.
  • [34] RQZCVDFD Implement applying timeout for expired iq await
  • [*] HKSQO7JZ Enable hyper http server and configuration

Change contents

  • replacement in src/xmpp/xmpp_connection.rs at line 0
    [3.21][2.0:38761]()
    use tokio_xmpp::{Client, Event, Packet};
    use tokio::prelude::future::{self, Either};
    use tokio::prelude::stream;
    use tokio::prelude::{Future, Stream};
    use std::collections::{HashMap, VecDeque};
    use std::time::{Duration, Instant};
    use super::stanzas;
    use super::element_processor;
    use crate::config;
    #[derive(Debug)]
    pub enum XmppCommand {
    /// Send message to someone by jid
    Chat {
    xmpp_to: xmpp_parsers::Jid,
    message: String,
    },
    /// Send message to MUC
    Chatroom { muc_id: String, message: String },
    /// Send ping request to the server to test connection
    Ping,
    /// Check iq requests if some have expired timeouts
    TimeoutCleanup,
    }
    /// trait of processing iq
    /// each function consumes handlers and
    /// returns false if connection should be reset
    trait IqHandler {
    /// process result
    fn result(
    self: Box<Self>,
    conn: &mut XmppConnection,
    opt_element: Option<xmpp_parsers::Element>,
    ) -> bool;
    /// process error
    fn error(
    self: Box<Self>,
    conn: &mut XmppConnection,
    error: xmpp_parsers::stanza_error::StanzaError,
    ) -> bool;
    /// process tmeout
    fn timeout(self: Box<Self>, conn: &mut XmppConnection) -> bool;
    }
    struct AddRosterIqHandler {
    jid: xmpp_parsers::Jid,
    }
    impl IqHandler for AddRosterIqHandler {
    fn result(
    self: Box<Self>,
    conn: &mut XmppConnection,
    opt_element: Option<xmpp_parsers::Element>,
    ) -> bool {
    match opt_element {
    Some(element) => {
    warn!(
    "Wrong payload when adding {} to roster: {}",
    self.jid,
    String::from(&element)
    );
    }
    None => {
    if conn.state.data.roster.contains_key(&self.jid) {
    info!("Jid {} updated to roster", self.jid);
    } else {
    info!("Jid {} added in roster", self.jid);
    conn.state.data.roster.insert(
    self.jid.clone(),
    (
    xmpp_parsers::roster::Subscription::None,
    xmpp_parsers::roster::Ask::None,
    ),
    );
    }
    conn.process_jid(&self.jid);
    }
    }
    true
    }
    fn error(
    self: Box<Self>,
    _conn: &mut XmppConnection,
    _error: xmpp_parsers::stanza_error::StanzaError,
    ) -> bool {
    true
    }
    fn timeout(self: Box<Self>, _conn: &mut XmppConnection) -> bool {
    true // ignore
    }
    }
    struct PingIqHandler {}
    impl IqHandler for PingIqHandler {
    fn result(
    self: Box<Self>,
    _conn: &mut XmppConnection,
    _opt_element: Option<xmpp_parsers::Element>,
    ) -> bool {
    info!("ping successed");
    true
    }
    fn error(
    self: Box<Self>,
    _conn: &mut XmppConnection,
    _error: xmpp_parsers::stanza_error::StanzaError,
    ) -> bool {
    false
    }
    fn timeout(self: Box<Self>, _conn: &mut XmppConnection) -> bool {
    false
    }
    }
    struct InitRosterIqHandler {}
    impl IqHandler for InitRosterIqHandler {
    fn result(
    self: Box<Self>,
    conn: &mut XmppConnection,
    opt_element: Option<xmpp_parsers::Element>,
    ) -> bool {
    if let Some(result) = opt_element {
    use std::convert::TryInto;
    match result.try_into() as Result<xmpp_parsers::roster::Roster, _> {
    Ok(roster) => {
    conn.state.data.roster_init = true;
    conn.state.data.roster.clear();
    info!("Got first roster:");
    for i in roster.items {
    info!(" >>> {:?}", i);
    conn.state
    .data
    .roster
    .insert(i.jid, (i.subscription, i.ask));
    }
    true
    }
    Err(e) => {
    error!("Cann't parse roster: {}", e);
    false
    }
    }
    } else {
    error!("No roster responded");
    false
    }
    }
    fn error(
    self: Box<Self>,
    _conn: &mut XmppConnection,
    _error: xmpp_parsers::stanza_error::StanzaError,
    ) -> bool {
    false
    }
    fn timeout(self: Box<Self>, _conn: &mut XmppConnection) -> bool {
    false
    }
    }
    #[derive(Default)]
    struct XmppData {
    /// known roster data
    roster: HashMap<
    xmpp_parsers::Jid,
    (
    xmpp_parsers::roster::Subscription,
    xmpp_parsers::roster::Ask,
    ),
    >,
    /// if roster was initialized
    /// ToDo: remove it as it is used only for initialization
    roster_init: bool,
    /// if self-presence accepted
    /// ToDo: remove it as it is used only for initialization
    self_presence: bool,
    /// ids counter
    counter: usize,
    /// stanzas to send
    send_queue: VecDeque<minidom::Element>,
    /// outgoing mailbox
    outgoing_mailbox: HashMap<xmpp_parsers::Jid, Vec<String>>,
    /// muc id to muc jid
    mucs: HashMap<String, xmpp_parsers::Jid>,
    /// map from iq's id to handler of this type of iqs
    pending_ids: HashMap<String, (Instant, Box<dyn IqHandler>)>,
    }
    struct XmppState {
    client: Client,
    data: XmppData,
    }
    pub struct XmppConnection {
    account: std::rc::Rc<config::Account>,
    state: XmppState,
    }
    trait IqRequestHandler {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq;
    }
    struct IqRequestUnknown {
    element: xmpp_parsers::Element,
    type_: &'static str,
    }
    impl IqRequestHandler for IqRequestUnknown {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    warn!(
    "Unsupported IQ {} request from {:?}: {}",
    self.type_,
    from,
    String::from(&self.element)
    );
    stanzas::make_iq_unsupported_error(id, conn.state.client.jid.clone(), from)
    }
    }
    struct IqSetRoster {}
    impl IqRequestHandler for IqSetRoster {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    info!("Got roster push {} from {:?}", id, from);
    stanzas::make_roster_push_answer(id, conn.state.client.jid.clone(), from)
    }
    }
    struct IqGetPing {}
    impl IqRequestHandler for IqGetPing {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    info!("Got ping {} from {:?}", id, from);
    stanzas::make_pong(id, conn.state.client.jid.clone(), from)
    }
    }
    struct IqGetDiscoInfo {}
    impl IqRequestHandler for IqGetDiscoInfo {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    info!("Got disco query {} from {:?}", id, from);
    stanzas::make_disco_info_result(id, conn.state.client.jid.clone(), from)
    }
    }
    struct IqGetDiscoItems {}
    impl IqRequestHandler for IqGetDiscoItems {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    info!("Got disco items query {} from {:?}", id, from);
    stanzas::make_disco_items_result(id, conn.state.client.jid.clone(), from)
    }
    }
    struct IqGetDiscoCommands {}
    impl IqRequestHandler for IqGetDiscoCommands {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    info!("Got disco commands query {} from {:?}", id, from);
    stanzas::make_disco_items_commands(id, conn.state.client.jid.clone(), from)
    }
    }
    lazy_static! {
    static ref INCOMING: element_processor::Processor<XmppConnection, bool, xmpp_parsers::Element> = {
    let mut incoming = element_processor::Processor::new(&|_, e| {
    warn!("Unknown stanza {}", String::from(&e));
    true
    });
    incoming.register(&XmppConnection::incoming_iq_processing);
    incoming.register(&XmppConnection::incoming_presence_processing);
    incoming.register(&XmppConnection::incoming_message_processing);
    incoming
    };
    static ref INCOMING_IQ_SET: element_processor::Processor<XmppConnection, Box<dyn IqRequestHandler>, xmpp_parsers::Element> = {
    let mut iq_set =
    element_processor::Processor::new(&|_conn: &mut XmppConnection, element| {
    Box::new(IqRequestUnknown {
    element,
    type_: "set",
    }) as Box<dyn IqRequestHandler>
    });
    iq_set.register(&XmppConnection::incoming_iq_processing_set_roster);
    iq_set
    };
    static ref INCOMING_IQ_GET: element_processor::Processor<XmppConnection, Box<dyn IqRequestHandler>, xmpp_parsers::Element> = {
    let mut iq_get =
    element_processor::Processor::new(&|_conn: &mut XmppConnection, element| {
    Box::new(IqRequestUnknown {
    element,
    type_: "get",
    }) as Box<dyn IqRequestHandler>
    });
    iq_get.register(&XmppConnection::incoming_iq_processing_get_ping);
    iq_get.register(&XmppConnection::incoming_iq_processing_get_disco_info);
    iq_get.register(&XmppConnection::incoming_iq_processing_get_disco_items);
    iq_get
    };
    }
    pub struct MaybeXmppConnection {
    account: std::rc::Rc<config::Account>,
    state: Option<XmppState>,
    }
    impl From<XmppConnection> for MaybeXmppConnection {
    fn from(from: XmppConnection) -> MaybeXmppConnection {
    MaybeXmppConnection {
    account: from.account,
    state: Some(from.state),
    }
    }
    }
    impl From<config::Account> for MaybeXmppConnection {
    fn from(from: config::Account) -> MaybeXmppConnection {
    MaybeXmppConnection {
    account: std::rc::Rc::new(from),
    state: None,
    }
    }
    }
    impl From<std::rc::Rc<config::Account>> for MaybeXmppConnection {
    fn from(from: std::rc::Rc<config::Account>) -> MaybeXmppConnection {
    MaybeXmppConnection {
    account: from,
    state: None,
    }
    }
    }
    impl MaybeXmppConnection {
    /// connects if nothing connected
    /// don't connect only if stop_future resolved
    pub fn connect<F>(
    self,
    stop_future: F,
    ) -> impl Future<Item = XmppConnection, Error = failure::Error>
    where
    F: future::Future + Clone + 'static,
    <F as hyper::rt::Future>::Error: Into<failure::Error> + Send,
    {
    info!("xmpp connection...");
    let MaybeXmppConnection { account, state } = self;
    if let Some(state) = state {
    Box::new(future::ok(XmppConnection { account, state }))
    as Box<dyn Future<Item = _, Error = _>>
    } else {
    Box::new(
    stop_future
    .clone()
    .select2(
    future::loop_fn(account, move |account| {
    info!("xmpp initialization...");
    let client =
    Client::new_with_jid(account.jid.clone(), &account.password);
    info!("xmpp initialized");
    let stop_future2 = stop_future.clone();
    let stop_future3 = stop_future.clone();
    let stop_future4 = stop_future.clone();
    // future to wait for online
    Box::new(
    XmppConnection {
    state: XmppState {
    client,
    data: std::default::Default::default(),
    },
    account,
    }
    .processing(XmppConnection::online, stop_future.clone())
    .map_err(|(acc, _)| acc)
    .and_then(|(conn, r)| match r {
    Ok(Either::A(_)) => future::ok(conn),
    Ok(Either::B(_)) => future::err(conn.account),
    Err(_e) => future::err(conn.account),
    })
    .and_then(|conn| conn.initial_roster(stop_future2))
    .and_then(|conn| conn.self_presence(stop_future3))
    .and_then(|conn| conn.enter_mucs(stop_future4))
    .then(|r| match r {
    Ok(conn) => future::ok(future::Loop::Break(conn)),
    Err(acc) => future::ok(future::Loop::Continue(acc)),
    }),
    )
    })
    .map_err(|_: ()| ()),
    )
    .then(|r| match r {
    Ok(Either::A((_x, _b))) => future::err(format_err!("Stop XMMP connection")),
    Ok(Either::B((x, _a))) => future::ok(x),
    Err(Either::A((e, _b))) => future::err(e.into()),
    Err(Either::B((_, _a))) => {
    future::err(format_err!("Cann't initiate XMPP connection"))
    }
    }),
    )
    }
    }
    }
    impl XmppConnection {
    /// base XMPP processing
    /// Returns false on error to disconnect
    fn xmpp_processing(&mut self, event: &Event) -> bool {
    match event {
    Event::Stanza(stanza) => INCOMING.process(self, stanza.clone()),
    Event::Online => true,
    e => {
    warn!("Unexpected event {:?}", e);
    false
    }
    }
    }
    /// Process roster push
    /// see RFC 6212 2.1.6. Roster Push
    fn incoming_iq_processing_set_roster(
    &mut self,
    roster: xmpp_parsers::roster::Roster,
    ) -> Box<dyn IqRequestHandler> {
    for i in roster.items {
    if let Some(ref mut rdata) = self.state.data.roster.get_mut(&i.jid) {
    info!("Update {} in roster", i.jid);
    rdata.0 = i.subscription;
    rdata.1 = i.ask;
    } else {
    info!("Add {} to roster", i.jid);
    self.state
    .data
    .roster
    .insert(i.jid.clone(), (i.subscription, i.ask));
    }
    self.process_jid(&i.jid);
    }
    Box::new(IqSetRoster {})
    }
    /// Enforce to answer to IQ "set"
    fn incoming_iq_processing_set(
    &mut self,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    element: minidom::Element,
    ) -> xmpp_parsers::iq::Iq {
    INCOMING_IQ_SET
    .process(self, element)
    .process(self, id, from)
    }
    /// Process ping request
    /// see XEP-0199: XMPP Ping
    fn incoming_iq_processing_get_ping(
    &mut self,
    _ping: xmpp_parsers::ping::Ping,
    ) -> Box<dyn IqRequestHandler> {
    Box::new(IqGetPing {})
    }
    /// Process disco query
    /// see XEP-0030: Service Discovery
    fn incoming_iq_processing_get_disco_info(
    &mut self,
    disco: xmpp_parsers::disco::DiscoInfoQuery,
    ) -> Box<dyn IqRequestHandler> {
    if let Some(ref node) = disco.node {
    warn!("Unsupported node {}", node);
    Box::new(IqRequestUnknown {
    element: disco.into(),
    type_: "get",
    })
    } else {
    Box::new(IqGetDiscoInfo {})
    }
    }
    /// Process disco items query
    /// see XEP-0030: Service Discovery
    fn incoming_iq_processing_get_disco_items(
    &mut self,
    disco: xmpp_parsers::disco::DiscoItemsQuery,
    ) -> Box<dyn IqRequestHandler> {
    match &disco.node {
    Some(node) if node == "http://jabber.org/protocol/commands" => {
    Box::new(IqGetDiscoCommands {})
    }
    Some(node) => {
    warn!("Unsupported node {}", node);
    Box::new(IqRequestUnknown {
    element: disco.into(),
    type_: "get",
    })
    }
    None => Box::new(IqGetDiscoItems {}),
    }
    }
    /// Enforce to answer to IQ "get"
    fn incoming_iq_processing_get(
    &mut self,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    element: minidom::Element,
    ) -> xmpp_parsers::iq::Iq {
    INCOMING_IQ_GET
    .process(self, element)
    .process(self, id, from)
    }
    fn incoming_iq_processing(&mut self, iq: xmpp_parsers::iq::Iq) -> bool {
    match iq.payload {
    xmpp_parsers::iq::IqType::Set(element) => {
    let iq_answer = self.incoming_iq_processing_set(iq.id, iq.from, element);
    self.state.data.send_queue.push_back(iq_answer.into());
    }
    xmpp_parsers::iq::IqType::Error(e) => {
    if let Some((_, handler)) = self.state.data.pending_ids.remove_entry(&iq.id) {
    return handler.1.error(self, e);
    }
    error!("iq error: {:?}", e);
    return false;
    }
    xmpp_parsers::iq::IqType::Get(element) => {
    let iq_answer = self.incoming_iq_processing_get(iq.id, iq.from, element);
    self.state.data.send_queue.push_back(iq_answer.into());
    }
    xmpp_parsers::iq::IqType::Result(opt_element) => {
    if let Some((_, handler)) = self.state.data.pending_ids.remove_entry(&iq.id) {
    return handler.1.result(self, opt_element);
    }
    warn!(
    "Unwanted iq result id {} from {:?}: {:?}",
    iq.id,
    iq.from,
    opt_element.map(|e| String::from(&e))
    );
    }
    }
    true
    }
    fn incoming_presence_processing(&mut self, presence: xmpp_parsers::presence::Presence) -> bool {
    if presence.from.as_ref() == Some(&self.state.client.jid) {
    info!("Self-presence accepted");
    self.state.data.self_presence = true;
    } else {
    warn!("Incoming presence stanza: {:?}", presence);
    }
    true
    }
    fn incoming_message_processing(&mut self, message: xmpp_parsers::message::Message) -> bool {
    for payload in message.payloads.iter() {
    use std::convert::TryInto;
    if let Some(_delay) =
    payload.clone().try_into().ok() as Option<xmpp_parsers::delay::Delay>
    {
    return true; // ignore delayed messages
    }
    }
    warn!("Incoming message stanza: {:?}", message);
    true
    }
    /// process event from xmpp stream
    /// returns from future when condition met
    /// or stop future was resolved.
    /// Return item if connection was preserved or error otherwise.
    /// Second part is a state of stop_future
    pub fn processing<S, F, T, E>(
    self,
    stop_condition: S,
    stop_future: F,
    ) -> impl Future<
    Item = (Self, Result<Either<F, T>, E>),
    Error = (std::rc::Rc<config::Account>, Result<Either<F, T>, E>),
    >
    where
    F: Future<Item = T, Error = E> + 'static,
    S: FnMut(&mut Self, Event) -> Result<bool, ()> + 'static,
    T: 'static,
    E: 'static,
    {
    future::loop_fn(
    (self, stop_future, stop_condition),
    |(xmpp, stop_future, mut stop_condition)| {
    // ToDo: check timeouts if iqs
    let XmppConnection {
    state: XmppState { client, mut data },
    account,
    } = xmpp;
    if let Some(send_element) = data.send_queue.pop_front() {
    use tokio::prelude::Sink;
    info!("Sending {}", String::from(&send_element));
    Box::new(
    client
    .send(Packet::Stanza(send_element))
    .select2(stop_future)
    .then(move |r| match r {
    Ok(Either::A((client, b))) => {
    Box::new(future::ok(future::Loop::Continue((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    b,
    stop_condition,
    ))))
    as Box<dyn Future<Item = _, Error = _>>
    }
    Ok(Either::B((t, a))) => Box::new(a.then(|r| match r {
    Ok(client) => future::ok(future::Loop::Break((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    Ok(Either::B(t)),
    ))),
    Err(se) => {
    warn!("XMPP sending error: {}", se);
    future::err((account, Ok(Either::B(t))))
    }
    })),
    Err(Either::A((e, b))) => {
    warn!("XMPP sending error: {}", e);
    Box::new(future::err((account, Ok(Either::A(b)))))
    }
    Err(Either::B((e, a))) => Box::new(a.then(|r| match r {
    Ok(client) => future::ok(future::Loop::Break((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    Err(e),
    ))),
    Err(se) => {
    warn!("XMPP sending error: {}", se);
    future::err((account, Err(e)))
    }
    })),
    }),
    ) as Box<dyn Future<Item = _, Error = _>>
    } else {
    Box::new(
    client
    .into_future()
    .select2(stop_future)
    .then(move |r| match r {
    Ok(Either::A(((event, client), b))) => {
    if let Some(event) = event {
    let mut xmpp = XmppConnection {
    state: XmppState { client, data },
    account,
    };
    if xmpp.xmpp_processing(&event) {
    match stop_condition(&mut xmpp, event) {
    Ok(true) => future::ok(future::Loop::Break((
    xmpp,
    Ok(Either::A(b)),
    ))),
    Ok(false) => future::ok(future::Loop::Continue((
    xmpp,
    b,
    stop_condition,
    ))),
    Err(_e) => {
    future::err((xmpp.account, Ok(Either::A(b))))
    }
    }
    } else {
    future::err((xmpp.account, Ok(Either::A(b))))
    }
    } else {
    future::err((account, Ok(Either::A(b))))
    }
    }
    Ok(Either::B((t, a))) => {
    if let Some(client) = a.into_inner() {
    future::ok(future::Loop::Break((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    Ok(Either::B(t)),
    )))
    } else {
    future::err((account, Ok(Either::B(t))))
    }
    }
    Err(Either::A((e, b))) => {
    warn!("XMPP error: {}", e.0);
    future::err((account, Ok(Either::A(b))))
    }
    Err(Either::B((e, a))) => {
    if let Some(client) = a.into_inner() {
    future::ok(future::Loop::Break((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    Err(e),
    )))
    } else {
    future::err((account, Err(e)))
    }
    }
    }),
    )
    }
    },
    )
    }
    /// get connection and wait for online status and set presence
    /// returns error if something went wrong and xmpp connection is broken
    fn online(&mut self, event: Event) -> Result<bool, ()> {
    match event {
    Event::Online => {
    info!("Online!");
    Ok(true)
    }
    Event::Stanza(s) => {
    warn!("Stanza before online: {}", String::from(&s));
    Ok(false)
    }
    _ => {
    error!("Disconnected while online");
    Err(())
    }
    }
    }
    fn initial_roster<F, E>(
    self,
    stop_future: F,
    ) -> impl Future<Item = Self, Error = std::rc::Rc<config::Account>>
    where
    F: Future<Error = E> + 'static,
    E: 'static,
    {
    let XmppConnection {
    account,
    state: XmppState { client, mut data },
    } = self;
    use tokio::prelude::Sink;
    data.counter += 1;
    let id_init_roster = format!("id_init_roster{}", data.counter);
    let get_roster = stanzas::make_get_roster(&id_init_roster);
    let account2 = account.clone();
    info!("Quering roster... {}", String::from(&get_roster));
    data.pending_ids.insert(
    id_init_roster.clone(),
    (
    Instant::now() + Duration::from_secs(60),
    Box::new(InitRosterIqHandler {}),
    ),
    );
    client
    .send(Packet::Stanza(get_roster))
    .map_err(move |e| {
    error!("Error on querying roster: {}", e);
    account2
    })
    .and_then(move |client| {
    XmppConnection {
    state: XmppState { client, data },
    account,
    }
    .processing(move |conn, _| Ok(conn.state.data.roster_init), stop_future)
    .map_err(|(account, _)| account)
    .and_then(|(conn, r)| match r {
    Ok(Either::A(_)) => future::ok(conn),
    Ok(Either::B(_)) => future::err(conn.account),
    Err(_e) => future::err(conn.account),
    })
    })
    }
    fn self_presence<F, E>(
    self,
    stop_future: F,
    ) -> impl Future<Item = Self, Error = std::rc::Rc<config::Account>>
    where
    F: Future<Error = E> + 'static,
    E: Into<failure::Error> + 'static,
    {
    let XmppConnection {
    account,
    state: XmppState { client, data },
    } = self;
    use tokio::prelude::Sink;
    let presence = stanzas::make_presence(&account);
    let account2 = account.clone();
    info!("Sending presence... {}", String::from(&presence));
    client
    .send(Packet::Stanza(presence))
    .map_err(|e| {
    error!("Error on send self-presence: {}", e);
    account2
    })
    .and_then(move |client| {
    XmppConnection {
    state: XmppState { client, data },
    account,
    }
    .processing(
    move |conn, _| Ok(conn.state.data.self_presence),
    stop_future,
    )
    .map_err(|(account, _)| account)
    .and_then(|(conn, r)| match r {
    Ok(Either::A(_)) => future::ok(conn),
    Ok(Either::B(_)) => future::err(conn.account),
    Err(_e) => future::err(conn.account),
    })
    })
    }
    fn process_jid(&mut self, xmpp_to: &xmpp_parsers::Jid) {
    if let Some(ref mut mailbox) = self.state.data.outgoing_mailbox.get_mut(xmpp_to) {
    if !mailbox.is_empty() {
    if let Some(ref mut rdata) = self.state.data.roster.get_mut(xmpp_to) {
    info!("Jid {} in roster", xmpp_to);
    let sub_to = match rdata.0 {
    xmpp_parsers::roster::Subscription::To => true,
    xmpp_parsers::roster::Subscription::Both => true,
    _ => false,
    };
    if sub_to {
    info!("Subscribed to {}", xmpp_to);
    self.state.data.send_queue.extend(
    mailbox.drain(..).map(|message| {
    stanzas::make_chat_message(xmpp_to.clone(), message)
    }),
    );
    } else if rdata.1 == xmpp_parsers::roster::Ask::None {
    info!("Not subscribed to {}", xmpp_to);
    self.state
    .data
    .send_queue
    .push_back(stanzas::make_ask_subscribe(xmpp_to.clone()));
    }
    let sub_from = match rdata.0 {
    xmpp_parsers::roster::Subscription::From => true,
    xmpp_parsers::roster::Subscription::Both => true,
    _ => false,
    };
    if !sub_from {
    info!("Not subscription from {}", xmpp_to);
    self.state
    .data
    .send_queue
    .push_back(stanzas::make_allow_subscribe(xmpp_to.clone()));
    }
    } else {
    info!("Jid {} not in roster", xmpp_to);
    self.state.data.counter += 1;
    let id_add_roster = format!("id_add_roster{}", self.state.data.counter);
    let add_roster = stanzas::make_add_roster(&id_add_roster, xmpp_to.clone());
    info!("Adding jid {} to roster id {}", xmpp_to, id_add_roster);
    self.state.data.pending_ids.insert(
    id_add_roster,
    (
    Instant::now() + Duration::from_secs(60),
    Box::new(AddRosterIqHandler {
    jid: xmpp_to.clone(),
    }),
    ),
    );
    self.state.data.send_queue.push_back(add_roster);
    }
    }
    }
    }
    pub fn process_command(&mut self, cmd: XmppCommand) {
    info!("Got command");
    match cmd {
    XmppCommand::Chat { xmpp_to, message } => {
    self.state
    .data
    .outgoing_mailbox
    .entry(xmpp_to.clone())
    .or_default()
    .push(message);
    self.process_jid(&xmpp_to);
    }
    XmppCommand::Chatroom { muc_id, message } => {
    if let Some(muc) = self.state.data.mucs.get(&muc_id) {
    self.state
    .data
    .send_queue
    .push_back(stanzas::make_muc_message(muc.clone(), message));
    } else {
    error!("Not found MUC {}", muc_id);
    }
    }
    XmppCommand::Ping => {
    self.state.data.counter += 1;
    let id_ping = format!("id_ping{}", self.state.data.counter);
    let ping = stanzas::make_ping(&id_ping, self.state.client.jid.clone());
    self.state.data.send_queue.push_back(ping);
    self.state.data.pending_ids.insert(
    id_ping,
    (
    Instant::now() + Duration::from_secs(30),
    Box::new(PingIqHandler {}),
    ),
    );
    }
    XmppCommand::TimeoutCleanup => {
    let now = Instant::now();
    let timeouted: Vec<String> = self
    .state
    .data
    .pending_ids
    .iter()
    .filter_map(|(id, (timeout, _))| {
    if now >= *timeout {
    Some(id.to_string())
    } else {
    None
    }
    })
    .collect();
    let mut correct = true;
    timeouted.into_iter().for_each(|id| {
    if let Some((_, handler)) = self.state.data.pending_ids.remove(&id) {
    correct &= handler.timeout(&mut self);
    }
    })
    }
    }
    }
    pub fn shutdown(self) -> impl Future<Item = (), Error = failure::Error> {
    info!("Shutdown connection");
    let XmppConnection { account, state } = self;
    stream::iter_ok(
    state
    .data
    .mucs
    .values()
    .map(std::clone::Clone::clone)
    .collect::<Vec<_>>(),
    )
    .fold(state, move |XmppState { client, data }, muc_jid| {
    let muc_presence =
    stanzas::make_muc_presence_leave(account.jid.clone(), muc_jid.clone());
    info!(
    "Sending muc leave presence... {}",
    String::from(&muc_presence)
    );
    use tokio::prelude::Sink;
    client
    .send(Packet::Stanza(muc_presence))
    .map_err(|e| {
    error!("Error on send muc presence: {}", e);
    e
    })
    .and_then(|client| future::ok(XmppState { client, data }))
    })
    .map(|_| ())
    }
    fn enter_mucs<F, E>(
    self,
    _stop_future: F,
    ) -> impl Future<Item = Self, Error = std::rc::Rc<config::Account>>
    where
    F: Future<Error = E> + 'static,
    E: Into<failure::Error> + 'static,
    {
    let XmppConnection { account, state } = self;
    let account2 = account.clone();
    let account3 = account.clone();
    stream::iter_ok(account.chatrooms.clone())
    .fold(state, move |XmppState { client, mut data }, muc_jid| {
    data.counter += 1;
    let id_muc_presence = format!("id_muc_presence{}", data.counter);
    let muc_presence = stanzas::make_muc_presence(
    &id_muc_presence,
    account2.jid.clone(),
    muc_jid.1.clone(),
    );
    info!("Sending muc presence... {}", String::from(&muc_presence));
    let account4 = account2.clone();
    use tokio::prelude::Sink;
    client
    .send(Packet::Stanza(muc_presence))
    .map_err(|e| {
    error!("Error on send muc presence: {}", e);
    account4
    })
    .and_then(|client| {
    data.mucs.insert(muc_jid.0, muc_jid.1);
    future::ok(XmppState { client, data })
    })
    })
    .map(|state| XmppConnection {
    account: account3,
    state,
    })
    }
    }
    [3.21]
    use tokio_xmpp::{Client, Event, Packet};
    use tokio::prelude::future::{self, Either};
    use tokio::prelude::stream;
    use tokio::prelude::{Future, Stream};
    use std::collections::{HashMap, VecDeque};
    use std::time::{Duration, Instant};
    use super::stanzas;
    use super::element_processor;
    use crate::config;
    #[derive(Debug)]
    pub enum XmppCommand {
    /// Send message to someone by jid
    Chat {
    xmpp_to: xmpp_parsers::Jid,
    message: String,
    },
    /// Send message to MUC
    Chatroom { muc_id: String, message: String },
    /// Send ping request to the server to test connection
    Ping,
    /// Check iq requests if some have expired timeouts
    TimeoutCleanup,
    }
    /// trait of processing iq
    /// each function consumes handlers and
    /// returns false if connection should be reset
    trait IqHandler {
    /// process result
    fn result(
    self: Box<Self>,
    conn: &mut XmppConnection,
    opt_element: Option<xmpp_parsers::Element>,
    ) -> bool;
    /// process error
    fn error(
    self: Box<Self>,
    conn: &mut XmppConnection,
    error: xmpp_parsers::stanza_error::StanzaError,
    ) -> bool;
    /// process tmeout
    fn timeout(self: Box<Self>, conn: &mut XmppConnection) -> bool;
    }
    struct AddRosterIqHandler {
    jid: xmpp_parsers::Jid,
    }
    impl IqHandler for AddRosterIqHandler {
    fn result(
    self: Box<Self>,
    conn: &mut XmppConnection,
    opt_element: Option<xmpp_parsers::Element>,
    ) -> bool {
    match opt_element {
    Some(element) => {
    warn!(
    "Wrong payload when adding {} to roster: {}",
    self.jid,
    String::from(&element)
    );
    }
    None => {
    if conn.state.data.roster.contains_key(&self.jid) {
    info!("Jid {} updated to roster", self.jid);
    } else {
    info!("Jid {} added in roster", self.jid);
    conn.state.data.roster.insert(
    self.jid.clone(),
    (
    xmpp_parsers::roster::Subscription::None,
    xmpp_parsers::roster::Ask::None,
    ),
    );
    }
    conn.process_jid(&self.jid);
    }
    }
    true
    }
    fn error(
    self: Box<Self>,
    _conn: &mut XmppConnection,
    _error: xmpp_parsers::stanza_error::StanzaError,
    ) -> bool {
    true
    }
    fn timeout(self: Box<Self>, _conn: &mut XmppConnection) -> bool {
    true // ignore
    }
    }
    struct PingIqHandler {}
    impl IqHandler for PingIqHandler {
    fn result(
    self: Box<Self>,
    _conn: &mut XmppConnection,
    _opt_element: Option<xmpp_parsers::Element>,
    ) -> bool {
    info!("ping successed");
    true
    }
    fn error(
    self: Box<Self>,
    _conn: &mut XmppConnection,
    _error: xmpp_parsers::stanza_error::StanzaError,
    ) -> bool {
    false
    }
    fn timeout(self: Box<Self>, _conn: &mut XmppConnection) -> bool {
    false
    }
    }
    struct InitRosterIqHandler {}
    impl IqHandler for InitRosterIqHandler {
    fn result(
    self: Box<Self>,
    conn: &mut XmppConnection,
    opt_element: Option<xmpp_parsers::Element>,
    ) -> bool {
    if let Some(result) = opt_element {
    use std::convert::TryInto;
    match result.try_into() as Result<xmpp_parsers::roster::Roster, _> {
    Ok(roster) => {
    conn.state.data.roster_init = true;
    conn.state.data.roster.clear();
    info!("Got first roster:");
    for i in roster.items {
    info!(" >>> {:?}", i);
    conn.state
    .data
    .roster
    .insert(i.jid, (i.subscription, i.ask));
    }
    true
    }
    Err(e) => {
    error!("Cann't parse roster: {}", e);
    false
    }
    }
    } else {
    error!("No roster responded");
    false
    }
    }
    fn error(
    self: Box<Self>,
    _conn: &mut XmppConnection,
    _error: xmpp_parsers::stanza_error::StanzaError,
    ) -> bool {
    false
    }
    fn timeout(self: Box<Self>, _conn: &mut XmppConnection) -> bool {
    false
    }
    }
    #[derive(Default)]
    struct XmppData {
    /// known roster data
    roster: HashMap<
    xmpp_parsers::Jid,
    (
    xmpp_parsers::roster::Subscription,
    xmpp_parsers::roster::Ask,
    ),
    >,
    /// if roster was initialized
    /// ToDo: remove it as it is used only for initialization
    roster_init: bool,
    /// if self-presence accepted
    /// ToDo: remove it as it is used only for initialization
    self_presence: bool,
    /// ids counter
    counter: usize,
    /// stanzas to send
    send_queue: VecDeque<minidom::Element>,
    /// outgoing mailbox
    outgoing_mailbox: HashMap<xmpp_parsers::Jid, Vec<String>>,
    /// muc id to muc jid
    mucs: HashMap<String, xmpp_parsers::Jid>,
    /// map from iq's id to handler of this type of iqs
    pending_ids: HashMap<String, (Instant, Box<dyn IqHandler>)>,
    }
    struct XmppState {
    client: Client,
    data: XmppData,
    }
    pub struct XmppConnection {
    account: std::rc::Rc<config::Account>,
    state: XmppState,
    }
    trait IqRequestHandler {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq;
    }
    struct IqRequestUnknown {
    element: xmpp_parsers::Element,
    type_: &'static str,
    }
    impl IqRequestHandler for IqRequestUnknown {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    warn!(
    "Unsupported IQ {} request from {:?}: {}",
    self.type_,
    from,
    String::from(&self.element)
    );
    stanzas::make_iq_unsupported_error(id, conn.state.client.jid.clone(), from)
    }
    }
    struct IqSetRoster {}
    impl IqRequestHandler for IqSetRoster {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    info!("Got roster push {} from {:?}", id, from);
    stanzas::make_roster_push_answer(id, conn.state.client.jid.clone(), from)
    }
    }
    struct IqGetPing {}
    impl IqRequestHandler for IqGetPing {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    info!("Got ping {} from {:?}", id, from);
    stanzas::make_pong(id, conn.state.client.jid.clone(), from)
    }
    }
    struct IqGetVersion {}
    impl IqRequestHandler for IqGetVersion {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    info!("Got version query {} from {:?}", id, from);
    stanzas::make_version(id, conn.state.client.jid.clone(), from)
    }
    }
    struct IqGetDiscoInfo {}
    impl IqRequestHandler for IqGetDiscoInfo {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    info!("Got disco query {} from {:?}", id, from);
    stanzas::make_disco_info_result(id, conn.state.client.jid.clone(), from)
    }
    }
    struct IqGetDiscoItems {}
    impl IqRequestHandler for IqGetDiscoItems {
    fn process(
    self: Box<Self>,
    conn: &mut XmppConnection,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    ) -> xmpp_parsers::iq::Iq {
    info!("Got disco items query {} from {:?}", id, from);
    stanzas::make_disco_items_result(id, conn.state.client.jid.clone(), from)
    }
    }
    lazy_static! {
    static ref INCOMING: element_processor::Processor<XmppConnection, bool, xmpp_parsers::Element> = {
    let mut incoming = element_processor::Processor::new(&|_, e| {
    warn!("Unknown stanza {}", String::from(&e));
    true
    });
    incoming.register(&XmppConnection::incoming_iq_processing);
    incoming.register(&XmppConnection::incoming_presence_processing);
    incoming.register(&XmppConnection::incoming_message_processing);
    incoming
    };
    static ref INCOMING_IQ_SET: element_processor::Processor<XmppConnection, Box<dyn IqRequestHandler>, xmpp_parsers::Element> = {
    let mut iq_set =
    element_processor::Processor::new(&|_conn: &mut XmppConnection, element| {
    Box::new(IqRequestUnknown {
    element,
    type_: "set",
    }) as Box<dyn IqRequestHandler>
    });
    iq_set.register(&XmppConnection::incoming_iq_processing_set_roster);
    iq_set
    };
    static ref INCOMING_IQ_GET: element_processor::Processor<XmppConnection, Box<dyn IqRequestHandler>, xmpp_parsers::Element> = {
    let mut iq_get =
    element_processor::Processor::new(&|_conn: &mut XmppConnection, element| {
    Box::new(IqRequestUnknown {
    element,
    type_: "get",
    }) as Box<dyn IqRequestHandler>
    });
    iq_get.register(&XmppConnection::incoming_iq_processing_get_ping);
    iq_get.register(&XmppConnection::incoming_iq_processing_get_disco_info);
    iq_get.register(&XmppConnection::incoming_iq_processing_get_disco_items);
    iq_get.register(&XmppConnection::incoming_iq_processing_get_version);
    iq_get
    };
    }
    pub struct MaybeXmppConnection {
    account: std::rc::Rc<config::Account>,
    state: Option<XmppState>,
    }
    impl From<XmppConnection> for MaybeXmppConnection {
    fn from(from: XmppConnection) -> MaybeXmppConnection {
    MaybeXmppConnection {
    account: from.account,
    state: Some(from.state),
    }
    }
    }
    impl From<config::Account> for MaybeXmppConnection {
    fn from(from: config::Account) -> MaybeXmppConnection {
    MaybeXmppConnection {
    account: std::rc::Rc::new(from),
    state: None,
    }
    }
    }
    impl From<std::rc::Rc<config::Account>> for MaybeXmppConnection {
    fn from(from: std::rc::Rc<config::Account>) -> MaybeXmppConnection {
    MaybeXmppConnection {
    account: from,
    state: None,
    }
    }
    }
    impl MaybeXmppConnection {
    /// connects if nothing connected
    /// don't connect only if stop_future resolved
    pub fn connect<F>(
    self,
    stop_future: F,
    ) -> impl Future<Item = XmppConnection, Error = failure::Error>
    where
    F: future::Future + Clone + 'static,
    <F as hyper::rt::Future>::Error: Into<failure::Error> + Send,
    {
    info!("xmpp connection...");
    let MaybeXmppConnection { account, state } = self;
    if let Some(state) = state {
    Box::new(future::ok(XmppConnection { account, state }))
    as Box<dyn Future<Item = _, Error = _>>
    } else {
    Box::new(
    stop_future
    .clone()
    .select2(
    future::loop_fn(account, move |account| {
    info!("xmpp initialization...");
    let client =
    Client::new_with_jid(account.jid.clone(), &account.password);
    info!("xmpp initialized");
    let stop_future2 = stop_future.clone();
    let stop_future3 = stop_future.clone();
    let stop_future4 = stop_future.clone();
    // future to wait for online
    Box::new(
    XmppConnection {
    state: XmppState {
    client,
    data: std::default::Default::default(),
    },
    account,
    }
    .processing(XmppConnection::online, stop_future.clone())
    .map_err(|(acc, _)| acc)
    .and_then(|(conn, r)| match r {
    Ok(Either::A(_)) => future::ok(conn),
    Ok(Either::B(_)) => future::err(conn.account),
    Err(_e) => future::err(conn.account),
    })
    .and_then(|conn| conn.initial_roster(stop_future2))
    .and_then(|conn| conn.self_presence(stop_future3))
    .and_then(|conn| conn.enter_mucs(stop_future4))
    .then(|r| match r {
    Ok(conn) => future::ok(future::Loop::Break(conn)),
    Err(acc) => future::ok(future::Loop::Continue(acc)),
    }),
    )
    })
    .map_err(|_: ()| ()),
    )
    .then(|r| match r {
    Ok(Either::A((_x, _b))) => future::err(format_err!("Stop XMMP connection")),
    Ok(Either::B((x, _a))) => future::ok(x),
    Err(Either::A((e, _b))) => future::err(e.into()),
    Err(Either::B((_, _a))) => {
    future::err(format_err!("Cann't initiate XMPP connection"))
    }
    }),
    )
    }
    }
    }
    impl XmppConnection {
    /// base XMPP processing
    /// Returns false on error to disconnect
    fn xmpp_processing(&mut self, event: &Event) -> bool {
    match event {
    Event::Stanza(stanza) => INCOMING.process(self, stanza.clone()),
    Event::Online => true,
    e => {
    warn!("Unexpected event {:?}", e);
    false
    }
    }
    }
    /// Process roster push
    /// see RFC 6212 2.1.6. Roster Push
    fn incoming_iq_processing_set_roster(
    &mut self,
    roster: xmpp_parsers::roster::Roster,
    ) -> Box<dyn IqRequestHandler> {
    for i in roster.items {
    if let Some(ref mut rdata) = self.state.data.roster.get_mut(&i.jid) {
    info!("Update {} in roster", i.jid);
    rdata.0 = i.subscription;
    rdata.1 = i.ask;
    } else {
    info!("Add {} to roster", i.jid);
    self.state
    .data
    .roster
    .insert(i.jid.clone(), (i.subscription, i.ask));
    }
    self.process_jid(&i.jid);
    }
    Box::new(IqSetRoster {})
    }
    /// Enforce to answer to IQ "set"
    fn incoming_iq_processing_set(
    &mut self,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    element: minidom::Element,
    ) -> xmpp_parsers::iq::Iq {
    INCOMING_IQ_SET
    .process(self, element)
    .process(self, id, from)
    }
    /// Process ping request
    /// see XEP-0199: XMPP Ping
    fn incoming_iq_processing_get_ping(
    &mut self,
    _ping: xmpp_parsers::ping::Ping,
    ) -> Box<dyn IqRequestHandler> {
    Box::new(IqGetPing {})
    }
    /// Process disco query
    /// see XEP-0030: Service Discovery
    fn incoming_iq_processing_get_disco_info(
    &mut self,
    disco: xmpp_parsers::disco::DiscoInfoQuery,
    ) -> Box<dyn IqRequestHandler> {
    if let Some(ref node) = disco.node {
    warn!("Unsupported node {}", node);
    Box::new(IqRequestUnknown {
    element: disco.into(),
    type_: "get",
    })
    } else {
    Box::new(IqGetDiscoInfo {})
    }
    }
    /// Process disco items query
    /// see XEP-0030: Service Discovery
    fn incoming_iq_processing_get_disco_items(
    &mut self,
    disco: xmpp_parsers::disco::DiscoItemsQuery,
    ) -> Box<dyn IqRequestHandler> {
    if let Some(ref node) = disco.node {
    warn!("Unsupported node {}", node);
    Box::new(IqRequestUnknown {
    element: disco.into(),
    type_: "get",
    })
    } else {
    Box::new(IqGetDiscoItems {})
    }
    }
    /// Process version query
    /// see XEP-0092: Software Version
    fn incoming_iq_processing_get_version(
    &mut self,
    _version: xmpp_parsers::version::VersionQuery,
    ) -> Box<dyn IqRequestHandler> {
    Box::new(IqGetVersion {})
    }
    /// Enforce to answer to IQ "get"
    fn incoming_iq_processing_get(
    &mut self,
    id: String,
    from: Option<xmpp_parsers::Jid>,
    element: minidom::Element,
    ) -> xmpp_parsers::iq::Iq {
    INCOMING_IQ_GET
    .process(self, element)
    .process(self, id, from)
    }
    fn incoming_iq_processing(&mut self, iq: xmpp_parsers::iq::Iq) -> bool {
    match iq.payload {
    xmpp_parsers::iq::IqType::Set(element) => {
    let iq_answer = self.incoming_iq_processing_set(iq.id, iq.from, element);
    self.state.data.send_queue.push_back(iq_answer.into());
    }
    xmpp_parsers::iq::IqType::Error(e) => {
    if let Some((_, handler)) = self.state.data.pending_ids.remove_entry(&iq.id) {
    return handler.1.error(self, e);
    }
    error!("iq error: {:?}", e);
    return false;
    }
    xmpp_parsers::iq::IqType::Get(element) => {
    let iq_answer = self.incoming_iq_processing_get(iq.id, iq.from, element);
    self.state.data.send_queue.push_back(iq_answer.into());
    }
    xmpp_parsers::iq::IqType::Result(opt_element) => {
    if let Some((_, handler)) = self.state.data.pending_ids.remove_entry(&iq.id) {
    return handler.1.result(self, opt_element);
    }
    warn!(
    "Unwanted iq result id {} from {:?}: {:?}",
    iq.id,
    iq.from,
    opt_element.map(|e| String::from(&e))
    );
    }
    }
    true
    }
    fn incoming_presence_processing(&mut self, presence: xmpp_parsers::presence::Presence) -> bool {
    if presence.from.as_ref() == Some(&self.state.client.jid) {
    info!("Self-presence accepted");
    self.state.data.self_presence = true;
    } else {
    warn!("Incoming presence stanza: {:?}", presence);
    }
    true
    }
    fn incoming_message_processing(&mut self, message: xmpp_parsers::message::Message) -> bool {
    for payload in message.payloads.iter() {
    use std::convert::TryInto;
    if let Some(_delay) =
    payload.clone().try_into().ok() as Option<xmpp_parsers::delay::Delay>
    {
    return true; // ignore delayed messages
    }
    }
    warn!("Incoming message stanza: {:?}", message);
    true
    }
    /// process event from xmpp stream
    /// returns from future when condition met
    /// or stop future was resolved.
    /// Return item if connection was preserved or error otherwise.
    /// Second part is a state of stop_future
    pub fn processing<S, F, T, E>(
    self,
    stop_condition: S,
    stop_future: F,
    ) -> impl Future<
    Item = (Self, Result<Either<F, T>, E>),
    Error = (std::rc::Rc<config::Account>, Result<Either<F, T>, E>),
    >
    where
    F: Future<Item = T, Error = E> + 'static,
    S: FnMut(&mut Self, Event) -> Result<bool, ()> + 'static,
    T: 'static,
    E: 'static,
    {
    future::loop_fn(
    (self, stop_future, stop_condition),
    |(xmpp, stop_future, mut stop_condition)| {
    // ToDo: check timeouts if iqs
    let XmppConnection {
    state: XmppState { client, mut data },
    account,
    } = xmpp;
    if let Some(send_element) = data.send_queue.pop_front() {
    use tokio::prelude::Sink;
    info!("Sending {}", String::from(&send_element));
    Box::new(
    client
    .send(Packet::Stanza(send_element))
    .select2(stop_future)
    .then(move |r| match r {
    Ok(Either::A((client, b))) => {
    Box::new(future::ok(future::Loop::Continue((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    b,
    stop_condition,
    ))))
    as Box<dyn Future<Item = _, Error = _>>
    }
    Ok(Either::B((t, a))) => Box::new(a.then(|r| match r {
    Ok(client) => future::ok(future::Loop::Break((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    Ok(Either::B(t)),
    ))),
    Err(se) => {
    warn!("XMPP sending error: {}", se);
    future::err((account, Ok(Either::B(t))))
    }
    })),
    Err(Either::A((e, b))) => {
    warn!("XMPP sending error: {}", e);
    Box::new(future::err((account, Ok(Either::A(b)))))
    }
    Err(Either::B((e, a))) => Box::new(a.then(|r| match r {
    Ok(client) => future::ok(future::Loop::Break((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    Err(e),
    ))),
    Err(se) => {
    warn!("XMPP sending error: {}", se);
    future::err((account, Err(e)))
    }
    })),
    }),
    ) as Box<dyn Future<Item = _, Error = _>>
    } else {
    Box::new(
    client
    .into_future()
    .select2(stop_future)
    .then(move |r| match r {
    Ok(Either::A(((event, client), b))) => {
    if let Some(event) = event {
    let mut xmpp = XmppConnection {
    state: XmppState { client, data },
    account,
    };
    if xmpp.xmpp_processing(&event) {
    match stop_condition(&mut xmpp, event) {
    Ok(true) => future::ok(future::Loop::Break((
    xmpp,
    Ok(Either::A(b)),
    ))),
    Ok(false) => future::ok(future::Loop::Continue((
    xmpp,
    b,
    stop_condition,
    ))),
    Err(_e) => {
    future::err((xmpp.account, Ok(Either::A(b))))
    }
    }
    } else {
    future::err((xmpp.account, Ok(Either::A(b))))
    }
    } else {
    future::err((account, Ok(Either::A(b))))
    }
    }
    Ok(Either::B((t, a))) => {
    if let Some(client) = a.into_inner() {
    future::ok(future::Loop::Break((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    Ok(Either::B(t)),
    )))
    } else {
    future::err((account, Ok(Either::B(t))))
    }
    }
    Err(Either::A((e, b))) => {
    warn!("XMPP error: {}", e.0);
    future::err((account, Ok(Either::A(b))))
    }
    Err(Either::B((e, a))) => {
    if let Some(client) = a.into_inner() {
    future::ok(future::Loop::Break((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    Err(e),
    )))
    } else {
    future::err((account, Err(e)))
    }
    }
    }),
    )
    }
    },
    )
    }
    /// get connection and wait for online status and set presence
    /// returns error if something went wrong and xmpp connection is broken
    fn online(&mut self, event: Event) -> Result<bool, ()> {
    match event {
    Event::Online => {
    info!("Online!");
    Ok(true)
    }
    Event::Stanza(s) => {
    warn!("Stanza before online: {}", String::from(&s));
    Ok(false)
    }
    _ => {
    error!("Disconnected while online");
    Err(())
    }
    }
    }
    fn initial_roster<F, E>(
    self,
    stop_future: F,
    ) -> impl Future<Item = Self, Error = std::rc::Rc<config::Account>>
    where
    F: Future<Error = E> + 'static,
    E: 'static,
    {
    let XmppConnection {
    account,
    state: XmppState { client, mut data },
    } = self;
    use tokio::prelude::Sink;
    data.counter += 1;
    let id_init_roster = format!("id_init_roster{}", data.counter);
    let get_roster = stanzas::make_get_roster(&id_init_roster);
    let account2 = account.clone();
    info!("Quering roster... {}", String::from(&get_roster));
    data.pending_ids.insert(
    id_init_roster.clone(),
    (
    Instant::now() + Duration::from_secs(60),
    Box::new(InitRosterIqHandler {}),
    ),
    );
    client
    .send(Packet::Stanza(get_roster))
    .map_err(move |e| {
    error!("Error on querying roster: {}", e);
    account2
    })
    .and_then(move |client| {
    XmppConnection {
    state: XmppState { client, data },
    account,
    }
    .processing(move |conn, _| Ok(conn.state.data.roster_init), stop_future)
    .map_err(|(account, _)| account)
    .and_then(|(conn, r)| match r {
    Ok(Either::A(_)) => future::ok(conn),
    Ok(Either::B(_)) => future::err(conn.account),
    Err(_e) => future::err(conn.account),
    })
    })
    }
    fn self_presence<F, E>(
    self,
    stop_future: F,
    ) -> impl Future<Item = Self, Error = std::rc::Rc<config::Account>>
    where
    F: Future<Error = E> + 'static,
    E: Into<failure::Error> + 'static,
    {
    let XmppConnection {
    account,
    state: XmppState { client, data },
    } = self;
    use tokio::prelude::Sink;
    let presence = stanzas::make_presence(&account);
    let account2 = account.clone();
    info!("Sending presence... {}", String::from(&presence));
    client
    .send(Packet::Stanza(presence))
    .map_err(|e| {
    error!("Error on send self-presence: {}", e);
    account2
    })
    .and_then(move |client| {
    XmppConnection {
    state: XmppState { client, data },
    account,
    }
    .processing(
    move |conn, _| Ok(conn.state.data.self_presence),
    stop_future,
    )
    .map_err(|(account, _)| account)
    .and_then(|(conn, r)| match r {
    Ok(Either::A(_)) => future::ok(conn),
    Ok(Either::B(_)) => future::err(conn.account),
    Err(_e) => future::err(conn.account),
    })
    })
    }
    fn process_jid(&mut self, xmpp_to: &xmpp_parsers::Jid) {
    if let Some(ref mut mailbox) = self.state.data.outgoing_mailbox.get_mut(xmpp_to) {
    if !mailbox.is_empty() {
    if let Some(ref mut rdata) = self.state.data.roster.get_mut(xmpp_to) {
    info!("Jid {} in roster", xmpp_to);
    let sub_to = match rdata.0 {
    xmpp_parsers::roster::Subscription::To => true,
    xmpp_parsers::roster::Subscription::Both => true,
    _ => false,
    };
    if sub_to {
    info!("Subscribed to {}", xmpp_to);
    self.state.data.send_queue.extend(
    mailbox.drain(..).map(|message| {
    stanzas::make_chat_message(xmpp_to.clone(), message)
    }),
    );
    } else if rdata.1 == xmpp_parsers::roster::Ask::None {
    info!("Not subscribed to {}", xmpp_to);
    self.state
    .data
    .send_queue
    .push_back(stanzas::make_ask_subscribe(xmpp_to.clone()));
    }
    let sub_from = match rdata.0 {
    xmpp_parsers::roster::Subscription::From => true,
    xmpp_parsers::roster::Subscription::Both => true,
    _ => false,
    };
    if !sub_from {
    info!("Not subscription from {}", xmpp_to);
    self.state
    .data
    .send_queue
    .push_back(stanzas::make_allow_subscribe(xmpp_to.clone()));
    }
    } else {
    info!("Jid {} not in roster", xmpp_to);
    self.state.data.counter += 1;
    let id_add_roster = format!("id_add_roster{}", self.state.data.counter);
    let add_roster = stanzas::make_add_roster(&id_add_roster, xmpp_to.clone());
    info!("Adding jid {} to roster id {}", xmpp_to, id_add_roster);
    self.state.data.pending_ids.insert(
    id_add_roster,
    (
    Instant::now() + Duration::from_secs(60),
    Box::new(AddRosterIqHandler {
    jid: xmpp_to.clone(),
    }),
    ),
    );
    self.state.data.send_queue.push_back(add_roster);
    }
    }
    }
    }
    pub fn process_command(&mut self, cmd: XmppCommand) {
    info!("Got command");
    match cmd {
    XmppCommand::Chat { xmpp_to, message } => {
    self.state
    .data
    .outgoing_mailbox
    .entry(xmpp_to.clone())
    .or_default()
    .push(message);
    self.process_jid(&xmpp_to);
    }
    XmppCommand::Chatroom { muc_id, message } => {
    if let Some(muc) = self.state.data.mucs.get(&muc_id) {
    self.state
    .data
    .send_queue
    .push_back(stanzas::make_muc_message(muc.clone(), message));
    } else {
    error!("Not found MUC {}", muc_id);
    }
    }
    XmppCommand::Ping => {
    self.state.data.counter += 1;
    let id_ping = format!("id_ping{}", self.state.data.counter);
    let ping = stanzas::make_ping(&id_ping, self.state.client.jid.clone());
    self.state.data.send_queue.push_back(ping);
    self.state.data.pending_ids.insert(
    id_ping,
    (
    Instant::now() + Duration::from_secs(30),
    Box::new(PingIqHandler {}),
    ),
    );
    }
    XmppCommand::TimeoutCleanup => {
    let now = Instant::now();
    let timeouted: Vec<String> = self
    .state
    .data
    .pending_ids
    .iter()
    .filter_map(|(id, (timeout, _))| {
    if now >= *timeout {
    Some(id.to_string())
    } else {
    None
    }
    })
    .collect();
    let mut correct = true;
    timeouted.into_iter().for_each(|id| {
    if let Some((_, handler)) = self.state.data.pending_ids.remove(&id) {
    correct &= handler.timeout(&mut self);
    }
    })
    }
    }
    }
    pub fn shutdown(self) -> impl Future<Item = (), Error = failure::Error> {
    info!("Shutdown connection");
    let XmppConnection { account, state } = self;
    stream::iter_ok(
    state
    .data
    .mucs
    .values()
    .map(std::clone::Clone::clone)
    .collect::<Vec<_>>(),
    )
    .fold(state, move |XmppState { client, data }, muc_jid| {
    let muc_presence =
    stanzas::make_muc_presence_leave(account.jid.clone(), muc_jid.clone());
    info!(
    "Sending muc leave presence... {}",
    String::from(&muc_presence)
    );
    use tokio::prelude::Sink;
    client
    .send(Packet::Stanza(muc_presence))
    .map_err(|e| {
    error!("Error on send muc presence: {}", e);
    e
    })
    .and_then(|client| future::ok(XmppState { client, data }))
    })
    .map(|_| ())
    }
    fn enter_mucs<F, E>(
    self,
    _stop_future: F,
    ) -> impl Future<Item = Self, Error = std::rc::Rc<config::Account>>
    where
    F: Future<Error = E> + 'static,
    E: Into<failure::Error> + 'static,
    {
    let XmppConnection { account, state } = self;
    let account2 = account.clone();
    let account3 = account.clone();
    stream::iter_ok(account.chatrooms.clone())
    .fold(state, move |XmppState { client, mut data }, muc_jid| {
    data.counter += 1;
    let id_muc_presence = format!("id_muc_presence{}", data.counter);
    let muc_presence = stanzas::make_muc_presence(
    &id_muc_presence,
    account2.jid.clone(),
    muc_jid.1.clone(),
    );
    info!("Sending muc presence... {}", String::from(&muc_presence));
    let account4 = account2.clone();
    use tokio::prelude::Sink;
    client
    .send(Packet::Stanza(muc_presence))
    .map_err(|e| {
    error!("Error on send muc presence: {}", e);
    account4
    })
    .and_then(|client| {
    data.mucs.insert(muc_jid.0, muc_jid.1);
    future::ok(XmppState { client, data })
    })
    })
    .map(|state| XmppConnection {
    account: account3,
    state,
    })
    }
    }
  • edit in src/xmpp/stanzas.rs at line 2
    [3.57]
    [3.35309]
    use xmpp_parsers::disco::{DiscoInfoResult, DiscoItemsResult, Feature, Identity};
  • edit in src/xmpp/stanzas.rs at line 5
    [3.35392]
    [3.57]
    use xmpp_parsers::ping::Ping;
  • edit in src/xmpp/stanzas.rs at line 8
    [3.35465]
    [3.141]
    use xmpp_parsers::stanza_error::{DefinedCondition, ErrorType, StanzaError};
    use xmpp_parsers::version::VersionResult;
  • replacement in src/xmpp/stanzas.rs at line 21
    [3.35611][2.38762:38923]()
    let mut get_roster = Iq::from_get(Roster {
    items: vec![],
    ver: None,
    });
    get_roster.id = Some(id.to_string());
    get_roster.into()
    [3.35611]
    [3.35737]
    Iq::from_get(
    id,
    Roster {
    items: vec![],
    ver: None,
    },
    )
    .into()
  • replacement in src/xmpp/stanzas.rs at line 32
    [3.35810][2.38924:39288]()
    let mut add_roster = Iq::from_set(Roster {
    items: vec![Item {
    jid,
    name: None,
    subscription: xmpp_parsers::roster::Subscription::None,
    ask: xmpp_parsers::roster::Ask::None,
    groups: vec![],
    }],
    ver: None,
    });
    add_roster.id = Some(id.to_string());
    add_roster.into()
    [3.35810]
    [3.36163]
    Iq::from_set(
    id,
    Roster {
    items: vec![Item {
    jid,
    name: None,
    subscription: xmpp_parsers::roster::Subscription::None,
    ask: xmpp_parsers::roster::Ask::None,
    groups: vec![],
    }],
    ver: None,
    },
    )
    .into()
  • edit in src/xmpp/stanzas.rs at line 48
    [3.36166]
    [3.36418]
    pub fn make_roster_push_answer(
    id: String,
    from: xmpp_parsers::Jid,
    to: Option<xmpp_parsers::Jid>,
    ) -> Iq {
    let mut answer = Iq::from_result(id, None as Option<Roster>);
    answer.from = Some(from);
    answer.to = to;
    answer
    }
  • edit in src/xmpp/stanzas.rs at line 61
    [3.36544]
    [3.36544]
    presence.to = Some(jid);
    presence.into()
    }
    pub fn make_allow_subscribe(jid: xmpp_parsers::Jid) -> Element {
    let mut presence = Presence::new(PresenceType::Subscribed);
  • edit in src/xmpp/stanzas.rs at line 92
    [3.37581]
    [3.37821]
    }
    pub fn make_muc_presence_leave(from: xmpp_parsers::Jid, to: xmpp_parsers::Jid) -> Element {
    let mut presence = Presence::new(PresenceType::Unavailable);
    presence.from = Some(from);
    presence.to = Some(to);
    presence.into()
    }
    pub fn make_ping(id: &str, from: xmpp_parsers::Jid) -> Element {
    let mut ping = Iq::from_get(id, Ping);
    ping.to = Some(from.clone().into_domain_jid());
    ping.from = Some(from);
    ping.into()
    }
    pub fn make_pong(id: String, from: xmpp_parsers::Jid, to: Option<xmpp_parsers::Jid>) -> Iq {
    let mut pong = Iq::from_result(id, None as Option<Roster>);
    pong.from = Some(from);
    pong.to = to;
    pong
    }
    pub fn make_version(id: String, from: xmpp_parsers::Jid, to: Option<xmpp_parsers::Jid>) -> Iq {
    let mut version = Iq::from_result(
    id,
    Some(VersionResult {
    name: "SendXmppDRust".to_string(),
    version: "0.1.0".to_string(),
    os: None,
    }),
    );
    version.from = Some(from);
    version.to = to;
    version
    }
    pub fn make_iq_unsupported_error(
    id: String,
    from: xmpp_parsers::Jid,
    to: Option<xmpp_parsers::Jid>,
    ) -> Iq {
    let mut error = Iq::from_error(
    id,
    StanzaError {
    type_: ErrorType::Cancel,
    by: Some(from.clone()),
    defined_condition: DefinedCondition::ServiceUnavailable,
    texts: std::collections::BTreeMap::new(),
    other: None,
    },
    );
    error.from = Some(from);
    error.to = to;
    error
    }
    pub fn make_disco_info_result(
    id: String,
    from: xmpp_parsers::Jid,
    to: Option<xmpp_parsers::Jid>,
    ) -> Iq {
    let mut result = Iq::from_result(
    id,
    Some(DiscoInfoResult {
    node: None,
    identities: vec![Identity {
    category: "client".to_string(),
    type_: "bot".to_string(),
    name: None,
    lang: None,
    }],
    features: vec![
    Feature {
    var: "http://jabber.org/protocol/disco#info".to_string(),
    },
    Feature {
    var: "urn:xmpp:ping".to_string(),
    },
    ],
    extensions: vec![],
    }),
    );
    result.from = Some(from);
    result.to = to;
    result
    }
    pub fn make_disco_items_result(
    id: String,
    from: xmpp_parsers::Jid,
    to: Option<xmpp_parsers::Jid>,
    ) -> Iq {
    let mut result = Iq::from_result(
    id,
    Some(DiscoItemsResult {
    node: None,
    items: vec![],
    }),
    );
    result.from = Some(from);
    result.to = to;
    result
  • replacement in src/xmpp/mod.rs at line 0
    [3.17][2.39289:39333]()
    use tokio::prelude::future::{self, Either};
    [3.17]
    [3.62]
    use tokio::prelude::future::{self, Either, Future};
  • edit in src/xmpp/mod.rs at line 2
    [3.90][2.39334:39414]()
    use tokio::prelude::{Future, Stream};
    use tokio_xmpp::{Client, Event, Packet};
  • replacement in src/xmpp/mod.rs at line 5
    [3.297][2.39415:39458]()
    use std::collections::{HashMap, VecDeque};
    [3.297]
    [3.3355]
    mod element_processor;
  • edit in src/xmpp/mod.rs at line 8
    [3.29460][2.39459:40248](),[2.40248][3.37511:37512](),[3.37511][3.37511:37512](),[3.37512][2.40249:47642](),[3.38899][3.37745:37746](),[2.47642][3.37745:37746](),[3.37745][3.37745:37746](),[3.37746][2.47643:55914]()
    #[derive(Default)]
    struct XmppData {
    /// known roster data
    roster: HashMap<
    xmpp_parsers::Jid,
    (
    xmpp_parsers::roster::Subscription,
    xmpp_parsers::roster::Ask,
    ),
    >,
    /// ids counter
    counter: usize,
    /// map from id of adding item to roster and jid of item
    pending_add_roster_ids: HashMap<String, xmpp_parsers::Jid>,
    /// stanzas to send
    send_queue: VecDeque<minidom::Element>,
    /// outgoing mailbox
    outgoing_mailbox: HashMap<xmpp_parsers::Jid, Vec<String>>,
    /// muc id to muc jid
    mucs: HashMap<String, xmpp_parsers::Jid>,
    }
    struct XmppState {
    client: Client,
    data: XmppData,
    }
    struct MaybeXmppConnection {
    account: std::rc::Rc<config::Account>,
    state: Option<XmppState>,
    }
    struct XmppConnection {
    account: std::rc::Rc<config::Account>,
    state: XmppState,
    }
    impl From<XmppConnection> for MaybeXmppConnection {
    fn from(from: XmppConnection) -> MaybeXmppConnection {
    MaybeXmppConnection {
    account: from.account,
    state: Some(from.state),
    }
    }
    }
    impl From<config::Account> for MaybeXmppConnection {
    fn from(from: config::Account) -> MaybeXmppConnection {
    MaybeXmppConnection {
    account: std::rc::Rc::new(from),
    state: None,
    }
    }
    }
    impl From<std::rc::Rc<config::Account>> for MaybeXmppConnection {
    fn from(from: std::rc::Rc<config::Account>) -> MaybeXmppConnection {
    MaybeXmppConnection {
    account: from,
    state: None,
    }
    }
    }
    impl MaybeXmppConnection {
    /// connects if nothing connected
    /// don't connect only if stop_future resolved
    fn connect<F>(
    self,
    stop_future: F,
    ) -> impl Future<Item = XmppConnection, Error = failure::Error>
    where
    F: future::Future + Clone + 'static,
    <F as hyper::rt::Future>::Error: Into<failure::Error> + Send,
    {
    info!("xmpp connection...");
    let MaybeXmppConnection { account, state } = self;
    if let Some(state) = state {
    Box::new(future::ok(XmppConnection { account, state }))
    as Box<dyn Future<Item = _, Error = _>>
    } else {
    Box::new(
    stop_future
    .clone()
    .select2(
    future::loop_fn(account, move |account| {
    info!("xmpp initialization...");
    let client =
    Client::new_with_jid(account.jid.clone(), &account.password);
    info!("xmpp initialized");
    let stop_future2 = stop_future.clone();
    let stop_future3 = stop_future.clone();
    let stop_future4 = stop_future.clone();
    // future to wait for online
    Box::new(
    XmppConnection {
    state: XmppState {
    client,
    data: std::default::Default::default(),
    },
    account,
    }
    .processing(XmppConnection::online, stop_future.clone())
    .map_err(|(acc, _)| acc)
    .and_then(|(conn, r)| match r {
    Ok(Either::A(_)) => future::ok(conn),
    Ok(Either::B(_)) => future::err(conn.account),
    Err(_e) => future::err(conn.account),
    })
    .and_then(|conn| conn.initial_roster(stop_future2))
    .and_then(|conn| conn.self_presence(stop_future3))
    .and_then(|conn| conn.enter_mucs(stop_future4))
    .then(|r| match r {
    Ok(conn) => future::ok(future::Loop::Break(conn)),
    Err(acc) => future::ok(future::Loop::Continue(acc)),
    }),
    )
    })
    .map_err(|_: ()| ()),
    )
    .then(|r| match r {
    Ok(Either::A((_x, _b))) => future::err(format_err!("Stop XMMP connection")),
    Ok(Either::B((x, _a))) => future::ok(x),
    Err(Either::A((e, _b))) => future::err(e.into()),
    Err(Either::B((_, _a))) => {
    future::err(format_err!("Cann't initiate XMPP connection"))
    }
    }),
    )
    }
    }
    }
    impl XmppConnection {
    /// base XMPP processing
    fn xmpp_processing(
    mut self,
    event: &Event,
    ) -> impl Future<Item = Self, Error = std::rc::Rc<config::Account>> {
    match event {
    Event::Stanza(stanza) => {
    info!("Incoming xmpp event: {:?}", stanza);
    let stanza = stanza.clone();
    use try_from::TryInto;
    if let Some(iq) = stanza.try_into().ok() as Option<xmpp_parsers::iq::Iq> {
    if let Some(id) = iq.id {
    if let Some((_, jid)) =
    self.state.data.pending_add_roster_ids.remove_entry(&id)
    {
    if let xmpp_parsers::iq::IqType::Result(None) = iq.payload {
    if self.state.data.roster.contains_key(&jid) {
    info!("Jid {} updated to roster", jid);
    } else {
    info!("Jid {} added in roster", jid);
    self.state.data.roster.insert(
    jid.clone(),
    (
    xmpp_parsers::roster::Subscription::None,
    xmpp_parsers::roster::Ask::None,
    ),
    );
    }
    self.process_jid(&jid);
    } else {
    warn!(
    "Wrong payload when adding {} to roster: {:?}",
    jid, iq.payload
    );
    }
    }
    }
    if let xmpp_parsers::iq::IqType::Set(element) = iq.payload {
    if let Some(roster) =
    element.try_into().ok() as Option<xmpp_parsers::roster::Roster>
    {
    for i in roster.items {
    if let Some(ref mut rdata) = self.state.data.roster.get_mut(&i.jid)
    {
    info!("Update {} in roster", i.jid);
    rdata.0 = i.subscription;
    rdata.1 = i.ask;
    } else {
    info!("Add {} to roster", i.jid);
    self.state
    .data
    .roster
    .insert(i.jid.clone(), (i.subscription, i.ask));
    }
    self.process_jid(&i.jid);
    }
    }
    }
    }
    future::ok(self)
    }
    Event::Online => future::ok(self),
    e => {
    warn!("Unexpected event {:?}", e);
    future::err(self.account)
    }
    }
    }
    /// process event from xmpp stream
    /// returns from future when condition met
    /// or stop future was resolved.
    /// Return item if connection was preserved or error otherwise.
    /// Second part is a state of stop_future
    fn processing<S, F, T, E>(
    self,
    stop_condition: S,
    stop_future: F,
    ) -> impl Future<
    Item = (Self, Result<Either<F, T>, E>),
    Error = (std::rc::Rc<config::Account>, Result<Either<F, T>, E>),
    >
    where
    F: Future<Item = T, Error = E> + 'static,
    S: FnMut(&mut Self, Event) -> Result<bool, ()> + 'static,
    T: 'static,
    E: 'static,
    {
    future::loop_fn(
    (self, stop_future, stop_condition),
    |(xmpp, stop_future, mut stop_condition)| {
    let XmppConnection {
    state: XmppState { client, mut data },
    account,
    } = xmpp;
    if let Some(send_element) = data.send_queue.pop_front() {
    use tokio::prelude::Sink;
    info!("Sending {:?}", send_element);
    Box::new(
    client
    .send(Packet::Stanza(send_element))
    .select2(stop_future)
    .then(move |r| match r {
    Ok(Either::A((client, b))) => {
    Box::new(future::ok(future::Loop::Continue((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    b,
    stop_condition,
    ))))
    as Box<dyn Future<Item = _, Error = _>>
    }
    Ok(Either::B((t, a))) => Box::new(a.then(|r| match r {
    Ok(client) => future::ok(future::Loop::Break((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    Ok(Either::B(t)),
    ))),
    Err(se) => {
    warn!("XMPP sending error: {}", se);
    future::err((account, Ok(Either::B(t))))
    }
    })),
    Err(Either::A((e, b))) => {
    warn!("XMPP sending error: {}", e);
    Box::new(future::err((account, Ok(Either::A(b)))))
    }
    Err(Either::B((e, a))) => Box::new(a.then(|r| match r {
    Ok(client) => future::ok(future::Loop::Break((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    Err(e),
    ))),
    Err(se) => {
    warn!("XMPP sending error: {}", se);
    future::err((account, Err(e)))
    }
    })),
    }),
    ) as Box<dyn Future<Item = _, Error = _>>
    } else {
    Box::new(
    client
    .into_future()
    .select2(stop_future)
    .then(move |r| match r {
    Ok(Either::A(((event, client), b))) => {
    if let Some(event) = event {
    let xmpp = XmppConnection {
    state: XmppState { client, data },
    account,
    };
    Box::new(xmpp.xmpp_processing(&event).then(|r| match r {
    Ok(mut xmpp) => {
    match stop_condition(&mut xmpp, event) {
    Ok(true) => future::ok(future::Loop::Break((
    xmpp,
    Ok(Either::A(b)),
    ))),
    Ok(false) => {
    future::ok(future::Loop::Continue((
    xmpp,
    b,
    stop_condition,
    )))
    }
    Err(_e) => future::err((
    xmpp.account,
    Ok(Either::A(b)),
    )),
    }
    }
    Err(account) => {
    future::err((account, Ok(Either::A(b))))
    }
    }))
    as Box<dyn Future<Item = _, Error = _>>
    } else {
    Box::new(future::err((account, Ok(Either::A(b)))))
    }
    }
    Ok(Either::B((t, a))) => {
    Box::new(if let Some(client) = a.into_inner() {
    future::ok(future::Loop::Break((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    Ok(Either::B(t)),
    )))
    } else {
    future::err((account, Ok(Either::B(t))))
    })
    }
    Err(Either::A((e, b))) => {
    warn!("XMPP error: {}", e.0);
    Box::new(future::err((account, Ok(Either::A(b)))))
    }
    Err(Either::B((e, a))) => {
    Box::new(if let Some(client) = a.into_inner() {
    future::ok(future::Loop::Break((
    XmppConnection {
    state: XmppState { client, data },
    account,
    },
    Err(e),
    )))
    } else {
    future::err((account, Err(e)))
    })
    }
    }),
    )
    }
    },
    )
    }
  • replacement in src/xmpp/mod.rs at line 9
    [3.40648][2.55915:56501]()
    /// get connection and wait for online status and set presence
    /// returns error if something went wrong and xmpp connection is broken
    fn online(&mut self, event: Event) -> Result<bool, ()> {
    match event {
    Event::Online => {
    info!("Online!");
    Ok(true)
    }
    Event::Stanza(s) => {
    warn!("Stanza before online: {:?}", s);
    Ok(false)
    }
    _ => {
    error!("Disconnected while online");
    Err(())
    }
    }
    }
    [3.40648]
    [2.56501]
    mod xmpp_connection;
    use xmpp_connection::MaybeXmppConnection;
  • replacement in src/xmpp/mod.rs at line 12
    [2.56502][2.56502:60584]()
    fn process_initial_roster(&mut self, event: Event, id_init_roster: &str) -> Result<bool, ()> {
    if let Event::Stanza(s) = event {
    use try_from::TryInto;
    match s.try_into() as Result<xmpp_parsers::iq::Iq, _> {
    Ok(iq) => {
    if let Some(id) = iq.id {
    if id == id_init_roster {
    match iq.payload {
    xmpp_parsers::iq::IqType::Error(_e) => {
    error!("Get error instead of roster");
    Err(())
    }
    xmpp_parsers::iq::IqType::Result(Some(result)) => {
    match result.try_into()
    as Result<xmpp_parsers::roster::Roster, _>
    {
    Ok(roster) => {
    self.state.data.roster.clear();
    info!("Got first roster:");
    for i in roster.items {
    info!(" >>> {:?}", i);
    self.state
    .data
    .roster
    .insert(i.jid, (i.subscription, i.ask));
    }
    Ok(true)
    }
    Err(e) => {
    error!("Cann't parse roster: {}", e);
    Err(())
    }
    }
    }
    _ => {
    error!("Unknown result of roster");
    Err(())
    }
    }
    } else {
    Ok(false)
    }
    } else {
    error!("Iq stanza without id");
    Err(())
    }
    }
    Err(_e) => Ok(false),
    }
    } else {
    error!("Wrong event while waiting roster");
    Err(())
    }
    }
    fn initial_roster<F, E>(
    self,
    stop_future: F,
    ) -> impl Future<Item = Self, Error = std::rc::Rc<config::Account>>
    where
    F: Future<Error = E> + 'static,
    E: 'static,
    {
    let XmppConnection {
    account,
    state: XmppState { client, mut data },
    } = self;
    use tokio::prelude::Sink;
    data.counter += 1;
    let id_init_roster = format!("id_init_roster{}", data.counter);
    let get_roster = stanzas::make_get_roster(&id_init_roster);
    let account2 = account.clone();
    info!("Quering roster... {:?}", get_roster);
    client
    .send(Packet::Stanza(get_roster))
    .map_err(move |e| {
    error!("Error on querying roster: {}", e);
    account2
    })
    .and_then(move |client| {
    XmppConnection {
    state: XmppState { client, data },
    account,
    }
    .processing(
    move |conn, event| conn.process_initial_roster(event, &id_init_roster),
    stop_future,
    )
    .map_err(|(account, _)| account)
    .and_then(|(conn, r)| match r {
    Ok(Either::A(_)) => future::ok(conn),
    Ok(Either::B(_)) => future::err(conn.account),
    Err(_e) => future::err(conn.account),
    })
    })
    }
    [2.56502]
    [2.60584]
    pub use xmpp_connection::XmppCommand;
  • edit in src/xmpp/mod.rs at line 14
    [2.60585][2.60585:67188]()
    fn self_presence<F, E>(
    self,
    stop_future: F,
    ) -> impl Future<Item = Self, Error = std::rc::Rc<config::Account>>
    where
    F: Future<Error = E> + 'static,
    E: Into<failure::Error> + 'static,
    {
    let XmppConnection {
    account,
    state: XmppState { client, data },
    } = self;
    use tokio::prelude::Sink;
    let presence = stanzas::make_presence(&account);
    let account2 = account.clone();
    info!("Sending presence... {:?}", presence);
    client
    .send(Packet::Stanza(presence))
    .map_err(|e| {
    error!("Error on send self-presence: {}", e);
    account2
    })
    .and_then(move |client| {
    XmppConnection {
    state: XmppState { client, data },
    account,
    }
    .processing(
    move |conn, event| {
    if let Event::Stanza(s) = event {
    if s.name() == "presence"
    && s.attr("from").map_or(false, |f| f == conn.account.jid)
    && s.attr("to").map_or(false, |f| f == conn.account.jid)
    {
    Ok(true)
    } else {
    Ok(false)
    }
    } else {
    error!("Wrong event while waiting self-presence");
    Err(())
    }
    },
    stop_future,
    )
    .map_err(|(account, _)| account)
    .and_then(|(conn, r)| match r {
    Ok(Either::A(_)) => future::ok(conn),
    Ok(Either::B(_)) => future::err(conn.account),
    Err(_e) => future::err(conn.account),
    })
    })
    }
    fn process_jid(&mut self, xmpp_to: &xmpp_parsers::Jid) {
    if let Some(ref mut mailbox) = self.state.data.outgoing_mailbox.get_mut(xmpp_to) {
    if !mailbox.is_empty() {
    if let Some(ref mut rdata) = self.state.data.roster.get_mut(xmpp_to) {
    info!("Jid {} in roster", xmpp_to);
    let sub_to = match rdata.0 {
    xmpp_parsers::roster::Subscription::To => true,
    xmpp_parsers::roster::Subscription::Both => true,
    _ => false,
    };
    if sub_to {
    info!("Subscribed to {}", xmpp_to);
    self.state.data.send_queue.extend(
    mailbox.drain(..).map(|message| {
    stanzas::make_chat_message(xmpp_to.clone(), message)
    }),
    );
    } else if rdata.1 == xmpp_parsers::roster::Ask::None {
    info!("Not subscribed to {}", xmpp_to);
    self.state
    .data
    .send_queue
    .push_back(stanzas::make_ask_subscribe(xmpp_to.clone()));
    }
    } else {
    info!("Jid {} not in roster", xmpp_to);
    self.state.data.counter += 1;
    let id_add_roster = format!("id_add_roster{}", self.state.data.counter);
    let add_roster = stanzas::make_add_roster(&id_add_roster, xmpp_to.clone());
    self.state
    .data
    .pending_add_roster_ids
    .insert(id_add_roster, xmpp_to.clone());
    info!("Adding jid to roster... {:?}", add_roster);
    self.state.data.send_queue.push_back(add_roster);
    }
    }
    }
    }
    fn process_command(&mut self, cmd: XmppCommand) {
    info!("Got command");
    match cmd {
    XmppCommand::Chat { xmpp_to, message } => {
    self.state
    .data
    .outgoing_mailbox
    .entry(xmpp_to.clone())
    .or_default()
    .push(message);
    self.process_jid(&xmpp_to);
    }
    XmppCommand::Chatroom { muc_id, message } => {
    if let Some(muc) = self.state.data.mucs.get(&muc_id) {
    self.state
    .data
    .send_queue
    .push_back(stanzas::make_muc_message(muc.clone(), message));
    } else {
    error!("Not found MUC {}", muc_id);
    }
    }
    }
    }
    fn enter_mucs<F, E>(
    self,
    _stop_future: F,
    ) -> impl Future<Item = Self, Error = std::rc::Rc<config::Account>>
    where
    F: Future<Error = E> + 'static,
    E: Into<failure::Error> + 'static,
    {
    let XmppConnection { account, state } = self;
    let account2 = account.clone();
    let account3 = account.clone();
    stream::iter_ok(account.chatrooms.clone())
    .fold(state, move |XmppState { client, mut data }, muc_jid| {
    data.counter += 1;
    let id_muc_presence = format!("id_muc_presence{}", data.counter);
    let muc_presence = stanzas::make_muc_presence(
    &id_muc_presence,
    account2.jid.clone(),
    muc_jid.1.clone(),
    );
    info!("Sending muc presence... {:?}", muc_presence);
    let account4 = account2.clone();
    use tokio::prelude::Sink;
    client
    .send(Packet::Stanza(muc_presence))
    .map_err(|e| {
    error!("Error on send muc presence: {}", e);
    account4
    })
    .and_then(|client| {
    data.mucs.insert(muc_jid.0, muc_jid.1);
    future::ok(XmppState { client, data })
    })
    })
    .map(|state| XmppConnection {
    account: account3,
    state,
    })
    }
    }
    #[derive(Debug)]
    pub enum XmppCommand {
    Chat {
    xmpp_to: xmpp_parsers::Jid,
    message: String,
    },
    Chatroom {
    muc_id: String,
    message: String,
    },
    }
  • replacement in src/xmpp/mod.rs at line 61
    [3.40205][2.67189:67274]()
    future::err(format_err!("Command receiver is gone"))
    [3.40205]
    [3.40349]
    error!("Command receiver is gone");
    future::ok(future::Loop::Break(Some(conn)))
  • replacement in src/xmpp/mod.rs at line 75
    [3.40881][2.67275:67343]()
    future::ok(future::Loop::Break(()))
    [3.40881]
    [3.40957]
    future::ok(future::Loop::Break(Some(conn)))
  • replacement in src/xmpp/mod.rs at line 78
    [3.41013][2.67344:67434]()
    Err(_) => future::err(format_err!("Command receiver is broken")),
    [3.41013]
    [3.41213]
    Err(_) => {
    error!("Command receiver is broken");
    future::ok(future::Loop::Break(Some(conn)))
    }
  • replacement in src/xmpp/mod.rs at line 104
    [3.42353][2.67435:67503]()
    future::ok(future::Loop::Break(()))
    [3.42353]
    [3.42423]
    future::ok(future::Loop::Break(None))
  • edit in src/xmpp/mod.rs at line 111
    [3.42622]
    [3.42838]
    })
    .and_then(|opt_conn| {
    if let Some(conn) = opt_conn {
    Box::new(conn.shutdown()) as Box<dyn Future<Item = (), Error = _>>
    } else {
    Box::new(future::ok(()))
    }
  • replacement in src/xmpp/element_processor.rs at line 0
    [3.11301][2.67504:68601]()
    type Func<S, T, E> = dyn Fn(&mut S, E) -> T + Sync;
    pub struct Processor<S: 'static, T: 'static, E: Clone + 'static> {
    processors: Vec<Box<Func<S, Option<T>, E>>>,
    default: &'static Func<S, T, E>,
    }
    impl<S: 'static, T: 'static, E: Clone + 'static> Processor<S, T, E> {
    pub fn new<F>(f: &'static F) -> Processor<S, T, E>
    where
    F: Fn(&mut S, E) -> T + Sync + 'static,
    {
    Processor {
    processors: vec![],
    default: f,
    }
    }
    pub fn register<F, A>(&mut self, f: &'static F)
    where
    F: Fn(&mut S, A) -> T + Sync + 'static,
    A: std::convert::TryFrom<E>,
    {
    self.processors.push(Box::new(move |s, e: E| {
    use std::convert::TryInto;
    (e.try_into().ok() as Option<A>).map(|a| f(s, a))
    }));
    }
    pub fn process(&self, s: &mut S, e: E) -> T {
    for processor in self.processors.iter() {
    match processor(s, e.clone()) {
    Some(t) => return t,
    None => continue,
    }
    }
    (*self.default)(s, e)
    }
    }
    [3.11301]
    type Func<S, T, E> = dyn Fn(&mut S, E) -> T + Sync;
    pub struct Processor<S: 'static, T: 'static, E: Clone + 'static> {
    processors: Vec<Box<Func<S, Option<T>, E>>>,
    default: &'static Func<S, T, E>,
    }
    impl<S: 'static, T: 'static, E: Clone + 'static> Processor<S, T, E> {
    pub fn new<F>(f: &'static F) -> Processor<S, T, E>
    where
    F: Fn(&mut S, E) -> T + Sync + 'static,
    {
    Processor {
    processors: vec![],
    default: f,
    }
    }
    pub fn register<F, A>(&mut self, f: &'static F)
    where
    F: Fn(&mut S, A) -> T + Sync + 'static,
    A: std::convert::TryFrom<E>,
    {
    self.processors.push(Box::new(move |s, e: E| {
    use std::convert::TryInto;
    (e.try_into().ok() as Option<A>).map(|a| f(s, a))
    }));
    }
    pub fn process(&self, s: &mut S, e: E) -> T {
    for processor in self.processors.iter() {
    match processor(s, e.clone()) {
    Some(t) => return t,
    None => continue,
    }
    }
    (*self.default)(s, e)
    }
    }
  • edit in src/main.rs at line 21
    [3.41232]
    [3.41232]
    #[macro_use]
    extern crate lazy_static;
  • replacement in src/main.rs at line 42
    [3.44414][2.68602:68633]()
    .map_err(|e| e.into())
    [3.44414]
    [3.44457]
    .map_err(std::convert::Into::into)
  • replacement in src/main.rs at line 68
    [3.45312][2.68634:68871]()
    .map_err(|e| e.into())
    .and_then(|s| {
    std::str::FromStr::from_str(s)
    .map_err(|e: xmpp_parsers::JidParseError| e.into())
    })
    [3.45312]
    [3.45467]
    .map_err(std::convert::Into::into)
    .and_then(|s| std::str::FromStr::from_str(s).map_err(std::convert::Into::into))
  • replacement in src/main.rs at line 76
    [3.45579][2.68872:68929]()
    .map(|h| h.to_str().map(|s| s.to_string()));
    [3.45579]
    [3.45651]
    .map(|h| h.to_str().map(std::string::ToString::to_string));
  • replacement in src/main.rs at line 85
    [3.46029][2.68930:68978]()
    .map_err(|e| e.into()),
    [3.46029]
    [3.46089]
    .map_err(std::convert::Into::into),
  • replacement in src/main.rs at line 113
    [3.47605][2.68979:69035]()
    .map_err(|e| e.into()),
    [3.47605]
    [3.47673]
    .map_err(std::convert::Into::into),
  • replacement in src/main.rs at line 121
    [3.48028][2.69036:69092]()
    .map_err(|e| e.into()),
    [3.48028]
    [3.48096]
    .map_err(std::convert::Into::into),
  • replacement in src/main.rs at line 152
    [3.49756][2.69093:69149]()
    .map_err(|e| e.into()),
    [3.49756]
    [3.49824]
    .map_err(std::convert::Into::into),
  • replacement in src/main.rs at line 160
    [3.50179][2.69150:69206]()
    .map_err(|e| e.into()),
    [3.50179]
    [3.50247]
    .map_err(std::convert::Into::into),
  • replacement in src/main.rs at line 172
    [3.50816][2.69207:69255]()
    .map_err(|e| e.into()),
    [3.50816]
    [3.50876]
    .map_err(std::convert::Into::into),
  • replacement in src/main.rs at line 231
    [3.49740][2.69256:69300]()
    .serve(MakeServiceCmd { cmd_send })
    [3.49740]
    [3.51863]
    .serve(MakeServiceCmd {
    cmd_send: cmd_send.clone(),
    })
  • edit in src/main.rs at line 239
    [3.50000]
    [3.50812]
    if let Some(ping) = config.account.ping {
    let ping = tokio::timer::Interval::new_interval(std::time::Duration::from_secs(ping));
    rt.spawn(
    ping.map_err(|e| {
    error!("Ping error: {}", e);
    })
    .for_each(move |_| {
    cmd_send
    .clone()
    .send(XmppCommand::Ping)
    .map_err(|e| {
    error!("Ping command error: {}", e);
    })
    .map(|_| ())
    })
    .select(
    ctrl_c
    .clone()
    .map(|_| ())
    .map_err(|e| error!("ping server error: {}", e)),
    )
    .map(|_| ())
    .map_err(|_| ()),
    );
    }
  • edit in src/config.rs at line 0
    [36.1396]
    [36.1397]
    use std::collections::HashMap;
  • edit in src/config.rs at line 10
    [36.1549]
    [36.1549]
    #[serde(default, deserialize_with = "deserialize_jid_map")]
    pub chatrooms: HashMap<String, xmpp_parsers::Jid>,
    pub ping: Option<u64>,
  • edit in src/config.rs at line 39
    [3.53506]
    [36.1943]
    }
    fn deserialize_jid_map<'de, D>(
    deserializer: D,
    ) -> Result<HashMap<String, xmpp_parsers::Jid>, D::Error>
    where
    D: serde::Deserializer<'de>,
    {
    use serde::Deserialize;
    let s = HashMap::<String, String>::deserialize(deserializer)?;
    let size = s.len();
    s.into_iter()
    .map(|(k, v)| (k, std::str::FromStr::from_str(&v)))
    .take_while(|(_k, r)| r.is_ok())
    .fold(Ok(HashMap::with_capacity(size)), |res, (k, r)| match res {
    Ok(mut res) => match r {
    Ok(v) => {
    res.insert(k, v);
    Ok(res)
    }
    Err(e) => Err(e),
    },
    Err(e) => Err(e),
    })
    .map_err(serde::de::Error::custom)
  • edit in README.md at line 9
    [3.39360]
    [3.39360]
    #### XEP-0030: Service Discovery
    Answers to `http://jabber.org/protocol/disco#info` query.
    Answers to `http://jabber.org/protocol/disco#items` query.
  • replacement in README.md at line 21
    [3.39486][2.69417:69491]()
    Ansers empty commands list. (Awaiting for implementation in xmpp_parser).
    [3.39486]
    [3.39537]
    Answers empty commands list. (Awaiting for implementation in xmpp_parser).
    #### XEP-0092: Software Version
    Answers version.
  • replacement in Cargo.toml at line 15
    [3.52750][2.69554:69567]()
    toml = "0.4"
    [3.52750]
    [3.52763]
    toml = "0.5"
  • replacement in Cargo.toml at line 21
    [3.54573][2.69568:69592]()
    xmpp-parsers = "0.12.2"
    [3.54573]
    [3.54595]
    xmpp-parsers = "0.13"
  • replacement in Cargo.toml at line 23
    [3.54630][2.69593:69628]()
    try_from = "=0.3.2" # xmpp-parsers
    [3.54630]
    lazy_static = "1.3.0" # ToDo: remove after const fn will be powerfull enough
  • edit in Cargo.lock at line 0
    [3.12201]
    [3.54799]
    # This file is automatically @generated by Cargo.
    # It is not intended for manual editing.
  • replacement in Cargo.lock at line 7
    [3.54933][2.69629:69701]()
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.54933]
    [3.55005]
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 12
    [3.53235][2.69702:69720]()
    version = "0.6.9"
    [3.53235]
    [3.53253]
    version = "0.7.3"
  • replacement in Cargo.lock at line 15
    [3.53335][2.69721:69794]()
    "memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.53335]
    [3.53408]
    "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 23
    [3.53543][2.69795:69868]()
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.53543]
    [3.53616]
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 28
    [3.53649][2.69869:69887]()
    version = "0.3.7"
    [3.53649]
    [3.46847]
    version = "0.3.10"
  • replacement in Cargo.lock at line 44
    [3.54069][2.69888:69960]()
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.54069]
    [3.54141]
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 46
    [3.54215][2.69961:70034]()
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.54215]
    [3.54288]
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 56
    [3.54435][2.70035:70054]()
    version = "0.3.13"
    [3.54435]
    [3.54454]
    version = "0.3.15"
  • replacement in Cargo.lock at line 61
    [3.55649][2.70055:70355]()
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.55649]
    [3.54991]
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    "rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 72
    [3.55130][2.70356:70498]()
    "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.55130]
    [3.55272]
    "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 102
    [3.56068][2.70499:70517]()
    version = "0.7.2"
    [3.56068]
    [3.56538]
    version = "0.7.0"
  • replacement in Cargo.lock at line 131
    [3.56958][2.70518:70537]()
    version = "0.4.11"
    [3.56958]
    [3.56977]
    version = "0.4.12"
  • replacement in Cargo.lock at line 145
    [3.57344][2.70538:70557]()
    version = "1.0.29"
    [3.57344]
    [3.57363]
    version = "1.0.35"
  • replacement in Cargo.lock at line 150
    [3.57457][2.70558:70576]()
    version = "0.1.6"
    [3.57457]
    [3.57475]
    version = "0.1.7"
  • replacement in Cargo.lock at line 165
    [3.57926][2.70577:70596]()
    version = "2.32.0"
    [3.57926]
    [3.57945]
    version = "2.33.0"
  • replacement in Cargo.lock at line 171
    [3.58251][2.70597:70746]()
    "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.58251]
    [3.58400]
    "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 191
    [3.58988][2.70747:70819]()
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.58988]
    [3.59060]
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • edit in Cargo.lock at line 197
    [3.59122][3.59122:59204](),[3.59122][3.59122:59204](),[3.59122][3.59122:59204](),[3.59122][3.59122:59204](),[3.59204][2.70820:70892](),[3.57647][3.59276:59291](),[3.49635][3.59276:59291](),[2.70892][3.59276:59291](),[3.59276][3.59276:59291](),[3.59291][2.70893:70930](),[3.57666][3.59334:59416](),[3.49654][3.59334:59416](),[2.70930][3.59334:59416](),[3.59334][3.59334:59416](),[3.59416][2.70931:71170](),[2.71170][3.57667:57831](),[3.59416][3.57667:57831](),[3.57831][2.71171:71402](),[3.57831][3.59580:59595](),[3.49819][3.59580:59595](),[2.71402][3.59580:59595](),[3.59580][3.59580:59595](),[3.59595][2.71403:71448]()
    source = "registry+https://github.com/rust-lang/crates.io-index"
    dependencies = [
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    ]
    [[package]]
    name = "crossbeam"
    version = "0.6.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    dependencies = [
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
    "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
    "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
    "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
    "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
    ]
    [[package]]
    name = "crossbeam-channel"
    version = "0.3.8"
  • replacement in Cargo.lock at line 199
    [3.58000][3.58000:58082](),[3.58082][2.71449:71524]()
    "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
    "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.59720]
    [3.60182]
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 204
    [2.71550][2.71550:71568]()
    version = "0.6.3"
    [2.71550]
    [3.60240]
    version = "0.7.1"
  • replacement in Cargo.lock at line 217
    [2.71853][2.71853:71926]()
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [2.71853]
    [2.71926]
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 219
    [2.72008][2.72008:72086]()
    "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
    [2.72008]
    [2.72086]
    "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • edit in Cargo.lock at line 225
    [2.72254]
    [3.58307]
    name = "crossbeam-queue"
    version = "0.1.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    dependencies = [
    "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
    ]
    [[package]]
  • replacement in Cargo.lock at line 237
    [3.60544][2.72255:72406]()
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.60544]
    [3.60695]
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 270
    [3.61585][2.72407:72426]()
    version = "0.8.15"
    [3.61585]
    [3.61604]
    version = "0.8.17"
  • replacement in Cargo.lock at line 273
    [3.61686][2.72427:72500]()
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.61686]
    [3.61759]
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 278
    [3.61794][2.72501:72519]()
    version = "0.6.0"
    [3.61794]
    [3.61812]
    version = "0.6.1"
  • replacement in Cargo.lock at line 284
    [3.59057][2.72520:72592]()
    "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.59057]
    [3.62184]
    "regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 293
    [3.62396][2.72593:72670]()
    "backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.62396]
    [3.62473]
    "backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 301
    [3.62605][2.72671:72748]()
    "backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.62605]
    [3.59304]
    "backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 311
    [3.59484][2.72749:72894]()
    "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.59484]
    [3.59629]
    "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 364
    [3.64522][2.72895:72983]()
    "new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.64522]
    [3.64610]
    "new_debug_unreachable 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 369
    [3.64642][2.72984:73003]()
    version = "0.1.25"
    [3.64642]
    [3.64661]
    version = "0.1.26"
  • replacement in Cargo.lock at line 377
    [3.64864][2.73004:73154]()
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.64864]
    [3.65015]
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 391
    [3.65256][2.73155:73174]()
    version = "0.1.16"
    [3.65256]
    [3.65275]
    version = "0.1.18"
  • replacement in Cargo.lock at line 395
    [3.60207][2.73175:73248]()
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.60207]
    [3.65506]
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 397
    [3.65576][2.73249:73396]()
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    "http 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.65576]
    [3.65723]
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 403
    [3.60643][2.73397:73473]()
    "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.60643]
    [3.60719]
    "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 420
    [3.66500][2.73474:73546]()
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.66500]
    [3.66572]
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 426
    [3.66675][2.73547:73566]()
    version = "0.1.15"
    [3.66675]
    [3.66694]
    version = "0.1.17"
  • replacement in Cargo.lock at line 429
    [3.66776][2.73567:73640]()
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.66776]
    [3.66849]
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 449
    [3.67346][2.73641:73661]()
    version = "0.12.23"
    [3.67346]
    [3.67366]
    version = "0.12.27"
  • replacement in Cargo.lock at line 452
    [3.67448][2.73662:73810]()
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.67448]
    [3.67596]
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 455
    [3.67678][2.73811:73953]()
    "h2 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
    "http 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.67678]
    [3.67820]
    "h2 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
    "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
  • edit in Cargo.lock at line 462
    [3.68180]
    [3.61649]
    "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 464
    [3.61721][2.73954:74264]()
    "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.61721]
    [3.62031]
    "tokio 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 469
    [3.62107][2.74265:74349]()
    "tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.62107]
    [3.62191]
    "tokio-threadpool 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 494
    [3.69566][2.74350:74422]()
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.69566]
    [3.69638]
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 506
    [3.70073][2.74423:74496]()
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.70073]
    [3.70146]
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 541
    [3.71124][2.74497:74515]()
    version = "1.2.0"
    [3.71124]
    [3.71142]
    version = "1.3.0"
  • replacement in Cargo.lock at line 551
    [3.71348][2.74516:74535]()
    version = "0.2.48"
    [3.71348]
    [3.71367]
    version = "0.2.51"
  • replacement in Cargo.lock at line 556
    [3.71470][2.74536:74554]()
    version = "0.4.2"
    [3.71470]
    [3.71488]
    version = "0.5.2"
  • replacement in Cargo.lock at line 573
    [3.54885][2.74555:74628]()
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.54885]
    [3.72039]
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 578
    [3.72073][2.74629:74647]()
    version = "0.1.1"
    [3.72073]
    [3.72091]
    version = "0.1.2"
  • replacement in Cargo.lock at line 581
    [3.72173][2.74648:74730]()
    "linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.72173]
    [3.72255]
    "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 596
    [3.63314][2.74731:74962]()
    "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)",
    "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)",
    "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.63314]
    [3.72881]
    "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
    "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
    "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 611
    [3.73265][2.74963:74981]()
    version = "2.1.3"
    [3.73265]
    [3.73283]
    version = "2.2.0"
  • edit in Cargo.lock at line 613
    [3.73348][2.74982:75146]()
    dependencies = [
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    ]
  • replacement in Cargo.lock at line 626
    [3.63815][2.75147:75224]()
    "quick-xml 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.63815]
    [3.73826]
    "quick-xml 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 639
    [3.63968][2.75225:75297]()
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.63968]
    [3.64040]
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 653
    [3.74980][2.75298:75370]()
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.74980]
    [3.75052]
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 673
    [3.75688][2.75371:75521]()
    "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.75688]
    [3.64406]
    "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 676
    [3.64476][2.75522:75598]()
    "openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.64476]
    [3.75984]
    "openssl 0.10.20 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 678
    [3.76064][2.75599:75754]()
    "openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)",
    "schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.76064]
    [3.64708]
    "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)",
    "schannel 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 682
    [3.64882][2.75755:75830]()
    "tempfile 3.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.64882]
    [3.76468]
    "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 690
    [3.76598][2.75831:76049]()
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.76598]
    [3.76816]
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 697
    [3.76862][2.76050:76068]()
    version = "1.0.1"
    [3.76862]
    [3.76880]
    version = "1.0.3"
  • edit in Cargo.lock at line 699
    [3.76945][2.76069:76166]()
    dependencies = [
    "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
    ]
  • replacement in Cargo.lock at line 720
    [3.77419][2.76167:76185]()
    version = "1.9.0"
    [3.77419]
    [3.77438]
    version = "1.10.0"
  • replacement in Cargo.lock at line 723
    [3.77520][2.76186:76258]()
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.77520]
    [3.77592]
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 733
    [3.77742][2.76259:76279]()
    version = "0.10.16"
    [3.77742]
    [3.77762]
    version = "0.10.20"
  • replacement in Cargo.lock at line 737
    [3.77919][2.76280:76353]()
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.77919]
    [3.77992]
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 739
    [3.78072][2.76354:76583]()
    "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    "openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.78072]
    [3.78301]
    "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 751
    [3.78456][2.76584:76603]()
    version = "0.9.40"
    [3.78456]
    [3.78475]
    version = "0.9.43"
  • replacement in Cargo.lock at line 754
    [3.78557][2.76604:76746]()
    "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.78557]
    [3.78699]
    "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • edit in Cargo.lock at line 757
    [3.78777]
    [3.78857]
    "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 783
    [3.79584][2.76747:76819]()
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.79584]
    [3.66285]
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 786
    [3.79807][2.76820:76968]()
    "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.79807]
    [3.66505]
    "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 863
    [3.81969][2.76969:76988]()
    version = "0.13.2"
    [3.81969]
    [3.81988]
    version = "0.13.3"
  • replacement in Cargo.lock at line 866
    [3.82070][2.76989:77068]()
    "encoding_rs 0.8.15 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.82070]
    [3.67378]
    "encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 869
    [3.67522][2.77069:77142]()
    "memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.67522]
    [3.82366]
    "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 879
    [3.82508][2.77143:77162]()
    version = "0.6.11"
    [3.82508]
    [3.82527]
    version = "0.6.12"
  • replacement in Cargo.lock at line 892
    [3.67870][2.77163:77235]()
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.67870]
    [3.67942]
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 894
    [3.68018][2.77236:77309]()
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.68018]
    [3.83193]
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 903
    [3.68266][2.77310:77382]()
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.68266]
    [3.68338]
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 909
    [3.68721][2.77383:77532]()
    "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
    "rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.68721]
    [3.68870]
    "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
    "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 912
    [3.68950][2.77533:77606]()
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.68950]
    [3.69023]
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 958
    [3.69961][2.77607:77679]()
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.69961]
    [3.70033]
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 960
    [3.70109][2.77680:77753]()
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.70109]
    [3.70182]
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 965
    [3.70214][2.77754:77772]()
    version = "0.1.2"
    [3.70214]
    [3.70232]
    version = "0.1.3"
  • replacement in Cargo.lock at line 970
    [3.70469][2.77773:77845]()
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.70469]
    [3.70541]
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 973
    [3.70690][2.77846:77919]()
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.70690]
    [3.70763]
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 978
    [3.70796][2.77920:77938]()
    version = "0.1.1"
    [3.70796]
    [3.70814]
    version = "0.1.2"
  • replacement in Cargo.lock at line 981
    [3.70896][2.77939:78095]()
    "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
    "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.70896]
    [3.71046]
    "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
    "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1003
    [3.86863][2.78096:78115]()
    version = "0.1.51"
    [3.86863]
    [3.86882]
    version = "0.1.54"
  • replacement in Cargo.lock at line 1011
    [3.87083][2.78116:78197]()
    "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.87083]
    [3.87164]
    "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1016
    [3.87194][2.78198:78216]()
    version = "1.1.0"
    [3.87194]
    [3.87212]
    version = "1.1.5"
  • replacement in Cargo.lock at line 1019
    [3.87294][2.78217:78448]()
    "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
    "memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
    "regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.87294]
    [3.87525]
    "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
    "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1028
    [3.87719][2.78449:78467]()
    version = "0.6.5"
    [3.87719]
    [3.87737]
    version = "0.6.6"
  • replacement in Cargo.lock at line 1039
    [3.88033][2.78468:78541]()
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.88033]
    [3.88106]
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1053
    [3.88434][2.78542:78561]()
    version = "0.1.13"
    [3.88434]
    [3.88453]
    version = "0.1.14"
  • replacement in Cargo.lock at line 1077
    [3.72302][2.78562:78636]()
    "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.72302]
    [3.72376]
    "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1084
    [3.89433][2.78637:78656]()
    version = "0.1.14"
    [3.89433]
    [3.89452]
    version = "0.1.15"
  • replacement in Cargo.lock at line 1087
    [3.89534][2.78657:78808]()
    "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.89534]
    [3.89685]
    "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1103
    [3.90112][2.78809:78881]()
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.90112]
    [3.72783]
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1114
    [3.90585][2.78882:78954]()
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.90585]
    [3.90657]
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1134
    [3.91027][2.78955:79104]()
    "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.91027]
    [3.73194]
    "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1137
    [3.73268][2.79105:79179]()
    "hyper 0.12.23 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.73268]
    [3.73420]
    "hyper 0.12.27 (registry+https://github.com/rust-lang/crates.io-index)",
    "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1141
    [3.73565][2.79180:79406]()
    "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)",
    "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.73565]
    [3.91695]
    "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
    "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1147
    [3.73948][2.79407:79634]()
    "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
    "try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
    "xmpp-parsers 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.73948]
    [3.92082]
    "toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "xmpp-parsers 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1153
    [3.92112][2.79635:79654]()
    version = "1.0.87"
    [3.92112]
    [3.92131]
    version = "1.0.90"
  • replacement in Cargo.lock at line 1158
    [3.92231][2.79655:79674]()
    version = "1.0.87"
    [3.92231]
    [3.92250]
    version = "1.0.90"
  • replacement in Cargo.lock at line 1162
    [3.74219][2.79675:79820]()
    "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.74219]
    [3.92556]
    "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1168
    [3.92591][2.79821:79840]()
    version = "1.0.38"
    [3.92591]
    [3.92610]
    version = "1.0.39"
  • replacement in Cargo.lock at line 1173
    [3.74455][2.79841:79914]()
    "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.74455]
    [3.92906]
    "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1181
    [3.93036][2.79915:79994]()
    "block-buffer 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.93036]
    [3.74627]
    "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1192
    [3.93472][2.79995:80074]()
    "block-buffer 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.93472]
    [3.74879]
    "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1203
    [3.93908][2.80075:80154]()
    "block-buffer 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.93908]
    [3.75131]
    "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1212
    [3.94325][2.80155:80173]()
    version = "0.1.7"
    [3.94325]
    [3.94343]
    version = "0.1.8"
  • replacement in Cargo.lock at line 1215
    [3.94425][2.80174:80321]()
    "arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.94425]
    [3.94573]
    "arc-swap 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1231
    [3.94831][2.80322:80340]()
    version = "0.6.8"
    [3.94831]
    [3.94849]
    version = "0.6.9"
  • edit in Cargo.lock at line 1233
    [3.94914][2.80341:80438]()
    dependencies = [
    "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
    ]
  • replacement in Cargo.lock at line 1239
    [3.95044][2.80439:80738]()
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.95044]
    [3.95343]
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1260
    [3.95716][2.80739:80905]()
    "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.95716]
    [3.76053]
    "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "new_debug_unreachable 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1264
    [3.96043][2.80906:80979]()
    "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.96043]
    [3.96116]
    "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1277
    [3.76444][2.80980:81053]()
    "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.76444]
    [3.96745]
    "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1288
    [3.96987][2.81054:81072]()
    version = "0.7.0"
    [3.96987]
    [3.76536]
    version = "0.8.0"
  • replacement in Cargo.lock at line 1308
    [3.97562][2.81073:81093]()
    version = "0.15.26"
    [3.97562]
    [3.97582]
    version = "0.15.30"
  • replacement in Cargo.lock at line 1312
    [3.76749][2.81094:81167]()
    "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.76749]
    [3.97816]
    "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1330
    [3.76922][2.81168:81313]()
    "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.76922]
    [3.98465]
    "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1337
    [3.98576][2.81314:81332]()
    version = "3.0.6"
    [3.98576]
    [3.98594]
    version = "3.0.7"
  • replacement in Cargo.lock at line 1340
    [3.98676][2.81333:81478]()
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.98676]
    [3.77232]
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1343
    [3.77303][2.81479:81560]()
    "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.77303]
    [3.98973]
    "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1345
    [3.99054][2.81561:81634]()
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.99054]
    [3.99127]
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1371
    [3.99813][2.81635:81788]()
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.99813]
    [3.99966]
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1378
    [3.100079][2.81789:81808]()
    version = "0.10.0"
    [3.100079]
    [3.100098]
    version = "0.11.0"
  • replacement in Cargo.lock at line 1389
    [3.100397][2.81809:81887]()
    "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.100397]
    [3.100475]
    "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1397
    [3.100605][2.81888:82114]()
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.100605]
    [3.100831]
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
    "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1404
    [3.100861][2.82115:82134]()
    version = "0.1.15"
    [3.100861]
    [3.100880]
    version = "0.1.18"
  • replacement in Cargo.lock at line 1407
    [3.100962][2.82135:82283]()
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.100962]
    [3.101110]
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1410
    [3.101181][2.82284:82359]()
    "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.101181]
    [3.101257]
    "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1412
    [3.101335][2.82360:82836]()
    "tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-fs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-sync 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.101335]
    [3.78773]
    "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-sync 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1419
    [3.78849][2.82837:82921]()
    "tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.78849]
    [3.78933]
    "tokio-threadpool 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
  • edit in Cargo.lock at line 1421
    [3.79012]
    [3.79095]
    "tokio-trace-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1431
    [3.102423][2.82922:82997]()
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.102423]
    [3.102498]
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1439
    [3.102634][2.82998:83222]()
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.102634]
    [3.102858]
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1446
    [3.102903][2.83223:83241]()
    version = "0.1.4"
    [3.102903]
    [3.102921]
    version = "0.1.6"
  • replacement in Cargo.lock at line 1449
    [3.103003][2.83242:83398]()
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.103003]
    [3.103159]
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1455
    [3.103198][2.83399:83417]()
    version = "0.1.6"
    [3.103198]
    [3.103216]
    version = "0.1.7"
  • replacement in Cargo.lock at line 1459
    [3.79826][2.83418:83493]()
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.79826]
    [3.103455]
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1464
    [3.103488][2.83494:83512]()
    version = "0.1.5"
    [3.103488]
    [3.103506]
    version = "0.1.6"
  • replacement in Cargo.lock at line 1467
    [3.103588][2.83513:83748]()
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.103588]
    [3.103823]
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-threadpool 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1474
    [3.103856][2.83749:83768]()
    version = "0.1.11"
    [3.103856]
    [3.103875]
    version = "0.1.12"
  • replacement in Cargo.lock at line 1477
    [3.103957][2.83769:83917]()
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.103957]
    [3.80325]
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1484
    [3.104213][2.83918:83936]()
    version = "0.1.8"
    [3.104213]
    [3.104231]
    version = "0.1.9"
  • replacement in Cargo.lock at line 1488
    [3.80497][2.83937:84090]()
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.80497]
    [3.80650]
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1492
    [3.104689][2.84091:84166]()
    "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.104689]
    [3.80797]
    "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1495
    [3.80946][2.84167:84324]()
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.80946]
    [3.105148]
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-sync 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1505
    [3.105285][2.84325:84472]()
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.105285]
    [3.105432]
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1509
    [3.105577][2.84473:84861]()
    "signal-hook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.105577]
    [3.81736]
    "signal-hook 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1518
    [3.81771][2.84862:84880]()
    version = "0.1.1"
    [3.81771]
    [3.81789]
    version = "0.1.4"
  • replacement in Cargo.lock at line 1521
    [3.81871][2.84881:84956]()
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.81871]
    [3.105965]
    "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1530
    [3.106379][2.84957:85105]()
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.106379]
    [3.106527]
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1534
    [3.106670][2.85106:85262]()
    "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.106670]
    [3.106826]
    "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1540
    [3.106867][2.85263:85282]()
    version = "0.1.11"
    [3.106867]
    [3.106886]
    version = "0.1.13"
  • replacement in Cargo.lock at line 1543
    [3.106968][2.85283:85525]()
    "crossbeam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
    "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.106968]
    [3.82526]
    "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
    "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1546
    [3.82608][2.85526:85601]()
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.82608]
    [3.82683]
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1548
    [3.82753][2.85602:85677]()
    "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.82753]
    [3.82829]
    "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1551
    [3.82971][2.85678:85759]()
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.82971]
    [3.107658]
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1560
    [3.83155][2.85760:85835]()
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.83155]
    [3.83230]
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1562
    [3.83301][2.85836:85917]()
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.83301]
    [3.108104]
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1570
    [3.108238][2.85918:85993]()
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.108238]
    [3.108313]
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1572
    [3.108390][2.85994:86070]()
    "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.108390]
    [3.83554]
    "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
    ]
    [[package]]
    name = "tokio-trace-core"
    version = "0.1.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    dependencies = [
    "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1588
    [3.108819][2.86071:86219]()
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.108819]
    [3.83941]
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1593
    [3.109186][2.86220:86376]()
    "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.109186]
    [3.109342]
    "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1602
    [3.109476][2.86377:86525]()
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.109476]
    [3.109624]
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1605
    [3.109696][2.86526:86598]()
    "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.109696]
    [3.84409]
    "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1610
    [3.84558][2.86599:86755]()
    "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.84558]
    [3.110217]
    "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1619
    [3.110352][2.86756:86829]()
    "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.110352]
    [3.110425]
    "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1621
    [3.110504][2.86830:86905]()
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.110504]
    [3.110579]
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1624
    [3.110727][2.86906:86983]()
    "quick-xml 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.110727]
    [3.84961]
    "quick-xml 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1626
    [3.85032][2.86984:87057]()
    "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.85032]
    [3.110948]
    "tokio 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1628
    [3.111026][2.87058:87134]()
    "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.111026]
    [3.85182]
    "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1638
    [3.111531][2.87135:87154]()
    version = "0.4.10"
    [3.111531]
    [3.111549]
    version = "0.5.0"
  • replacement in Cargo.lock at line 1641
    [3.111631][2.87155:87228]()
    "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.111631]
    [3.111704]
    "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1651
    [3.85845][2.87229:87304]()
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.85845]
    [3.112069]
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1653
    [3.112140][2.87305:87383]()
    "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.112140]
    [3.85999]
    "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1656
    [3.86140][2.87384:87459]()
    "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.86140]
    [3.112434]
    "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1658
    [3.112508][2.87460:87697]()
    "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.112508]
    [3.86453]
    "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1672
    [3.113190][2.87698:87771]()
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.113190]
    [3.86848]
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1674
    [3.86922][2.87772:87847]()
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.86922]
    [3.86997]
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1676
    [3.87072][2.87848:87926]()
    "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.87072]
    [3.87150]
    "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1678
    [3.87220][2.87927:88003]()
    "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.87220]
    [3.87296]
    "lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1680
    [3.87374][2.88004:88152]()
    "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.87374]
    [3.87522]
    "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
    "tokio 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1695
    [3.87641][2.88153:88226]()
    "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.87641]
    [3.87714]
    "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1721
    [3.87772][2.88227:88302]()
    "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.87772]
    [3.87847]
    "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
  • edit in Cargo.lock at line 1740
    [3.115350][2.88303:88510]()
    name = "unreachable"
    version = "1.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    dependencies = [
    "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
    ]
    [[package]]
  • edit in Cargo.lock at line 1770
    [3.116158][2.88511:88621]()
    name = "void"
    version = "1.0.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    [[package]]
  • replacement in Cargo.lock at line 1774
    [3.116272][2.88622:88697]()
    "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.116272]
    [3.87982]
    "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1791
    [3.116751][2.88698:88716]()
    version = "0.3.6"
    [3.116751]
    [3.116769]
    version = "0.3.7"
  • replacement in Cargo.lock at line 1813
    [3.117425][2.88717:88790]()
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.117425]
    [3.117498]
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1826
    [3.117765][2.88791:88864]()
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.117765]
    [3.88238]
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1835
    [3.118047][2.88865:88938]()
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.118047]
    [3.118120]
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1843
    [3.118252][2.88939:89012]()
    "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
    [3.118252]
    [3.118325]
    "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  • edit in Cargo.lock at line 1881
    [3.89382]
    [3.120691]
    ]
    [[package]]
    name = "xmpp-parsers"
    version = "0.13.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    dependencies = [
    "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
    "blake2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
    "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "jid 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
    "minidom 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
    "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
    "sha3 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  • replacement in Cargo.lock at line 1901
    [3.90328][2.89013:89168]()
    "checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e"
    [3.90328]
    [3.121015]
    "checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
  • replacement in Cargo.lock at line 1903
    [3.121168][2.89169:89320]()
    "checksum arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1025aeae2b664ca0ea726a89d574fe8f4e77dd712d443236ad1de00379450cf6"
    [3.121168]
    [3.90636]
    "checksum arc-swap 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)" = "a57a5698f85c6fd92f19dad87ff2d822fc4ba79dd85c13914d8c4dad589cb815"
  • replacement in Cargo.lock at line 1907
    [3.90939][2.89321:89474]()
    "checksum backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "b5b493b66e03090ebc4343eb02f94ff944e0cbc9ac6571491d170ba026741eb5"
    [3.90939]
    [3.91092]
    "checksum backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f106c02a3604afcdc0df5d36cc47b44b55917dbaf3d808f71c163a0ddba64637"
  • replacement in Cargo.lock at line 1912
    [3.91549][2.89475:89630]()
    "checksum block-buffer 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "509de513cca6d92b6aacf9c61acfe7eaa160837323a81068d690cc1f8e5740da"
    [3.91549]
    [3.91704]
    "checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d"
  • replacement in Cargo.lock at line 1916
    [3.92165][2.89631:89780]()
    "checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa"
    [3.92165]
    [3.123295]
    "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
  • replacement in Cargo.lock at line 1918
    [3.123442][2.89781:90076]()
    "checksum cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "4390a3b5f4f6bce9c1d0c00128379df433e53777fdd30e92f16a529332baec4e"
    "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
    [3.123442]
    [3.123737]
    "checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83"
    "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
  • replacement in Cargo.lock at line 1921
    [3.123886][2.90077:90225]()
    "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
    [3.123886]
    [3.124034]
    "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
  • replacement in Cargo.lock at line 1925
    [3.124505][2.90226:90696]()
    "checksum crossbeam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad4c7ea749d9fb09e23c5cb17e3b70650860553a0e2744e38446b1803bf7db94"
    "checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b"
    "checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13"
    [3.124505]
    [3.92918]
    "checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71"
  • edit in Cargo.lock at line 1927
    [3.93076]
    [3.93234]
    "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b"
  • replacement in Cargo.lock at line 1932
    [3.93695][2.90697:91005]()
    "checksum encoding_rs 0.8.15 (registry+https://github.com/rust-lang/crates.io-index)" = "fd251508d65030820f3a4317af2248180db337fdb25d89967956242580277813"
    "checksum env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afb070faf94c85d17d50ca44f6ad076bce18ae92f0037d350947240a36e9d42e"
    [3.93695]
    [3.125902]
    "checksum encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4155785c79f2f6701f185eb2e6b4caf0555ec03477cb4c70db67b465311620ed"
    "checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a"
  • replacement in Cargo.lock at line 1945
    [3.127601][2.91006:91157]()
    "checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b"
    [3.127601]
    [3.127752]
    "checksum futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "62941eff9507c8177d448bd83a44d9b9760856e184081d8cd79ba9f03dd24981"
  • replacement in Cargo.lock at line 1948
    [3.94778][2.91158:91304]()
    "checksum h2 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ddb2b25a33e231484694267af28fec74ac63b5ccf51ee2065a5e313b834d836e"
    [3.94778]
    [3.94924]
    "checksum h2 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "85ab6286db06040ddefb71641b50017c06874614001a134b423783e2db2920bd"
  • replacement in Cargo.lock at line 1951
    [3.128511][2.91305:91453]()
    "checksum http 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "1a10e5b573b9a0146545010f50772b9e8b1dd0a256564cc4307694c68832a2f5"
    [3.128511]
    [3.128659]
    "checksum http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "eed324f0f0daf6ec10c474f150505af2c143f251722bf9dbd1261bd1f2ee2c1a"
  • replacement in Cargo.lock at line 1954
    [3.95373][2.91454:91604]()
    "checksum hyper 0.12.23 (registry+https://github.com/rust-lang/crates.io-index)" = "860faf61a9957c9cb0e23e69f1c8290e92f6eb660fcdd1f2d6777043a2ae1a46"
    [3.95373]
    [3.129112]
    "checksum hyper 0.12.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4f2777434f26af6e4ce4fdcdccd3bed9d861d11e87bcbe72c0f51ddaca8ff848"
  • replacement in Cargo.lock at line 1963
    [3.130306][2.91605:91759]()
    "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
    [3.130306]
    [3.95977]
    "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
  • replacement in Cargo.lock at line 1965
    [3.96128][2.91760:92066]()
    "checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
    "checksum linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7860ec297f7008ff7a1e3382d7f7e1dcd69efc94751a2284bafc3d013c2aa939"
    [3.96128]
    [3.96434]
    "checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917"
    "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
  • replacement in Cargo.lock at line 1969
    [3.96731][2.92067:92219]()
    "checksum lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4d06ff7ff06f729ce5f4e227876cb88d10bc59cd4ae1e09fbb2bde15c850dc21"
    [3.96731]
    [3.131366]
    "checksum lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
  • replacement in Cargo.lock at line 1973
    [3.131816][2.92220:92369]()
    "checksum memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e1dd4eaac298c32ce07eb6ed9242eda7d82955b9170b7d6db59b2e02cc63fcb8"
    [3.131816]
    [3.131965]
    "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
  • replacement in Cargo.lock at line 1981
    [3.133013][2.92370:92534]()
    "checksum new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0cdc457076c78ab54d5e0d6fa7c47981757f1e34dc39ff92787f217dede586c4"
    [3.133013]
    [3.97505]
    "checksum new_debug_unreachable 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f40f005c60db6e03bae699e414c58bf9aa7ea02a2d0b9bfbcf19286cc4c82b30"
  • replacement in Cargo.lock at line 1985
    [3.133635][2.92535:92686]()
    "checksum num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a69d464bdc213aaaff628444e99578ede64e9c854025aa43b9796530afa9238"
    [3.133635]
    [3.97808]
    "checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
  • replacement in Cargo.lock at line 1987
    [3.97963][2.92687:92839]()
    "checksum openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ec7bd7ca4cce6dbdc77e7c1230682740d307d1218a87fb0349a571272be749f9"
    [3.97963]
    [3.134094]
    "checksum openssl 0.10.20 (registry+https://github.com/rust-lang/crates.io-index)" = "5a0d6b781aac4ac1bd6cafe2a2f0ad8c16ae8e1dd5184822a16c50139f8838d9"
  • replacement in Cargo.lock at line 1989
    [3.134250][2.92840:92995]()
    "checksum openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)" = "1bb974e77de925ef426b6bc82fce15fd45bdcbeb5728bffcfc7cdeeb7ce1c2d6"
    [3.134250]
    [3.98271]
    "checksum openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)" = "33c86834957dd5b915623e94f2f4ab2c70dd8f6b70679824155d5ae21dbd495d"
  • replacement in Cargo.lock at line 2003
    [3.136414][2.92996:93149]()
    "checksum quick-xml 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98d8d2d671bd29c6122a98b45ce3106391e89ba378f731274de677f1eff06e5f"
    [3.136414]
    [3.136567]
    "checksum quick-xml 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)" = "22fcc48ecef4609b243e8c01ff4695d08ee0fc9d5bdbc54630e1a5fe8bb40953"
  • replacement in Cargo.lock at line 2005
    [3.136716][2.93150:93299]()
    "checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
    [3.136716]
    [3.99960]
    "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
  • replacement in Cargo.lock at line 2014
    [3.101169][2.93300:93601]()
    "checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d"
    "checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05"
    [3.101169]
    [3.101470]
    "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
    "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
  • replacement in Cargo.lock at line 2018
    [3.101775][2.93602:93759]()
    "checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85"
    [3.101775]
    [3.138837]
    "checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
  • replacement in Cargo.lock at line 2020
    [3.138993][2.93760:94063]()
    "checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f"
    "checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861"
    [3.138993]
    [3.139296]
    "checksum regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "559008764a17de49a3146b234641644ed37d118d1ef641a0bb573d146edc6ce0"
    "checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
  • replacement in Cargo.lock at line 2024
    [3.102391][2.94064:94222]()
    "checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
    [3.102391]
    [3.139765]
    "checksum rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc78bfd5acd7bf3e89cffcf899e5cb1a52d6fafa8dec2739ad70c9577a57288"
  • replacement in Cargo.lock at line 2028
    [3.102843][2.94223:94375]()
    "checksum schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "0e1a231dc10abf6749cfa5d7767f25888d484201accbd919b66ab5413c502d56"
    [3.102843]
    [3.140366]
    "checksum schannel 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f6abf258d99c3c1c5c2131d99d064e94b7b3dd5f416483057f308fea253339"
  • replacement in Cargo.lock at line 2034
    [3.141150][2.94376:94835]()
    "checksum serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)" = "2e20fde37801e83c891a2dc4ebd3b81f0da4d1fb67a9e0a2a3b921e2536a58ee"
    "checksum serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)" = "633e97856567e518b59ffb2ad7c7a4fd4c5d91d9c7f32dd38a27b2bf7e8114ea"
    "checksum serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "27dce848e7467aa0e2fcaf0a413641499c0b745452aaca1194d24dedde9e13c9"
    [3.141150]
    [3.103782]
    "checksum serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "aa5f7c20820475babd2c077c3ab5f8c77a31c15e16ea38687b4c02d3e48680f4"
    "checksum serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "58fc82bec244f168b23d1963b45c8bf5726e9a15a9d146a067f9081aeed2de79"
    "checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d"
  • replacement in Cargo.lock at line 2040
    [3.104224][2.94836:94990]()
    "checksum signal-hook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1f272d1b7586bec132ed427f532dd418d8beca1ca7f2caf7df35569b1415a4b4"
    [3.104224]
    [3.142205]
    "checksum signal-hook 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "97a47ae722318beceb0294e6f3d601205a1e6abaa4437d9d33e3a212233e3021"
  • replacement in Cargo.lock at line 2043
    [3.104526][2.94991:95142]()
    "checksum smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "88aea073965ab29f6edb5493faf96ad662fb18aa9eeb186a3b7057951605ed15"
    [3.104526]
    [3.142655]
    "checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be"
  • replacement in Cargo.lock at line 2050
    [3.143595][2.95143:95292]()
    "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
    [3.143595]
    [3.104977]
    "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
  • replacement in Cargo.lock at line 2053
    [3.144041][2.95293:95441]()
    "checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9"
    [3.144041]
    [3.144189]
    "checksum syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)" = "66c8865bf5a7cbb662d8b011950060b3c8743dca141b054bf7195b20d314d8e2"
  • replacement in Cargo.lock at line 2056
    [3.105432][2.95442:95593]()
    "checksum tempfile 3.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "37daa55a7240c4931c84559f03b3cad7d19535840d1c4a0cc4e9b2fb0dcf70ff"
    [3.105432]
    [3.105583]
    "checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a"
  • replacement in Cargo.lock at line 2060
    [3.145097][2.95594:95746]()
    "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
    [3.145097]
    [3.145249]
    "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
  • replacement in Cargo.lock at line 2063
    [3.106035][2.95747:95896]()
    "checksum tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "e0500b88064f08bebddd0c0bed39e19f5c567a5f30975bee52b0c0d3e2eeb38c"
    [3.106035]
    [3.145701]
    "checksum tokio 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "65641e515a437b308ab131a82ce3042ff9795bef5d6c5a9be4eb24195c417fd9"
  • replacement in Cargo.lock at line 2066
    [3.146011][2.95897:96676]()
    "checksum tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "331c8acc267855ec06eb0c94618dcbbfea45bed2d20b77252940095273fb58f6"
    "checksum tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30c6dbf2d1ad1de300b393910e8a3aa272b724a400b6531da03eed99e329fbf0"
    "checksum tokio-fs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0e9cbbc8a3698b7ab652340f46633364f9eaa928ddaaee79d8b8f356dd79a09d"
    "checksum tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b53aeb9d3f5ccf2ebb29e19788f96987fa1355f8fe45ea193928eaaaf3ae820f"
    "checksum tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "afbcdb0f0d2a1e4c440af82d7bbf0bf91a8a8c0575bcd20c05d15be7e9d3a02f"
    [3.146011]
    [3.106964]
    "checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443"
    "checksum tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "83ea44c6c0773cc034771693711c35c677b4b5a4b21b9e7071704c54de7d555e"
    "checksum tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe6dc22b08d6993916647d108a1a7d15b9cd29c4f4496c62b92c45b5041b7af"
    "checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926"
    "checksum tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6af16bfac7e112bea8b0442542161bfc41cbfa4466b580bdda7d18cb88b911ce"
  • replacement in Cargo.lock at line 2072
    [3.107119][2.96677:96830]()
    "checksum tokio-sync 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3742b64166c1ee9121f1921aea5a726098458926a6b732d906ef23b1f3ef6f4f"
    [3.107119]
    [3.107272]
    "checksum tokio-sync 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fda385df506bf7546e70872767f71e81640f1f251bdf2fd8eb81a0eaec5fe022"
  • replacement in Cargo.lock at line 2074
    [3.107424][2.96831:96991]()
    "checksum tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c3fd86cb15547d02daa2b21aadaf4e37dee3368df38a526178a5afa3c034d2fb"
    [3.107424]
    [3.107584]
    "checksum tokio-threadpool 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "ec5759cf26cf9659555f36c431b515e3d05f66831741c85b4b5d5dfb9cf1323c"
  • edit in Cargo.lock at line 2077
    [3.107891]
    [3.108050]
    "checksum tokio-trace-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "350c9edade9830dc185ae48ba45667a445ab59f6167ef6d0254ec9d2430d9dd3"
  • replacement in Cargo.lock at line 2081
    [3.108507][2.96992:97140]()
    "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
    [3.108507]
    [3.108654]
    "checksum toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87c5890a989fa47ecdc7bcb4c63a77a82c18f306714104b1decfd722db17b39e"
  • edit in Cargo.lock at line 2093
    [3.150187][2.97141:97295]()
    "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
  • edit in Cargo.lock at line 2098
    [3.150933][2.97296:97443]()
    "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
  • replacement in Cargo.lock at line 2101
    [3.151382][2.97444:97593]()
    "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
    [3.151382]
    [3.151531]
    "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
  • edit in Cargo.lock at line 2112
    [3.110506]
    "checksum xmpp-parsers 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5094cec449beca92f82ae4d7fe13cda058005849766d71b86c23e6217f61a357"