aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/devtools/Cargo.toml1
-rw-r--r--components/devtools/actors/inspector.rs106
-rw-r--r--components/devtools/lib.rs2
-rw-r--r--components/devtools_traits/lib.rs29
-rw-r--r--components/layout/layout_thread.rs16
-rw-r--r--components/layout/query.rs22
-rw-r--r--components/script/devtools.rs49
-rw-r--r--components/script/dom/node.rs1
-rw-r--r--components/script/dom/window.rs10
-rw-r--r--components/script/layout_interface.rs22
-rw-r--r--components/servo/Cargo.lock1
-rw-r--r--ports/cef/Cargo.lock1
-rw-r--r--ports/gonk/Cargo.lock1
13 files changed, 222 insertions, 39 deletions
diff --git a/components/devtools/Cargo.toml b/components/devtools/Cargo.toml
index 36567380d14..9d4f910dfe1 100644
--- a/components/devtools/Cargo.toml
+++ b/components/devtools/Cargo.toml
@@ -27,5 +27,6 @@ hyper = { version = "0.7", features = [ "serde-serialization" ] }
log = "0.3"
rustc-serialize = "0.3"
serde = "0.6"
+serde_json = "0.6"
serde_macros = "0.6"
time = "0.1"
diff --git a/components/devtools/actors/inspector.rs b/components/devtools/actors/inspector.rs
index 7dd5def34cf..1bf72d96e64 100644
--- a/components/devtools/actors/inspector.rs
+++ b/components/devtools/actors/inspector.rs
@@ -12,7 +12,8 @@ use devtools_traits::{ComputedNodeLayout, DevtoolScriptControlMsg, NodeInfo};
use ipc_channel::ipc::{self, IpcSender};
use msg::constellation_msg::PipelineId;
use protocol::JsonPacketStream;
-use rustc_serialize::json::{self, Json, ToJson};
+use rustc_serialize::json::{self, Json};
+use serde_json;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::net::TcpStream;
@@ -397,21 +398,49 @@ struct AppliedSheet {
ruleCount: usize,
}
-#[derive(RustcEncodable)]
+#[derive(Serialize)]
struct GetLayoutReply {
- width: i32,
- height: i32,
- autoMargins: Json,
from: String,
-}
-#[derive(RustcEncodable)]
-#[allow(dead_code)]
-struct AutoMargins {
- top: String,
- bottom: String,
- left: String,
- right: String,
+ display: String,
+ position: String,
+ #[serde(rename = "z-index")]
+ zIndex: String,
+ #[serde(rename = "box-sizing")]
+ boxSizing: String,
+
+ // Would be nice to use a proper struct, blocked by
+ // https://github.com/serde-rs/serde/issues/43
+ autoMargins: serde_json::value::Value,
+ #[serde(rename = "margin-top")]
+ marginTop: String,
+ #[serde(rename = "margin-right")]
+ marginRight: String,
+ #[serde(rename = "margin-bottom")]
+ marginBottom: String,
+ #[serde(rename = "margin-left")]
+ marginLeft: String,
+
+ #[serde(rename = "border-top-width")]
+ borderTopWidth: String,
+ #[serde(rename = "border-right-width")]
+ borderRightWidth: String,
+ #[serde(rename = "border-bottom-width")]
+ borderBottomWidth: String,
+ #[serde(rename = "border-left-width")]
+ borderLeftWidth: String,
+
+ #[serde(rename = "padding-top")]
+ paddingTop: String,
+ #[serde(rename = "padding-right")]
+ paddingRight: String,
+ #[serde(rename = "padding-bottom")]
+ paddingBottom: String,
+ #[serde(rename = "padding-left")]
+ paddingLeft: String,
+
+ width: f32,
+ height: f32,
}
impl Actor for PageStyleActor {
@@ -455,31 +484,52 @@ impl Actor for PageStyleActor {
registry.actor_to_script(target.to_owned()),
tx))
.unwrap();
- let ComputedNodeLayout { width, height } = rx.recv().unwrap();
+ let ComputedNodeLayout {
+ display, position, zIndex, boxSizing,
+ autoMargins, marginTop, marginRight, marginBottom, marginLeft,
+ borderTopWidth, borderRightWidth, borderBottomWidth, borderLeftWidth,
+ paddingTop, paddingRight, paddingBottom, paddingLeft,
+ width, height,
+ } = rx.recv().unwrap();
let auto_margins = msg.get("autoMargins")
.and_then(&Json::as_boolean).unwrap_or(false);
- //TODO: the remaining layout properties (margin, border, padding, position)
- // as specified in getLayout in
- // http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/styles.js
+ // http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/styles.js
let msg = GetLayoutReply {
- width: width.round() as i32,
- height: height.round() as i32,
+ from: self.name(),
+ display: display,
+ position: position,
+ zIndex: zIndex,
+ boxSizing: boxSizing,
autoMargins: if auto_margins {
- //TODO: real values like processMargins in
- // http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/styles.js
let mut m = BTreeMap::new();
- m.insert("top".to_owned(), "auto".to_owned().to_json());
- m.insert("bottom".to_owned(), "auto".to_owned().to_json());
- m.insert("left".to_owned(), "auto".to_owned().to_json());
- m.insert("right".to_owned(), "auto".to_owned().to_json());
- Json::Object(m)
+ let auto = serde_json::value::Value::String("auto".to_owned());
+ if autoMargins.top { m.insert("top".to_owned(), auto.clone()); }
+ if autoMargins.right { m.insert("right".to_owned(), auto.clone()); }
+ if autoMargins.bottom { m.insert("bottom".to_owned(), auto.clone()); }
+ if autoMargins.left { m.insert("left".to_owned(), auto.clone()); }
+ serde_json::value::Value::Object(m)
} else {
- Json::Null
+ serde_json::value::Value::Null
},
- from: self.name(),
+ marginTop: marginTop,
+ marginRight: marginRight,
+ marginBottom: marginBottom,
+ marginLeft: marginLeft,
+ borderTopWidth: borderTopWidth,
+ borderRightWidth: borderRightWidth,
+ borderBottomWidth: borderBottomWidth,
+ borderLeftWidth: borderLeftWidth,
+ paddingTop: paddingTop,
+ paddingRight: paddingRight,
+ paddingBottom: paddingBottom,
+ paddingLeft: paddingLeft,
+ width: width,
+ height: height,
};
+ let msg = &serde_json::to_string(&msg).unwrap();
+ let msg = Json::from_str(msg).unwrap();
stream.write_json_packet(&msg);
ActorMessageStatus::Processed
}
diff --git a/components/devtools/lib.rs b/components/devtools/lib.rs
index 1d96c932389..3ee14422d53 100644
--- a/components/devtools/lib.rs
+++ b/components/devtools/lib.rs
@@ -11,6 +11,7 @@
#![crate_type = "rlib"]
#![feature(box_syntax)]
+#![feature(custom_attribute)]
#![feature(custom_derive)]
#![feature(plugin)]
#![plugin(serde_macros)]
@@ -27,6 +28,7 @@ extern crate log;
extern crate msg;
extern crate rustc_serialize;
extern crate serde;
+extern crate serde_json;
extern crate time;
extern crate util;
diff --git a/components/devtools_traits/lib.rs b/components/devtools_traits/lib.rs
index 38d9f65d9c5..44a55001a0e 100644
--- a/components/devtools_traits/lib.rs
+++ b/components/devtools_traits/lib.rs
@@ -157,10 +157,39 @@ pub enum TimelineMarkerType {
/// The properties of a DOM node as computed by layout.
#[derive(Deserialize, Serialize)]
pub struct ComputedNodeLayout {
+ pub display: String,
+ pub position: String,
+ pub zIndex: String,
+ pub boxSizing: String,
+
+ pub autoMargins: AutoMargins,
+ pub marginTop: String,
+ pub marginRight: String,
+ pub marginBottom: String,
+ pub marginLeft: String,
+
+ pub borderTopWidth: String,
+ pub borderRightWidth: String,
+ pub borderBottomWidth: String,
+ pub borderLeftWidth: String,
+
+ pub paddingTop: String,
+ pub paddingRight: String,
+ pub paddingBottom: String,
+ pub paddingLeft: String,
+
pub width: f32,
pub height: f32,
}
+#[derive(Deserialize, Serialize)]
+pub struct AutoMargins {
+ pub top: bool,
+ pub right: bool,
+ pub bottom: bool,
+ pub left: bool,
+}
+
/// Messages to process in a particular script thread, as instructed by a devtools client.
#[derive(Deserialize, Serialize)]
pub enum DevtoolScriptControlMsg {
diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs
index fbc1cd26daf..e1e163acb39 100644
--- a/components/layout/layout_thread.rs
+++ b/components/layout/layout_thread.rs
@@ -42,9 +42,10 @@ use profile_traits::mem::{self, Report, ReportKind, ReportsChan};
use profile_traits::time::{TimerMetadataFrameType, TimerMetadataReflowType};
use profile_traits::time::{self, TimerMetadata, profile};
use query::{LayoutRPCImpl, process_content_box_request, process_content_boxes_request};
-use query::{process_node_geometry_request, process_offset_parent_query, process_resolved_style_request};
+use query::{process_node_geometry_request, process_offset_parent_query};
+use query::{process_resolved_style_request, process_margin_style_query};
use script::dom::node::OpaqueStyleAndLayoutData;
-use script::layout_interface::{LayoutRPC, OffsetParentResponse};
+use script::layout_interface::{LayoutRPC, OffsetParentResponse, MarginStyleResponse};
use script::layout_interface::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType};
use script::layout_interface::{ScriptLayoutChan, ScriptReflow};
use script::reporter::CSSErrorReporter;
@@ -117,6 +118,9 @@ pub struct LayoutThreadData {
/// A queued response for the offset parent/rect of a node.
pub offset_parent_response: OffsetParentResponse,
+
+ /// A queued response for the offset parent/rect of a node.
+ pub margin_style_response: MarginStyleResponse,
}
/// Information needed by the layout thread.
@@ -455,6 +459,7 @@ impl LayoutThread {
client_rect_response: Rect::zero(),
resolved_style_response: None,
offset_parent_response: OffsetParentResponse::empty(),
+ margin_style_response: MarginStyleResponse::empty(),
})),
error_reporter: CSSErrorReporter {
pipelineid: id,
@@ -986,6 +991,9 @@ impl LayoutThread {
ReflowQueryType::OffsetParentQuery(_) => {
rw_data.offset_parent_response = OffsetParentResponse::empty();
},
+ ReflowQueryType::MarginStyleQuery(_) => {
+ rw_data.margin_style_response = MarginStyleResponse::empty();
+ },
ReflowQueryType::NoQuery => {}
}
return;
@@ -1129,6 +1137,10 @@ impl LayoutThread {
let node = unsafe { ServoLayoutNode::new(&node) };
rw_data.offset_parent_response = process_offset_parent_query(node, &mut root_flow);
},
+ ReflowQueryType::MarginStyleQuery(node) => {
+ let node = unsafe { ServoLayoutNode::new(&node) };
+ rw_data.margin_style_response = process_margin_style_query(node);
+ },
ReflowQueryType::NoQuery => {}
}
}
diff --git a/components/layout/query.rs b/components/layout/query.rs
index af2dbdd9724..0a66a135919 100644
--- a/components/layout/query.rs
+++ b/components/layout/query.rs
@@ -17,7 +17,7 @@ use msg::constellation_msg::ConstellationChan;
use opaque_node::OpaqueNodeMethods;
use script::layout_interface::{ContentBoxResponse, ContentBoxesResponse, NodeGeometryResponse};
use script::layout_interface::{HitTestResponse, LayoutRPC, MouseOverResponse, OffsetParentResponse};
-use script::layout_interface::{ResolvedStyleResponse, ScriptLayoutChan};
+use script::layout_interface::{ResolvedStyleResponse, ScriptLayoutChan, MarginStyleResponse};
use script_traits::LayoutMsg as ConstellationMsg;
use sequential;
use std::ops::Deref;
@@ -131,6 +131,12 @@ impl LayoutRPC for LayoutRPCImpl {
let rw_data = rw_data.lock().unwrap();
rw_data.offset_parent_response.clone()
}
+
+ fn margin_style(&self) -> MarginStyleResponse {
+ let &LayoutRPCImpl(ref rw_data) = self;
+ let rw_data = rw_data.lock().unwrap();
+ rw_data.margin_style_response.clone()
+ }
}
struct UnioningFragmentBorderBoxIterator {
@@ -575,3 +581,17 @@ pub fn process_offset_parent_query<'ln, N: LayoutNode<'ln>>(requested_node: N, l
}
}
}
+
+pub fn process_margin_style_query<'ln, N: LayoutNode<'ln>>(requested_node: N)
+ -> MarginStyleResponse {
+ let layout_node = requested_node.to_threadsafe();
+ let style = &*layout_node.style();
+ let margin = style.get_margin();
+
+ MarginStyleResponse {
+ top: margin.margin_top,
+ right: margin.margin_right,
+ bottom: margin.margin_bottom,
+ left: margin.margin_left,
+ }
+}
diff --git a/components/script/devtools.rs b/components/script/devtools.rs
index 668c4554722..f0ec814cdc2 100644
--- a/components/script/devtools.rs
+++ b/components/script/devtools.rs
@@ -2,18 +2,22 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-use devtools_traits::{CONSOLE_API, CachedConsoleMessage, CachedConsoleMessageTypes, PAGE_ERROR};
+use devtools_traits::TimelineMarkerType;
+use devtools_traits::{AutoMargins, CONSOLE_API, CachedConsoleMessage, CachedConsoleMessageTypes};
use devtools_traits::{ComputedNodeLayout, ConsoleAPI, PageError, ScriptToDevtoolsControlMsg};
-use devtools_traits::{EvaluateJSReply, Modification, NodeInfo, TimelineMarker, TimelineMarkerType};
+use devtools_traits::{EvaluateJSReply, Modification, NodeInfo, PAGE_ERROR, TimelineMarker};
+use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods;
use dom::bindings::codegen::Bindings::DOMRectBinding::DOMRectMethods;
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
+use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::conversions::{FromJSValConvertible, jsstring_to_str};
use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root;
use dom::element::Element;
use dom::node::Node;
+use dom::window::Window;
use ipc_channel::ipc::IpcSender;
use js::jsapi::{ObjectClassName, RootedObject, RootedValue};
use js::jsval::UndefinedValue;
@@ -23,6 +27,7 @@ use script_thread::get_page;
use std::ffi::CStr;
use std::rc::Rc;
use std::str;
+use style::properties::longhands::{margin_top, margin_right, margin_bottom, margin_left};
use util::str::DOMString;
use uuid::Uuid;
@@ -110,15 +115,47 @@ pub fn handle_get_layout(page: &Rc<Page>,
node_id: String,
reply: IpcSender<ComputedNodeLayout>) {
let node = find_node_by_unique_id(&*page, pipeline, node_id);
+
let elem = node.downcast::<Element>().expect("should be getting layout of element");
let rect = elem.GetBoundingClientRect();
let width = rect.Width() as f32;
let height = rect.Height() as f32;
+
+ let window = page.window();
+ let elem = node.downcast::<Element>().expect("should be getting layout of element");
+ let computed_style = window.r().GetComputedStyle(elem, None);
+
reply.send(ComputedNodeLayout {
- width: width,
- height: height,
- })
- .unwrap();
+ display: String::from(computed_style.Display()),
+ position: String::from(computed_style.Position()),
+ zIndex: String::from(computed_style.ZIndex()),
+ boxSizing: String::from(computed_style.BoxSizing()),
+ autoMargins: determine_auto_margins(&window, &*node),
+ marginTop: String::from(computed_style.MarginTop()),
+ marginRight: String::from(computed_style.MarginRight()),
+ marginBottom: String::from(computed_style.MarginBottom()),
+ marginLeft: String::from(computed_style.MarginLeft()),
+ borderTopWidth: String::from(computed_style.BorderTopWidth()),
+ borderRightWidth: String::from(computed_style.BorderRightWidth()),
+ borderBottomWidth: String::from(computed_style.BorderBottomWidth()),
+ borderLeftWidth: String::from(computed_style.BorderLeftWidth()),
+ paddingTop: String::from(computed_style.PaddingTop()),
+ paddingRight: String::from(computed_style.PaddingRight()),
+ paddingBottom: String::from(computed_style.PaddingBottom()),
+ paddingLeft: String::from(computed_style.PaddingLeft()),
+ width: width,
+ height: height,
+ }).unwrap();
+}
+
+fn determine_auto_margins(window: &Window, node: &Node) -> AutoMargins {
+ let margin = window.margin_style_query(node.to_trusted_node_address());
+ AutoMargins {
+ top: margin.top == margin_top::computed_value::T::Auto,
+ right: margin.right == margin_right::computed_value::T::Auto,
+ bottom: margin.bottom == margin_bottom::computed_value::T::Auto,
+ left: margin.left == margin_left::computed_value::T::Auto,
+ }
}
pub fn handle_get_cached_messages(_pipeline_id: PipelineId,
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index f1ebf6f9965..c82fbb49e88 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -185,7 +185,6 @@ unsafe impl Send for OpaqueStyleAndLayoutData {}
no_jsmanaged_fields!(OpaqueStyleAndLayoutData);
-
impl OpaqueStyleAndLayoutData {
/// Sends the style and layout data, if any, back to the layout thread to be destroyed.
pub fn dispose(self, node: &Node) {
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 908d3dffd2c..0869423c55b 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -41,7 +41,7 @@ use js::jsapi::{JSAutoCompartment, JSAutoRequest, JS_GC, JS_GetRuntime};
use js::rust::CompileOptionsWrapper;
use js::rust::Runtime;
use layout_interface::{ContentBoxResponse, ContentBoxesResponse, ResolvedStyleResponse, ScriptReflow};
-use layout_interface::{LayoutChan, LayoutRPC, Msg, Reflow, ReflowQueryType};
+use layout_interface::{LayoutChan, LayoutRPC, Msg, Reflow, ReflowQueryType, MarginStyleResponse};
use libc;
use msg::constellation_msg::{ConstellationChan, LoadData, PipelineId, SubpageId, WindowSizeData};
use msg::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
@@ -1099,6 +1099,13 @@ impl Window {
(element, response.rect)
}
+ pub fn margin_style_query(&self, node: TrustedNodeAddress) -> MarginStyleResponse {
+ self.reflow(ReflowGoal::ForScriptQuery,
+ ReflowQueryType::MarginStyleQuery(node),
+ ReflowReason::Query);
+ self.layout_rpc.margin_style()
+ }
+
pub fn init_browsing_context(&self, browsing_context: &BrowsingContext) {
assert!(self.browsing_context.get().is_none());
self.browsing_context.set(Some(&browsing_context));
@@ -1420,6 +1427,7 @@ fn debug_reflow_events(goal: &ReflowGoal, query_type: &ReflowQueryType, reason:
ReflowQueryType::NodeGeometryQuery(_n) => "\tNodeGeometryQuery",
ReflowQueryType::ResolvedStyleQuery(_, _, _) => "\tResolvedStyleQuery",
ReflowQueryType::OffsetParentQuery(_n) => "\tOffsetParentQuery",
+ ReflowQueryType::MarginStyleQuery(_n) => "\tMarginStyleQuery",
});
debug_msg.push_str(match *reason {
diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs
index 831c04a9516..17f553d43e8 100644
--- a/components/script/layout_interface.rs
+++ b/components/script/layout_interface.rs
@@ -23,6 +23,7 @@ use std::sync::Arc;
use std::sync::mpsc::{Receiver, Sender, channel};
use string_cache::Atom;
use style::context::ReflowGoal;
+use style::properties::longhands::{margin_top, margin_right, margin_bottom, margin_left};
use style::selector_impl::PseudoElement;
use style::servo::Stylesheet;
use url::Url;
@@ -109,8 +110,28 @@ pub trait LayoutRPC {
/// Query layout for the resolved value of a given CSS property
fn resolved_style(&self) -> ResolvedStyleResponse;
fn offset_parent(&self) -> OffsetParentResponse;
+ /// Query layout for the resolve values of the margin properties for an element.
+ fn margin_style(&self) -> MarginStyleResponse;
}
+#[derive(Clone)]
+pub struct MarginStyleResponse {
+ pub top: margin_top::computed_value::T,
+ pub right: margin_right::computed_value::T,
+ pub bottom: margin_bottom::computed_value::T,
+ pub left: margin_left::computed_value::T,
+}
+
+impl MarginStyleResponse {
+ pub fn empty() -> MarginStyleResponse {
+ MarginStyleResponse {
+ top: margin_top::computed_value::T::Auto,
+ right: margin_right::computed_value::T::Auto,
+ bottom: margin_bottom::computed_value::T::Auto,
+ left: margin_left::computed_value::T::Auto,
+ }
+ }
+}
pub struct ContentBoxResponse(pub Rect<Au>);
pub struct ContentBoxesResponse(pub Vec<Rect<Au>>);
@@ -145,6 +166,7 @@ pub enum ReflowQueryType {
NodeGeometryQuery(TrustedNodeAddress),
ResolvedStyleQuery(TrustedNodeAddress, Option<PseudoElement>, Atom),
OffsetParentQuery(TrustedNodeAddress),
+ MarginStyleQuery(TrustedNodeAddress),
}
/// Information needed for a reflow.
diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock
index 59c4c094747..3513e593952 100644
--- a/components/servo/Cargo.lock
+++ b/components/servo/Cargo.lock
@@ -386,6 +386,7 @@ dependencies = [
"plugins 0.0.1",
"rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_macros 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock
index 846618da32b..fd72d6fc145 100644
--- a/ports/cef/Cargo.lock
+++ b/ports/cef/Cargo.lock
@@ -358,6 +358,7 @@ dependencies = [
"plugins 0.0.1",
"rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_macros 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",
diff --git a/ports/gonk/Cargo.lock b/ports/gonk/Cargo.lock
index 0ef2a176773..4202bb74279 100644
--- a/ports/gonk/Cargo.lock
+++ b/ports/gonk/Cargo.lock
@@ -350,6 +350,7 @@ dependencies = [
"plugins 0.0.1",
"rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_macros 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
"util 0.0.1",