{"action":"created","comment":{"url":"https://api.github.com/repos/cryptosense/key-parsers/pulls/comments/75471707","id":75471707,"diff_hunk":"@@ -615,11 +667,263 @@ struct\n     map f g @@ sequence2\n       (required ~label:\"algorithm\" Algo.grammar)\n       (required ~label:\"parameters\" DH.Params.grammar)\n+\n end\n \n let map_result f = function Result.Ok x -> Result.Ok (f x) | Result.Error _ as r -> r\n let default_result default = function Result.Error _ -> default () | Result.Ok _ as r -> r\n \n+module CVC = struct\n+  let rsa_oid = Asn.OID.of_string \"0.4.0.127.0.7.2.2.2.1.4\"\n+  let ecdsa_oid = Asn.OID.of_string \"0.4.0.127.0.7.2.2.2.2.3\"\n+\n+  type t =\n+    [ `RSA of RSA_CVC.Public.t | `ECDSA of ECDSA_CVC.Public.t | `UNKNOWN ]\n+\n+  type algo_typ =\n+    | RSA\n+    | ECDSA\n+    | Unknown of Asn.OID.t\n+\n+  type parser_state =\n+    | Init\n+    | Type\n+    | Length\n+    | Value of int\n+\n+  let cvc_object_types =\n+    [ 0x7F21, (`CV_CERTIFICATE, true)\n+    ; 0x7F4E, (`CERTIFICATE_BODY, true)\n+    ; 0x5F29, (`PROFILE_IDENTIFIER, false)\n+    ; 0x7F49, (`PUBLIC_KEY, true)\n+    ; 0x5F20, (`HOLDER_REFERENCE, false)\n+    ; 0x7F4C, (`HOLDER_AUTH_TEMPLATE, true)\n+    ; 0x5F25, (`EFFECTIVE_DATE, false)\n+    ; 0x5F24, (`EXPIRATION_DATE, false)\n+    ; 0x5F37, (`SIGNATURE, false)\n+    ; 0x06, (`OID, false)\n+    ; 0x42, (`CA_REFERENCE, false)\n+    ; 0x67, (`REQ_AUTHENTICATION, true)\n+    ; 0x53, (`ROLE_AND_ACCESS_RIGHTS, false)\n+    ; 0x81, (`MODULUS, false)\n+    ; 0x82, (`EXPONENT, false)\n+    ; 0x82, (`COEFFICIENT_A, false)\n+    ; 0x83, (`COEFFICIENT_B, false)\n+    ; 0x84, (`BASE_POINT_G, false)\n+    ; 0x85, (`BASE_POINT_R_ORDER, false)\n+    ; 0x86, (`PUBLIC_POINT_Y, false)\n+    ; 0x87, (`COFACTOR_F, false)\n+    ]\n+\n+  let find_cvc_object_type tag =\n+    let code =\n+      Cstruct.get_char tag 0\n+      |> Char.code\n+    in\n+    try code, List.assoc code cvc_object_types\n+    with Not_found ->\n+      let code =\n+        let msb = code * 0x100 in\n+        let lsb =\n+          Cstruct.get_char tag 1\n+          |> Char.code\n+        in\n+        msb + lsb\n+      in\n+      code, List.assoc code cvc_object_types\n+\n+  (* utility function to parse a big-endian blob as a Z.t *)\n+  let atoz_bigendian s =\n+    let reverse s =\n+      let n = String.length s in\n+      String.init n (fun i -> s.[n-1-i])\n+    in\n+    Z.of_bits @@ reverse @@ Cstruct.to_string s\n+\n+  let grammar =\n+    let open Asn in\n+    let f = function\n+      | oid when oid = rsa_oid -> RSA\n+      | oid when oid = ecdsa_oid -> ECDSA\n+      | oid -> Unknown oid in\n+    let g = function\n+      | RSA -> rsa_oid\n+      | ECDSA -> ecdsa_oid\n+      | Unknown oid -> oid in\n+    map f g oid\n+\n+  let decode_oid str =\n+    let t, left = Asn.(decode_exn (codec ber grammar) str) in\n+    t\n+\n+  let decode bytes =\n+    let buffer = Cstruct.create 4_096 in\n+    (* FSM to produce `Type ..., `Length ..., `Value ... tokens from a blob.\n+     * This tries to exploit tailcall recursion as much as possible in order to\n+     * avoid a stack explosion\n+     *)\n+    let rec tokenize ~acc bytes i lim state = function\n+      | Init ->\n+          if i >= lim then List.rev acc\n+          else tokenize ~acc bytes i lim None Type\n+      | Type ->\n+          Cstruct.blit bytes i buffer 0 2;\n+          let cvc_type = find_cvc_object_type buffer in\n+          let acc = `Type cvc_type :: acc in\n+          begin match cvc_type with\n+            | tag, _ when tag <= 0xff ->\n+                let i = i + 1 in\n+                (tokenize[@tailcall]) ~acc bytes i lim (Some cvc_type) Length\n+            | tag, _ ->\n+                let i = i + 2 in\n+                (tokenize[@tailcall]) ~acc bytes i lim (Some cvc_type) Length\n+          end\n+      | Length ->\n+          let code = Char.code (Cstruct.get_char bytes i) in\n+          if code < 0x80\n+          then begin\n+            let i = i + 1 in\n+            (tokenize[@tailcall]) ~acc:((`Length code) :: acc) bytes i lim state (Value code)\n+          end\n+          else\n+            begin match code with\n+              | 0x81 ->\n+                  let code = Char.code (Cstruct.get_char bytes (i + 1)) in\n+                  let i = i + 2 in\n+                  (tokenize[@tailcall]) ~acc:((`Length code) :: acc) bytes i lim state (Value code)\n+              | 0x82 ->\n+                  let code =\n+                    let msb = Char.code (Cstruct.get_char bytes (i + 1)) * 0x100 in\n+                    let lsb = Char.code (Cstruct.get_char bytes (i + 2)) in\n+                    msb + lsb\n+                  in\n+                  let i = i + 3 in\n+                  (tokenize[@tailcall]) ~acc:((`Length code) :: acc) bytes i lim state (Value code)\n+              | _ ->\n+                  raise (Failure \"Invalid LENGTH field in TLV encoded CVC data\")\n+            end\n+      | Value length ->\n+          let is_rec =\n+            match state with\n+              | None -> false\n+              | Some (_, (_, x)) -> x\n+          in\n+          let acc =\n+            if is_rec\n+            then\n+              `Value (tokenize ~acc:[] bytes i (i + length) None Init) :: acc\n+            else\n+              let bytes' =\n+                Cstruct.sub bytes i length\n+              in\n+              `Bytes bytes' :: acc\n+          in\n+          (if length + i >= Cstruct.len bytes then List.rev acc else (tokenize[@tailcall]) ~acc bytes (i + length) lim None Init)\n+    in\n+    let tokens = tokenize ~acc:[] bytes 0 (Cstruct.len bytes) None Init in\n+    let rec parse = function\n+      | `Type (_, (`PUBLIC_KEY, _)) :: `Length _ :: `Value ls :: _ ->\n+          parse ls\n+      | `Type (_, (`OID, _)) :: `Length _ :: `Bytes bytes :: tl ->\n+          let bytes =\n+            let prefix =\n+              Printf.sprintf \"\\006%c\" (Char.chr (Cstruct.len bytes))\n+              |> Cstruct.of_string\n+            in\n+            Cstruct.append prefix bytes\n+          in\n+          `Oid (decode_oid bytes) :: parse tl\n+      | `Type (_, (`MODULUS, _)) :: `Length _ :: `Bytes bytes :: tl ->\n+          `Modulus (atoz_bigendian bytes) :: parse tl\n+      | `Type (0x82, ((*`EXPONENT*) _ , _)) :: `Length _ :: `Bytes bytes :: tl ->\n+          `Exponent (atoz_bigendian bytes) :: parse tl\n+      | `Type (_, (`COEFFICIENT_B, _)) :: `Length _ :: `Bytes bytes :: tl ->\n+          `Coefficient_b (atoz_bigendian bytes) :: parse tl\n+      | `Type (_, (`BASE_POINT_G, _)) :: `Length _ :: `Bytes bytes :: tl ->\n+          `Base_point_g (atoz_bigendian bytes) :: parse tl\n+      | `Type (_, (`BASE_POINT_R_ORDER, _)) :: `Length _ :: `Bytes bytes :: tl ->\n+          `Base_point_r_order (atoz_bigendian bytes) :: parse tl\n+      | `Type (_, (`PUBLIC_POINT_Y, _)) :: `Length _ :: `Bytes bytes :: tl ->\n+          `Public_point_y (atoz_bigendian bytes) :: parse tl\n+      | `Type (_, (`COFACTOR_F, _)) :: `Length _ :: `Bytes bytes :: tl ->\n+          `Cofactor_f (atoz_bigendian bytes) :: parse tl\n+      | [] ->\n+          []\n+      | `Type (t, _) :: tl ->\n+          let () = Printf.printf \"`Type (0x%x, _) :: tl found\\n\" t in\n+          parse tl\n+      | `Length _ :: tl ->\n+          let () = Printf.printf \"`Length _ :: tl found\\n\" in\n+          parse tl\n+      | `Bytes _ :: tl ->\n+          let () = Printf.printf \"`Bytes _ :: tl found\\n\" in\n+          parse tl\n+      | `Value _ :: tl ->\n+          let () = Printf.printf \"`Value _ :: tl found\\n\" in\n+          parse tl\n+      | _ ->\n+          raise (Failure \"unaccounted for case\")\n+    in\n+    let symbols = parse tokens in\n+    let oid =\n+      try\n+        List.find (function `Oid x -> true | _ -> false) symbols\n+      with Not_found -> `Oid (Unknown (Asn.OID.of_string \"0.0.0.0.0.0.0.0.0.0\"))\n+    in\n+    let open Result in\n+    match oid with\n+      | `Oid RSA ->\n+          Ok (\n+            `RSA\n+              RSA_CVC.Public.(\n+                let n =\n+                  List.fold_left (fun acc x -> (match x with `Modulus x -> [x] | _ -> []) @ acc) [] symbols\n+                  |> List.hd\n+                in\n+                let e =\n+                  List.fold_left (fun acc x -> (match x with `Exponent x -> [x] | _ -> []) @ acc) [] symbols\n+                  |> List.hd\n+                in\n+                {n; e}))\n+      | `Oid ECDSA ->\n+          Ok\n+            (`ECDSA\n+              ECDSA_CVC.Public.(\n+                let modulus =\n+                  List.fold_left (fun acc x -> (match x with `Modulus x -> [x] | _ -> []) @ acc) [] symbols\n+                  |> List.hd\n+                in\n+                let coefficient_a =\n+                  List.fold_left (fun acc x -> (match x with `Coefficient_a x | `Exponent x -> [x] | _ -> []) @ acc) [] symbols\n+                  |> List.hd\n+                in\n+                let coefficient_b =\n+                  List.fold_left (fun acc x -> (match x with `Coefficient_b x -> [x] | _ -> []) @ acc) [] symbols\n+                  |> List.hd\n+                in\n+                let base_point_g =\n+                  List.fold_left (fun acc x -> (match x with `Base_point_g x -> [x] | _ -> []) @ acc) [] symbols\n+                  |> List.hd\n+                in\n+                let base_point_r_order =\n+                  List.fold_left (fun acc x -> (match x with `Base_point_r_order x -> [x] | _ -> []) @ acc) [] symbols\n+                  |> List.hd\n+                in\n+                let public_point_y =\n+                  List.fold_left (fun acc x -> (match x with `Public_point_y x -> [x] | _ -> []) @ acc) [] symbols\n+                  |> List.hd\n+                in\n+                let cofactor_f =\n+                  List.fold_left (fun acc x -> (match x with `Cofactor_f x -> [x] | _ -> []) @ acc) [] symbols\n+                  |> List.hd\n+                in\n+                { modulus; coefficient_a; coefficient_b; base_point_g; base_point_r_order; public_point_y; cofactor_f }))\n+      | `Oid (Unknown oid) -> Error (Printf.sprintf \"unknown OID \\\"%s\\\".\" (Asn.OID.to_string oid))\n+      | _ ->\n+          Error \"This should be impossible, if you're seeing this message please report.\"","path":"src/asn1.ml","position":316,"original_position":316,"commit_id":"f506234454f454307d0f4e14ec35d91a2d11c6cc","original_commit_id":"f506234454f454307d0f4e14ec35d91a2d11c6cc","user":{"login":"emillon","id":496345,"avatar_url":"https://avatars.githubusercontent.com/u/496345?v=3","gravatar_id":"","url":"https://api.github.com/users/emillon","html_url":"https://github.com/emillon","followers_url":"https://api.github.com/users/emillon/followers","following_url":"https://api.github.com/users/emillon/following{/other_user}","gists_url":"https://api.github.com/users/emillon/gists{/gist_id}","starred_url":"https://api.github.com/users/emillon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/emillon/subscriptions","organizations_url":"https://api.github.com/users/emillon/orgs","repos_url":"https://api.github.com/users/emillon/repos","events_url":"https://api.github.com/users/emillon/events{/privacy}","received_events_url":"https://api.github.com/users/emillon/received_events","type":"User","site_admin":false},"body":"You can remove this case by replacing the `List.find` call above by a function that returns an `oid option` instead of a `[> `Oid of oid]`. It's not in the standard library but you can copy for example [https://github.com/cryptosense/ocamllint/blob/39b1c8c4c4bf95db9d28fdd1ecf12b7d4d2650c4/rules.ml#L209-L216](this one).","created_at":"2016-08-19T12:23:00Z","updated_at":"2016-08-19T12:23:00Z","html_url":"https://github.com/cryptosense/key-parsers/pull/13#discussion_r75471707","pull_request_url":"https://api.github.com/repos/cryptosense/key-parsers/pulls/13","_links":{"self":{"href":"https://api.github.com/repos/cryptosense/key-parsers/pulls/comments/75471707"},"html":{"href":"https://github.com/cryptosense/key-parsers/pull/13#discussion_r75471707"},"pull_request":{"href":"https://api.github.com/repos/cryptosense/key-parsers/pulls/13"}}},"pull_request":{"url":"https://api.github.com/repos/cryptosense/key-parsers/pulls/13","id":81953387,"html_url":"https://github.com/cryptosense/key-parsers/pull/13","diff_url":"https://github.com/cryptosense/key-parsers/pull/13.diff","patch_url":"https://github.com/cryptosense/key-parsers/pull/13.patch","issue_url":"https://api.github.com/repos/cryptosense/key-parsers/issues/13","number":13,"state":"open","locked":false,"title":"Feat/cvc","user":{"login":"chrismamo1","id":3238755,"avatar_url":"https://avatars.githubusercontent.com/u/3238755?v=3","gravatar_id":"","url":"https://api.github.com/users/chrismamo1","html_url":"https://github.com/chrismamo1","followers_url":"https://api.github.com/users/chrismamo1/followers","following_url":"https://api.github.com/users/chrismamo1/following{/other_user}","gists_url":"https://api.github.com/users/chrismamo1/gists{/gist_id}","starred_url":"https://api.github.com/users/chrismamo1/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/chrismamo1/subscriptions","organizations_url":"https://api.github.com/users/chrismamo1/orgs","repos_url":"https://api.github.com/users/chrismamo1/repos","events_url":"https://api.github.com/users/chrismamo1/events{/privacy}","received_events_url":"https://api.github.com/users/chrismamo1/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-08-19T09:41:46Z","updated_at":"2016-08-19T12:23:00Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c532499ba8c2dc229c78f248dc1a5c4864909dd6","assignee":{"login":"emillon","id":496345,"avatar_url":"https://avatars.githubusercontent.com/u/496345?v=3","gravatar_id":"","url":"https://api.github.com/users/emillon","html_url":"https://github.com/emillon","followers_url":"https://api.github.com/users/emillon/followers","following_url":"https://api.github.com/users/emillon/following{/other_user}","gists_url":"https://api.github.com/users/emillon/gists{/gist_id}","starred_url":"https://api.github.com/users/emillon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/emillon/subscriptions","organizations_url":"https://api.github.com/users/emillon/orgs","repos_url":"https://api.github.com/users/emillon/repos","events_url":"https://api.github.com/users/emillon/events{/privacy}","received_events_url":"https://api.github.com/users/emillon/received_events","type":"User","site_admin":false},"assignees":[{"login":"emillon","id":496345,"avatar_url":"https://avatars.githubusercontent.com/u/496345?v=3","gravatar_id":"","url":"https://api.github.com/users/emillon","html_url":"https://github.com/emillon","followers_url":"https://api.github.com/users/emillon/followers","following_url":"https://api.github.com/users/emillon/following{/other_user}","gists_url":"https://api.github.com/users/emillon/gists{/gist_id}","starred_url":"https://api.github.com/users/emillon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/emillon/subscriptions","organizations_url":"https://api.github.com/users/emillon/orgs","repos_url":"https://api.github.com/users/emillon/repos","events_url":"https://api.github.com/users/emillon/events{/privacy}","received_events_url":"https://api.github.com/users/emillon/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/cryptosense/key-parsers/pulls/13/commits","review_comments_url":"https://api.github.com/repos/cryptosense/key-parsers/pulls/13/comments","review_comment_url":"https://api.github.com/repos/cryptosense/key-parsers/pulls/comments{/number}","comments_url":"https://api.github.com/repos/cryptosense/key-parsers/issues/13/comments","statuses_url":"https://api.github.com/repos/cryptosense/key-parsers/statuses/f506234454f454307d0f4e14ec35d91a2d11c6cc","head":{"label":"chrismamo1:feat/CVC","ref":"feat/CVC","sha":"f506234454f454307d0f4e14ec35d91a2d11c6cc","user":{"login":"chrismamo1","id":3238755,"avatar_url":"https://avatars.githubusercontent.com/u/3238755?v=3","gravatar_id":"","url":"https://api.github.com/users/chrismamo1","html_url":"https://github.com/chrismamo1","followers_url":"https://api.github.com/users/chrismamo1/followers","following_url":"https://api.github.com/users/chrismamo1/following{/other_user}","gists_url":"https://api.github.com/users/chrismamo1/gists{/gist_id}","starred_url":"https://api.github.com/users/chrismamo1/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/chrismamo1/subscriptions","organizations_url":"https://api.github.com/users/chrismamo1/orgs","repos_url":"https://api.github.com/users/chrismamo1/repos","events_url":"https://api.github.com/users/chrismamo1/events{/privacy}","received_events_url":"https://api.github.com/users/chrismamo1/received_events","type":"User","site_admin":false},"repo":{"id":65831930,"name":"key-parsers","full_name":"chrismamo1/key-parsers","owner":{"login":"chrismamo1","id":3238755,"avatar_url":"https://avatars.githubusercontent.com/u/3238755?v=3","gravatar_id":"","url":"https://api.github.com/users/chrismamo1","html_url":"https://github.com/chrismamo1","followers_url":"https://api.github.com/users/chrismamo1/followers","following_url":"https://api.github.com/users/chrismamo1/following{/other_user}","gists_url":"https://api.github.com/users/chrismamo1/gists{/gist_id}","starred_url":"https://api.github.com/users/chrismamo1/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/chrismamo1/subscriptions","organizations_url":"https://api.github.com/users/chrismamo1/orgs","repos_url":"https://api.github.com/users/chrismamo1/repos","events_url":"https://api.github.com/users/chrismamo1/events{/privacy}","received_events_url":"https://api.github.com/users/chrismamo1/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/chrismamo1/key-parsers","description":"OCaml parsers for multiple key formats","fork":true,"url":"https://api.github.com/repos/chrismamo1/key-parsers","forks_url":"https://api.github.com/repos/chrismamo1/key-parsers/forks","keys_url":"https://api.github.com/repos/chrismamo1/key-parsers/keys{/key_id}","collaborators_url":"https://api.github.com/repos/chrismamo1/key-parsers/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/chrismamo1/key-parsers/teams","hooks_url":"https://api.github.com/repos/chrismamo1/key-parsers/hooks","issue_events_url":"https://api.github.com/repos/chrismamo1/key-parsers/issues/events{/number}","events_url":"https://api.github.com/repos/chrismamo1/key-parsers/events","assignees_url":"https://api.github.com/repos/chrismamo1/key-parsers/assignees{/user}","branches_url":"https://api.github.com/repos/chrismamo1/key-parsers/branches{/branch}","tags_url":"https://api.github.com/repos/chrismamo1/key-parsers/tags","blobs_url":"https://api.github.com/repos/chrismamo1/key-parsers/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/chrismamo1/key-parsers/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/chrismamo1/key-parsers/git/refs{/sha}","trees_url":"https://api.github.com/repos/chrismamo1/key-parsers/git/trees{/sha}","statuses_url":"https://api.github.com/repos/chrismamo1/key-parsers/statuses/{sha}","languages_url":"https://api.github.com/repos/chrismamo1/key-parsers/languages","stargazers_url":"https://api.github.com/repos/chrismamo1/key-parsers/stargazers","contributors_url":"https://api.github.com/repos/chrismamo1/key-parsers/contributors","subscribers_url":"https://api.github.com/repos/chrismamo1/key-parsers/subscribers","subscription_url":"https://api.github.com/repos/chrismamo1/key-parsers/subscription","commits_url":"https://api.github.com/repos/chrismamo1/key-parsers/commits{/sha}","git_commits_url":"https://api.github.com/repos/chrismamo1/key-parsers/git/commits{/sha}","comments_url":"https://api.github.com/repos/chrismamo1/key-parsers/comments{/number}","issue_comment_url":"https://api.github.com/repos/chrismamo1/key-parsers/issues/comments{/number}","contents_url":"https://api.github.com/repos/chrismamo1/key-parsers/contents/{+path}","compare_url":"https://api.github.com/repos/chrismamo1/key-parsers/compare/{base}...{head}","merges_url":"https://api.github.com/repos/chrismamo1/key-parsers/merges","archive_url":"https://api.github.com/repos/chrismamo1/key-parsers/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/chrismamo1/key-parsers/downloads","issues_url":"https://api.github.com/repos/chrismamo1/key-parsers/issues{/number}","pulls_url":"https://api.github.com/repos/chrismamo1/key-parsers/pulls{/number}","milestones_url":"https://api.github.com/repos/chrismamo1/key-parsers/milestones{/number}","notifications_url":"https://api.github.com/repos/chrismamo1/key-parsers/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/chrismamo1/key-parsers/labels{/name}","releases_url":"https://api.github.com/repos/chrismamo1/key-parsers/releases{/id}","deployments_url":"https://api.github.com/repos/chrismamo1/key-parsers/deployments","created_at":"2016-08-16T15:32:45Z","updated_at":"2016-08-16T15:32:47Z","pushed_at":"2016-08-19T09:41:12Z","git_url":"git://github.com/chrismamo1/key-parsers.git","ssh_url":"git@github.com:chrismamo1/key-parsers.git","clone_url":"https://github.com/chrismamo1/key-parsers.git","svn_url":"https://github.com/chrismamo1/key-parsers","homepage":null,"size":48,"stargazers_count":0,"watchers_count":0,"language":"OCaml","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":"cryptosense:master","ref":"master","sha":"f91b3cf8d07569ec5c2a9c5eb52b7d59da1cb8ea","user":{"login":"cryptosense","id":4948867,"avatar_url":"https://avatars.githubusercontent.com/u/4948867?v=3","gravatar_id":"","url":"https://api.github.com/users/cryptosense","html_url":"https://github.com/cryptosense","followers_url":"https://api.github.com/users/cryptosense/followers","following_url":"https://api.github.com/users/cryptosense/following{/other_user}","gists_url":"https://api.github.com/users/cryptosense/gists{/gist_id}","starred_url":"https://api.github.com/users/cryptosense/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cryptosense/subscriptions","organizations_url":"https://api.github.com/users/cryptosense/orgs","repos_url":"https://api.github.com/users/cryptosense/repos","events_url":"https://api.github.com/users/cryptosense/events{/privacy}","received_events_url":"https://api.github.com/users/cryptosense/received_events","type":"Organization","site_admin":false},"repo":{"id":45904114,"name":"key-parsers","full_name":"cryptosense/key-parsers","owner":{"login":"cryptosense","id":4948867,"avatar_url":"https://avatars.githubusercontent.com/u/4948867?v=3","gravatar_id":"","url":"https://api.github.com/users/cryptosense","html_url":"https://github.com/cryptosense","followers_url":"https://api.github.com/users/cryptosense/followers","following_url":"https://api.github.com/users/cryptosense/following{/other_user}","gists_url":"https://api.github.com/users/cryptosense/gists{/gist_id}","starred_url":"https://api.github.com/users/cryptosense/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cryptosense/subscriptions","organizations_url":"https://api.github.com/users/cryptosense/orgs","repos_url":"https://api.github.com/users/cryptosense/repos","events_url":"https://api.github.com/users/cryptosense/events{/privacy}","received_events_url":"https://api.github.com/users/cryptosense/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/cryptosense/key-parsers","description":"OCaml parsers for multiple key formats","fork":false,"url":"https://api.github.com/repos/cryptosense/key-parsers","forks_url":"https://api.github.com/repos/cryptosense/key-parsers/forks","keys_url":"https://api.github.com/repos/cryptosense/key-parsers/keys{/key_id}","collaborators_url":"https://api.github.com/repos/cryptosense/key-parsers/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/cryptosense/key-parsers/teams","hooks_url":"https://api.github.com/repos/cryptosense/key-parsers/hooks","issue_events_url":"https://api.github.com/repos/cryptosense/key-parsers/issues/events{/number}","events_url":"https://api.github.com/repos/cryptosense/key-parsers/events","assignees_url":"https://api.github.com/repos/cryptosense/key-parsers/assignees{/user}","branches_url":"https://api.github.com/repos/cryptosense/key-parsers/branches{/branch}","tags_url":"https://api.github.com/repos/cryptosense/key-parsers/tags","blobs_url":"https://api.github.com/repos/cryptosense/key-parsers/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/cryptosense/key-parsers/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/cryptosense/key-parsers/git/refs{/sha}","trees_url":"https://api.github.com/repos/cryptosense/key-parsers/git/trees{/sha}","statuses_url":"https://api.github.com/repos/cryptosense/key-parsers/statuses/{sha}","languages_url":"https://api.github.com/repos/cryptosense/key-parsers/languages","stargazers_url":"https://api.github.com/repos/cryptosense/key-parsers/stargazers","contributors_url":"https://api.github.com/repos/cryptosense/key-parsers/contributors","subscribers_url":"https://api.github.com/repos/cryptosense/key-parsers/subscribers","subscription_url":"https://api.github.com/repos/cryptosense/key-parsers/subscription","commits_url":"https://api.github.com/repos/cryptosense/key-parsers/commits{/sha}","git_commits_url":"https://api.github.com/repos/cryptosense/key-parsers/git/commits{/sha}","comments_url":"https://api.github.com/repos/cryptosense/key-parsers/comments{/number}","issue_comment_url":"https://api.github.com/repos/cryptosense/key-parsers/issues/comments{/number}","contents_url":"https://api.github.com/repos/cryptosense/key-parsers/contents/{+path}","compare_url":"https://api.github.com/repos/cryptosense/key-parsers/compare/{base}...{head}","merges_url":"https://api.github.com/repos/cryptosense/key-parsers/merges","archive_url":"https://api.github.com/repos/cryptosense/key-parsers/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/cryptosense/key-parsers/downloads","issues_url":"https://api.github.com/repos/cryptosense/key-parsers/issues{/number}","pulls_url":"https://api.github.com/repos/cryptosense/key-parsers/pulls{/number}","milestones_url":"https://api.github.com/repos/cryptosense/key-parsers/milestones{/number}","notifications_url":"https://api.github.com/repos/cryptosense/key-parsers/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/cryptosense/key-parsers/labels{/name}","releases_url":"https://api.github.com/repos/cryptosense/key-parsers/releases{/id}","deployments_url":"https://api.github.com/repos/cryptosense/key-parsers/deployments","created_at":"2015-11-10T10:15:39Z","updated_at":"2016-08-16T17:11:31Z","pushed_at":"2016-08-19T11:16:40Z","git_url":"git://github.com/cryptosense/key-parsers.git","ssh_url":"git@github.com:cryptosense/key-parsers.git","clone_url":"https://github.com/cryptosense/key-parsers.git","svn_url":"https://github.com/cryptosense/key-parsers","homepage":null,"size":52,"stargazers_count":6,"watchers_count":6,"language":"OCaml","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":4,"forks":2,"open_issues":4,"watchers":6,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/cryptosense/key-parsers/pulls/13"},"html":{"href":"https://github.com/cryptosense/key-parsers/pull/13"},"issue":{"href":"https://api.github.com/repos/cryptosense/key-parsers/issues/13"},"comments":{"href":"https://api.github.com/repos/cryptosense/key-parsers/issues/13/comments"},"review_comments":{"href":"https://api.github.com/repos/cryptosense/key-parsers/pulls/13/comments"},"review_comment":{"href":"https://api.github.com/repos/cryptosense/key-parsers/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/cryptosense/key-parsers/pulls/13/commits"},"statuses":{"href":"https://api.github.com/repos/cryptosense/key-parsers/statuses/f506234454f454307d0f4e14ec35d91a2d11c6cc"}}}}
{"actor":{"display_login":"emillon"}}