{"action":"created","comment":{"url":"https://api.github.com/repos/servo/html5ever/pulls/comments/27121229","id":27121229,"diff_hunk":"@@ -0,0 +1,922 @@\n+// Copyright 2015 The html5ever Project Developers. See the\n+// COPYRIGHT file at the top-level directory of this distribution.\n+//\n+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license\n+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your\n+// option. This file may not be copied, modified, or distributed\n+// except according to those terms.\n+\n+use std::prelude::v1::*;\n+\n+use std::{mem, fmt, io, str, slice};\n+use std::raw::{self, Repr};\n+use std::ops::Deref;\n+use std::cmp::Ordering;\n+use std::error::FromError;\n+\n+use iobuf::{Iobuf, ROIobuf, RWIobuf};\n+\n+use util::str::AsciiCast;\n+\n+use self::Tendril_::{Shared, Owned, Ascii};\n+\n+#[derive(Clone)]\n+enum Tendril_ {\n+    Shared(ROIobuf<'static>),\n+    Ascii(u8),\n+    Owned(String),\n+}\n+\n+/// html5ever's abstraction of strings.\n+///\n+/// A tendril either owns its content, or is a slice of a shared buffer.\n+/// These buffers are managed with non-atomic (thread-local) reference\n+/// counting, which is very fast.\n+///\n+/// Like `String`, `Tendril` implements `Deref<Target = str>`. So you can\n+/// call string slice methods on `Tendril`, or pass `&Tendril` to a function\n+/// expecting `&str`.\n+///\n+/// Accordingly, the content of a tendril is guaranteed to be valid UTF-8.\n+/// Take particular care of this when calling `unsafe` functions below!\n+///\n+/// The maximum size of a tendril is 1 GB. The safe methods below will\n+/// `panic!` if a tendril grows beyond that size.\n+#[derive(Clone)]\n+pub struct Tendril(Tendril_);\n+\n+impl PartialEq for Tendril {\n+    #[inline]\n+    fn eq(&self, other: &Tendril) -> bool {\n+        &**self == &**other\n+    }\n+\n+    #[inline]\n+    fn ne(&self, other: &Tendril) -> bool {\n+        &**self != &**other\n+    }\n+}\n+\n+impl Eq for Tendril { }\n+\n+impl PartialOrd for Tendril {\n+    #[inline]\n+    fn partial_cmp(&self, other: &Tendril) -> Option<Ordering> {\n+        (&**self).partial_cmp(other)\n+    }\n+}\n+\n+impl Ord for Tendril {\n+    #[inline]\n+    fn cmp(&self, other: &Tendril) -> Ordering {\n+        (&**self).cmp(other)\n+    }\n+}\n+\n+impl fmt::Display for Tendril {\n+    #[inline]\n+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {\n+        <str as fmt::Display>::fmt(&*self, fmt)\n+    }\n+}\n+\n+impl fmt::Debug for Tendril {\n+    #[inline]\n+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {\n+        try!(write!(fmt, \"Tendril[{}](\", match self.0 {\n+            Shared(_) => \"shared\",\n+            Ascii(_) => \"ascii\",\n+            Owned(_) => \"owned\",\n+        }));\n+        try!(<str as fmt::Debug>::fmt(&*self, fmt));\n+        try!(write!(fmt, \")\"));\n+        Ok(())\n+    }\n+}\n+\n+impl Deref for Tendril {\n+    type Target = str;\n+\n+    #[inline]\n+    fn deref<'a>(&'a self) -> &'a str {\n+        match self.0 {\n+            Shared(ref s) => unsafe {\n+                mem::transmute(s.as_window_slice())\n+            },\n+            Owned(ref s) => s,\n+            Ascii(ref b) => unsafe {\n+                str::from_utf8_unchecked(slice::ref_slice(b))\n+            },\n+        }\n+    }\n+}\n+\n+/// Interpret the slice as a single ASCII codepoint, if possible.\n+#[inline(always)]\n+fn as_single_ascii(x: &str) -> Option<u8> {\n+    // &str is always valid UTF-8, so a one-byte &str must contain\n+    // an ASCII character.\n+    if x.len() == 1 {\n+        Some(unsafe { *x.as_bytes().get_unchecked(0) })\n+    } else {\n+        None\n+    }\n+}\n+\n+/// The maximum size of a tendril is 1 GB.\n+pub const TENDRIL_MAX_LEN: u32 = 1 << 30;\n+\n+impl Tendril {\n+    /// Create a new, empty tendril.\n+    #[inline]\n+    pub fn new() -> Tendril {\n+        Tendril(Owned(String::new()))\n+    }\n+\n+    /// Create a tendril from any `IntoTendril` type.\n+    #[inline]\n+    pub fn from<T>(x: T) -> Tendril\n+        where T: IntoTendril,\n+    {\n+        x.into_tendril()\n+    }\n+\n+    /// Create a tendril from a character.\n+    #[inline]\n+    pub fn from_char(c: char) -> Tendril {\n+        let n = c as usize;\n+        if n < 0x80 {\n+            Tendril(Ascii(n as u8))\n+        } else {\n+            Tendril(Owned(c.to_string()))\n+        }\n+    }\n+\n+    /// Create a tendril from a `String`, without copying.\n+    #[inline]\n+    pub fn owned(s: String) -> Tendril {\n+        assert!(s.len() < (1 << 31));\n+        Tendril(Owned(s))\n+    }\n+\n+    /// Copy a string to create a tendril which owns its content.\n+    #[inline]\n+    pub fn owned_copy(s: &str) -> Tendril {\n+        if let Some(n) = as_single_ascii(s) {\n+            Tendril(Ascii(n))\n+        } else {\n+            Tendril(Owned(String::from_str(s)))\n+        }\n+    }\n+\n+    /// Copy a string to create a shared buffer which multiple\n+    /// tendrils can point into.\n+    ///\n+    /// See also `subtendril`.\n+    #[inline]\n+    pub fn shared_copy(s: &str) -> Tendril {\n+        Tendril(Shared(ROIobuf::from_str_copy(s)))\n+    }\n+\n+    /// Does this tendril point into a shared buffer?\n+    #[inline]\n+    pub fn is_shared(&self) -> bool {\n+        match self.0 {\n+            Shared(_) => true,\n+            _ => false,\n+        }\n+    }\n+\n+    /// Get the length of the tendril.\n+    #[inline]\n+    pub fn len32(&self) -> u32 {\n+        match self.0 {\n+            Shared(ref b) => b.len(),\n+            Owned(ref s) => s.len() as u32,\n+            Ascii(_) => 1,\n+        }\n+    }\n+\n+    /// Count how many bytes at the beginning of the tendril\n+    /// either all match or all don't match the predicate,\n+    /// and also return whether they match.\n+    ///\n+    /// Returns `None` on an empty string.\n+    pub fn char_run<Pred>(&self, mut pred: Pred) -> Option<(u32, bool)>\n+        where Pred: FnMut(char) -> bool,\n+    {\n+        let (first, rest) = unwrap_or_return!(self.slice_shift_char(), None);\n+        let matches = pred(first);\n+\n+        for (idx, ch) in rest.char_indices() {\n+            if matches != pred(ch) {\n+                return Some(((idx + first.len_utf8()) as u32, matches));\n+            }\n+        }\n+        Some((self.len32(), matches))\n+    }\n+\n+    /// Promotes the tendril to owning its content, and get a\n+    /// mutable reference.\n+    ///\n+    /// This is unsafe because the user must not exceed the 1 GB\n+    /// size limit!\n+    #[inline]\n+    unsafe fn to_mut<'a>(&'a mut self) -> &'a mut String {\n+        match self.0 {\n+            Owned(ref mut s) => return s,\n+            _ => (),\n+        }\n+\n+        self.0 = Owned(String::from_str(self));\n+        match self.0 {\n+            Owned(ref mut s) => s,\n+            _ => unreachable!(),\n+        }\n+    }\n+\n+    #[inline(always)]\n+    fn check_len(&self) {\n+        if self.len() > TENDRIL_MAX_LEN as usize {\n+            panic!(\"tendril exceeded 1 GB\");\n+        }\n+    }\n+\n+    /// Push a character onto the end of the tendril.\n+    #[inline]\n+    pub fn push(&mut self, c: char) {\n+        if self.is_empty() {\n+            if let Some(a) = c.to_ascii_opt() {\n+                self.0 = Ascii(a.to_u8());\n+                return;\n+            }\n+        }\n+        unsafe {\n+            self.to_mut().push(c);\n+        }\n+        self.check_len();\n+    }\n+\n+    /// Push a string onto the end of the tendril.\n+    #[inline]\n+    pub fn push_str(&mut self, rhs: &str) {\n+        match rhs.len() {\n+            0 => return,\n+            1 if self.is_empty() => {\n+                if let Some(n) = as_single_ascii(rhs) {\n+                    self.0 = Ascii(n);\n+                    return;\n+                }\n+            }\n+            n if n > TENDRIL_MAX_LEN as usize => {\n+                panic!(\"attempted to extend tendril by more than 1 GB\");\n+            }\n+\n+            // Otherwise, 2 * TENDRIL_MAX_LEN does not overflow u32.","path":"src/util/tendril.rs","position":276,"original_position":276,"commit_id":"9ca1de005fef3f65e3914f899c06d759c9283261","original_commit_id":"9ca1de005fef3f65e3914f899c06d759c9283261","user":{"login":"cgaebel","id":128969,"avatar_url":"https://avatars.githubusercontent.com/u/128969?v=3","gravatar_id":"","url":"https://api.github.com/users/cgaebel","html_url":"https://github.com/cgaebel","followers_url":"https://api.github.com/users/cgaebel/followers","following_url":"https://api.github.com/users/cgaebel/following{/other_user}","gists_url":"https://api.github.com/users/cgaebel/gists{/gist_id}","starred_url":"https://api.github.com/users/cgaebel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cgaebel/subscriptions","organizations_url":"https://api.github.com/users/cgaebel/orgs","repos_url":"https://api.github.com/users/cgaebel/repos","events_url":"https://api.github.com/users/cgaebel/events{/privacy}","received_events_url":"https://api.github.com/users/cgaebel/received_events","type":"User","site_admin":false},"body":"One needs to worry about overflowing `i32`, not `u32`. I use a bit in one of the `u32` fields in iobuf to say whether or not the pointer is owned or borrowed.","created_at":"2015-03-25T13:50:19Z","updated_at":"2015-03-25T13:50:19Z","html_url":"https://github.com/servo/html5ever/pull/114#discussion_r27121229","pull_request_url":"https://api.github.com/repos/servo/html5ever/pulls/114","_links":{"self":{"href":"https://api.github.com/repos/servo/html5ever/pulls/comments/27121229"},"html":{"href":"https://github.com/servo/html5ever/pull/114#discussion_r27121229"},"pull_request":{"href":"https://api.github.com/repos/servo/html5ever/pulls/114"}}},"pull_request":{"url":"https://api.github.com/repos/servo/html5ever/pulls/114","id":31789918,"html_url":"https://github.com/servo/html5ever/pull/114","diff_url":"https://github.com/servo/html5ever/pull/114.diff","patch_url":"https://github.com/servo/html5ever/pull/114.patch","issue_url":"https://api.github.com/repos/servo/html5ever/issues/114","number":114,"state":"open","locked":false,"title":"Implement zero-copy parsing","user":{"login":"kmcallister","id":444997,"avatar_url":"https://avatars.githubusercontent.com/u/444997?v=3","gravatar_id":"","url":"https://api.github.com/users/kmcallister","html_url":"https://github.com/kmcallister","followers_url":"https://api.github.com/users/kmcallister/followers","following_url":"https://api.github.com/users/kmcallister/following{/other_user}","gists_url":"https://api.github.com/users/kmcallister/gists{/gist_id}","starred_url":"https://api.github.com/users/kmcallister/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kmcallister/subscriptions","organizations_url":"https://api.github.com/users/kmcallister/orgs","repos_url":"https://api.github.com/users/kmcallister/repos","events_url":"https://api.github.com/users/kmcallister/events{/privacy}","received_events_url":"https://api.github.com/users/kmcallister/received_events","type":"User","site_admin":false},"body":"This is based on #60 but with substantial changes. The biggest difference is that we only use shared buffers for the character runs found by `pop_except_from`. The majority of the remaining spans are single ASCII characters, which have their own fast path. Everything else is a `String` as before.\r\n\r\nThis branch also drops many of the micro-optimizations from #60. Unlike that PR, we leave the parser rules alone for the most part.\r\n\r\nr? @Manishearth or @SimonSapin (general review)\r\n\r\nr? @cgaebel (iobuf usage in `tendril.rs`)\r\n\r\nDepending on the specific content and the I/O chunk size, this branch speeds up tokenization by up to a few percent. I did not see any significant performance regressions with sensible chunk sizes.\r\n\r\nI have plans for further optimizations, including following up on the rustc bugs @cgaebel identified in #60.\r\n\r\nThe branch already achieves a significant drop in allocations and memory consumption:\r\n\r\n(preliminary numbers)\r\n\r\n### Webapp spec, single page:\r\n\r\npre-zerocopy\r\n\r\n```\r\n846,520 allocs, 37,567,992 bytes allocated\r\nmaximum resident: 11,248 kB\r\n```\r\n\r\nzerocopy\r\n\r\n```\r\n95,690 allocs, 25,698,480 bytes allocated\r\nmaximum resident: 3,648 kB\r\n```\r\n\r\n### Wikipedia (GotG from servo-static-suite)\r\n\r\npre-zerocopy\r\n\r\n```\r\n62,705 allocs, 2,299,424 bytes allocated\r\nmaximum resident: 3,948 kB\r\n```\r\n\r\nzerocopy\r\n\r\n```\r\n11,549 allocs, 2,355,984 bytes allocated\r\nmaximum resident: 3,596 kB\r\n```","created_at":"2015-03-24T01:23:49Z","updated_at":"2015-03-25T13:50:19Z","closed_at":null,"merged_at":null,"merge_commit_sha":"bf57b2e2d1ef8ecfa7c57f1892d5609b6140478f","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/servo/html5ever/pulls/114/commits","review_comments_url":"https://api.github.com/repos/servo/html5ever/pulls/114/comments","review_comment_url":"https://api.github.com/repos/servo/html5ever/pulls/comments{/number}","comments_url":"https://api.github.com/repos/servo/html5ever/issues/114/comments","statuses_url":"https://api.github.com/repos/servo/html5ever/statuses/9ca1de005fef3f65e3914f899c06d759c9283261","head":{"label":"kmcallister:zerocopy","ref":"zerocopy","sha":"9ca1de005fef3f65e3914f899c06d759c9283261","user":{"login":"kmcallister","id":444997,"avatar_url":"https://avatars.githubusercontent.com/u/444997?v=3","gravatar_id":"","url":"https://api.github.com/users/kmcallister","html_url":"https://github.com/kmcallister","followers_url":"https://api.github.com/users/kmcallister/followers","following_url":"https://api.github.com/users/kmcallister/following{/other_user}","gists_url":"https://api.github.com/users/kmcallister/gists{/gist_id}","starred_url":"https://api.github.com/users/kmcallister/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kmcallister/subscriptions","organizations_url":"https://api.github.com/users/kmcallister/orgs","repos_url":"https://api.github.com/users/kmcallister/repos","events_url":"https://api.github.com/users/kmcallister/events{/privacy}","received_events_url":"https://api.github.com/users/kmcallister/received_events","type":"User","site_admin":false},"repo":{"id":29552814,"name":"html5ever","full_name":"kmcallister/html5ever","owner":{"login":"kmcallister","id":444997,"avatar_url":"https://avatars.githubusercontent.com/u/444997?v=3","gravatar_id":"","url":"https://api.github.com/users/kmcallister","html_url":"https://github.com/kmcallister","followers_url":"https://api.github.com/users/kmcallister/followers","following_url":"https://api.github.com/users/kmcallister/following{/other_user}","gists_url":"https://api.github.com/users/kmcallister/gists{/gist_id}","starred_url":"https://api.github.com/users/kmcallister/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kmcallister/subscriptions","organizations_url":"https://api.github.com/users/kmcallister/orgs","repos_url":"https://api.github.com/users/kmcallister/repos","events_url":"https://api.github.com/users/kmcallister/events{/privacy}","received_events_url":"https://api.github.com/users/kmcallister/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/kmcallister/html5ever","description":"High-performance browser-grade HTML5 parser","fork":true,"url":"https://api.github.com/repos/kmcallister/html5ever","forks_url":"https://api.github.com/repos/kmcallister/html5ever/forks","keys_url":"https://api.github.com/repos/kmcallister/html5ever/keys{/key_id}","collaborators_url":"https://api.github.com/repos/kmcallister/html5ever/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/kmcallister/html5ever/teams","hooks_url":"https://api.github.com/repos/kmcallister/html5ever/hooks","issue_events_url":"https://api.github.com/repos/kmcallister/html5ever/issues/events{/number}","events_url":"https://api.github.com/repos/kmcallister/html5ever/events","assignees_url":"https://api.github.com/repos/kmcallister/html5ever/assignees{/user}","branches_url":"https://api.github.com/repos/kmcallister/html5ever/branches{/branch}","tags_url":"https://api.github.com/repos/kmcallister/html5ever/tags","blobs_url":"https://api.github.com/repos/kmcallister/html5ever/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/kmcallister/html5ever/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/kmcallister/html5ever/git/refs{/sha}","trees_url":"https://api.github.com/repos/kmcallister/html5ever/git/trees{/sha}","statuses_url":"https://api.github.com/repos/kmcallister/html5ever/statuses/{sha}","languages_url":"https://api.github.com/repos/kmcallister/html5ever/languages","stargazers_url":"https://api.github.com/repos/kmcallister/html5ever/stargazers","contributors_url":"https://api.github.com/repos/kmcallister/html5ever/contributors","subscribers_url":"https://api.github.com/repos/kmcallister/html5ever/subscribers","subscription_url":"https://api.github.com/repos/kmcallister/html5ever/subscription","commits_url":"https://api.github.com/repos/kmcallister/html5ever/commits{/sha}","git_commits_url":"https://api.github.com/repos/kmcallister/html5ever/git/commits{/sha}","comments_url":"https://api.github.com/repos/kmcallister/html5ever/comments{/number}","issue_comment_url":"https://api.github.com/repos/kmcallister/html5ever/issues/comments{/number}","contents_url":"https://api.github.com/repos/kmcallister/html5ever/contents/{+path}","compare_url":"https://api.github.com/repos/kmcallister/html5ever/compare/{base}...{head}","merges_url":"https://api.github.com/repos/kmcallister/html5ever/merges","archive_url":"https://api.github.com/repos/kmcallister/html5ever/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/kmcallister/html5ever/downloads","issues_url":"https://api.github.com/repos/kmcallister/html5ever/issues{/number}","pulls_url":"https://api.github.com/repos/kmcallister/html5ever/pulls{/number}","milestones_url":"https://api.github.com/repos/kmcallister/html5ever/milestones{/number}","notifications_url":"https://api.github.com/repos/kmcallister/html5ever/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/kmcallister/html5ever/labels{/name}","releases_url":"https://api.github.com/repos/kmcallister/html5ever/releases{/id}","created_at":"2015-01-20T21:22:35Z","updated_at":"2015-01-20T21:22:35Z","pushed_at":"2015-03-23T23:11:30Z","git_url":"git://github.com/kmcallister/html5ever.git","ssh_url":"git@github.com:kmcallister/html5ever.git","clone_url":"https://github.com/kmcallister/html5ever.git","svn_url":"https://github.com/kmcallister/html5ever","homepage":"","size":1513,"stargazers_count":0,"watchers_count":0,"language":"Rust","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"servo:master","ref":"master","sha":"ecd96056e8240ec875c13954087d3d0aa74f04a7","user":{"login":"servo","id":2566135,"avatar_url":"https://avatars.githubusercontent.com/u/2566135?v=3","gravatar_id":"","url":"https://api.github.com/users/servo","html_url":"https://github.com/servo","followers_url":"https://api.github.com/users/servo/followers","following_url":"https://api.github.com/users/servo/following{/other_user}","gists_url":"https://api.github.com/users/servo/gists{/gist_id}","starred_url":"https://api.github.com/users/servo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/servo/subscriptions","organizations_url":"https://api.github.com/users/servo/orgs","repos_url":"https://api.github.com/users/servo/repos","events_url":"https://api.github.com/users/servo/events{/privacy}","received_events_url":"https://api.github.com/users/servo/received_events","type":"Organization","site_admin":false},"repo":{"id":17691231,"name":"html5ever","full_name":"servo/html5ever","owner":{"login":"servo","id":2566135,"avatar_url":"https://avatars.githubusercontent.com/u/2566135?v=3","gravatar_id":"","url":"https://api.github.com/users/servo","html_url":"https://github.com/servo","followers_url":"https://api.github.com/users/servo/followers","following_url":"https://api.github.com/users/servo/following{/other_user}","gists_url":"https://api.github.com/users/servo/gists{/gist_id}","starred_url":"https://api.github.com/users/servo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/servo/subscriptions","organizations_url":"https://api.github.com/users/servo/orgs","repos_url":"https://api.github.com/users/servo/repos","events_url":"https://api.github.com/users/servo/events{/privacy}","received_events_url":"https://api.github.com/users/servo/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/servo/html5ever","description":"High-performance browser-grade HTML5 parser","fork":false,"url":"https://api.github.com/repos/servo/html5ever","forks_url":"https://api.github.com/repos/servo/html5ever/forks","keys_url":"https://api.github.com/repos/servo/html5ever/keys{/key_id}","collaborators_url":"https://api.github.com/repos/servo/html5ever/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/servo/html5ever/teams","hooks_url":"https://api.github.com/repos/servo/html5ever/hooks","issue_events_url":"https://api.github.com/repos/servo/html5ever/issues/events{/number}","events_url":"https://api.github.com/repos/servo/html5ever/events","assignees_url":"https://api.github.com/repos/servo/html5ever/assignees{/user}","branches_url":"https://api.github.com/repos/servo/html5ever/branches{/branch}","tags_url":"https://api.github.com/repos/servo/html5ever/tags","blobs_url":"https://api.github.com/repos/servo/html5ever/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/servo/html5ever/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/servo/html5ever/git/refs{/sha}","trees_url":"https://api.github.com/repos/servo/html5ever/git/trees{/sha}","statuses_url":"https://api.github.com/repos/servo/html5ever/statuses/{sha}","languages_url":"https://api.github.com/repos/servo/html5ever/languages","stargazers_url":"https://api.github.com/repos/servo/html5ever/stargazers","contributors_url":"https://api.github.com/repos/servo/html5ever/contributors","subscribers_url":"https://api.github.com/repos/servo/html5ever/subscribers","subscription_url":"https://api.github.com/repos/servo/html5ever/subscription","commits_url":"https://api.github.com/repos/servo/html5ever/commits{/sha}","git_commits_url":"https://api.github.com/repos/servo/html5ever/git/commits{/sha}","comments_url":"https://api.github.com/repos/servo/html5ever/comments{/number}","issue_comment_url":"https://api.github.com/repos/servo/html5ever/issues/comments{/number}","contents_url":"https://api.github.com/repos/servo/html5ever/contents/{+path}","compare_url":"https://api.github.com/repos/servo/html5ever/compare/{base}...{head}","merges_url":"https://api.github.com/repos/servo/html5ever/merges","archive_url":"https://api.github.com/repos/servo/html5ever/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/servo/html5ever/downloads","issues_url":"https://api.github.com/repos/servo/html5ever/issues{/number}","pulls_url":"https://api.github.com/repos/servo/html5ever/pulls{/number}","milestones_url":"https://api.github.com/repos/servo/html5ever/milestones{/number}","notifications_url":"https://api.github.com/repos/servo/html5ever/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/servo/html5ever/labels{/name}","releases_url":"https://api.github.com/repos/servo/html5ever/releases{/id}","created_at":"2014-03-13T02:04:18Z","updated_at":"2015-03-23T17:05:06Z","pushed_at":"2015-03-24T01:23:49Z","git_url":"git://github.com/servo/html5ever.git","ssh_url":"git@github.com:servo/html5ever.git","clone_url":"https://github.com/servo/html5ever.git","svn_url":"https://github.com/servo/html5ever","homepage":"","size":3419,"stargazers_count":144,"watchers_count":144,"language":"Rust","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":28,"mirror_url":null,"open_issues_count":43,"forks":28,"open_issues":43,"watchers":144,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/servo/html5ever/pulls/114"},"html":{"href":"https://github.com/servo/html5ever/pull/114"},"issue":{"href":"https://api.github.com/repos/servo/html5ever/issues/114"},"comments":{"href":"https://api.github.com/repos/servo/html5ever/issues/114/comments"},"review_comments":{"href":"https://api.github.com/repos/servo/html5ever/pulls/114/comments"},"review_comment":{"href":"https://api.github.com/repos/servo/html5ever/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/servo/html5ever/pulls/114/commits"},"statuses":{"href":"https://api.github.com/repos/servo/html5ever/statuses/9ca1de005fef3f65e3914f899c06d759c9283261"}}}}