{"action":"created","comment":{"url":"https://api.github.com/repos/Microsoft/visualfsharp/pulls/comments/44420630","id":44420630,"diff_hunk":"@@ -0,0 +1,204 @@\n+module PlatformHelpers\n+\n+type ProcessorArchitecture = \n+    | X86\n+    | IA64\n+    | AMD64\n+    | Unknown of string\n+    override this.ToString() = \n+        match this with\n+        | X86 -> \"x86\"\n+        | IA64 -> \"IA64\"\n+        | AMD64 -> \"AMD64\"\n+        | Unknown arc -> arc\n+\n+open System.IO\n+\n+type FilePath = string\n+\n+type CmdResult = \n+    | Success\n+    | ErrorLevel of int\n+\n+type CmdArguments = \n+    { RedirectOutput : (string -> unit) option\n+      RedirectError : (string -> unit) option\n+      RedirectInput : (StreamWriter -> unit) option }\n+\n+module Process =\n+\n+    open System.Diagnostics\n+\n+    let processExePath baseDir exe =\n+        if Path.IsPathRooted(exe) then exe\n+        else \n+            match Path.GetDirectoryName(exe) with\n+            | \"\" -> exe\n+            | _ -> Path.Combine(baseDir,exe) |> Path.GetFullPath\n+\n+    let exec cmdArgs (workDir: FilePath) envs (path: FilePath) arguments =\n+\n+        let exePath = path |> processExePath workDir\n+        let processInfo = new ProcessStartInfo(exePath, arguments)\n+        processInfo.CreateNoWindow <- true\n+        processInfo.UseShellExecute <- false\n+        processInfo.WorkingDirectory <- workDir\n+\n+        envs\n+        |> Map.iter (fun k v -> processInfo.EnvironmentVariables.[k] <- v)\n+\n+        let p = new Process()\n+        p.EnableRaisingEvents <- true\n+        p.StartInfo <- processInfo\n+\n+        cmdArgs.RedirectOutput\n+        |> Option.map (fun f -> (fun (ea: DataReceivedEventArgs) -> ea.Data |> f)) \n+        |> Option.iter (fun newOut ->\n+            processInfo.RedirectStandardOutput <- true\n+            p.OutputDataReceived.Add newOut\n+        )\n+\n+        cmdArgs.RedirectError \n+        |> Option.map (fun f -> (fun (ea: DataReceivedEventArgs) -> ea.Data |> f)) \n+        |> Option.iter (fun newErr ->\n+            processInfo.RedirectStandardError <- true\n+            p.ErrorDataReceived.Add newErr\n+        )\n+\n+        cmdArgs.RedirectInput\n+        |> Option.iter (fun _ -> p.StartInfo.RedirectStandardInput <- true)\n+\n+        let exitedAsync (proc: Process) =\n+            let tcs = new System.Threading.Tasks.TaskCompletionSource<int>();\n+            p.Exited.Add (fun s -> \n+                tcs.TrySetResult(proc.ExitCode) |> ignore\n+                proc.Dispose())\n+            tcs.Task\n+\n+        p.Start() |> ignore\n+    \n+        cmdArgs.RedirectOutput |> Option.iter (fun _ -> p.BeginOutputReadLine())\n+        cmdArgs.RedirectError |> Option.iter (fun _ -> p.BeginErrorReadLine())\n+\n+        cmdArgs.RedirectInput\n+        |> Option.map (fun input -> async {\n+            let inputWriter = p.StandardInput\n+            do! inputWriter.FlushAsync () |> Async.AwaitIAsyncResult |> Async.Ignore\n+            input inputWriter\n+            do! inputWriter.FlushAsync () |> Async.AwaitIAsyncResult |> Async.Ignore\n+            inputWriter.Close ()\n+            })\n+        |> Option.iter Async.Start\n+\n+        let exitCode = p |> exitedAsync |> Async.AwaitTask |> Async.RunSynchronously\n+\n+        match exitCode with\n+        | 0 -> Success\n+        | err -> ErrorLevel err\n+\n+\n+\n+type Result<'S,'F> =\n+    | Success of 'S\n+    | Failure of 'F\n+\n+type Attempt<'S,'F> = (unit -> Result<'S,'F>)\n+\n+open System.Diagnostics\n+\n+[<DebuggerStepThrough>]\n+let internal succeed x = (fun () -> Success x)\n+\n+[<DebuggerStepThrough>]\n+let internal failed err = (fun () -> Failure err)\n+\n+[<DebuggerStepThrough>]\n+let runAttempt (a: Attempt<_,_>) = a ()\n+\n+[<DebuggerStepThrough>]\n+let delay f = (fun () -> f() |> runAttempt)\n+\n+[<DebuggerStepThrough>]\n+let either successTrack failTrack (input : Attempt<_, _>) : Attempt<_, _> =\n+    match runAttempt input with\n+    | Success s -> successTrack s\n+    | Failure f -> failTrack f\n+\n+[<DebuggerStepThrough>]\n+let bind successTrack = either successTrack failed\n+\n+[<DebuggerStepThrough>] \n+let fail failTrack result = either succeed failTrack result\n+\n+[<DebuggerStepThrough>] \n+type Attempt =\n+    static member Run x = runAttempt x\n+\n+[<DebuggerStepThrough>] \n+type AttemptBuilder() =\n+    member this.Bind(m : Attempt<_, _>, success) = bind success m\n+    member this.Bind(m : Result<_, _>, success) = bind success (fun () -> m)\n+    member this.Bind(m : Result<_, _> option, success) = \n+        match m with\n+        | None -> this.Combine(this.Zero(), success)\n+        | Some x -> this.Bind(x, success)\n+    member this.Return(x) : Attempt<_, _> = succeed x\n+    member this.ReturnFrom(x : Attempt<_, _>) = x\n+    member this.Combine(v, f) : Attempt<_, _> = bind f v\n+    member this.Yield(x) = Success x\n+    member this.YieldFrom(x) = x\n+    member this.Delay(f) : Attempt<_, _> = delay f\n+    member this.Zero() : Attempt<_, _> = succeed ()\n+    member this.While(guard, body: Attempt<_, _>) =\n+        if not (guard()) \n+        then this.Zero() \n+        else this.Bind(body, fun () -> \n+            this.While(guard, body))  \n+\n+    member this.TryWith(body, handler) =\n+        try this.ReturnFrom(body())\n+        with e -> handler e\n+\n+    member this.TryFinally(body, compensation) =\n+        try this.ReturnFrom(body())\n+        finally compensation() \n+\n+    member this.Using(disposable:#System.IDisposable, body) =\n+        let body' = fun () -> body disposable\n+        this.TryFinally(body', fun () -> \n+            match disposable with \n+                | null -> () \n+                | disp -> disp.Dispose())\n+\n+    member this.For(sequence:seq<'a>, body: 'a -> Attempt<_,_>) =\n+        this.Using(sequence.GetEnumerator(),fun enum -> \n+            this.While(enum.MoveNext, \n+                this.Delay(fun () -> body enum.Current)))\n+\n+let processor = new AttemptBuilder()\n+\n+\n+let log format = Printf.ksprintf (printfn \"%s\") format\n+\n+type OutPipe (mailbox: MailboxProcessor<_>) =\n+    member x.Post msg = mailbox.Post(msg)\n+    interface System.IDisposable with\n+        member x.Dispose () = \n+            async {\n+                while mailbox.CurrentQueueLength > 0 do\n+                    let timeout = System.TimeSpan.FromMilliseconds(50.0)\n+                    do! Async.Sleep (timeout.TotalMilliseconds |> int)\n+            } |> Async.RunSynchronously\n+\n+let redirectTo (writer: TextWriter) =\n+    let mailbox = MailboxProcessor.Start(fun inbox -> \n+        let rec loop () = async {\n+            let! (msg : string) = inbox.Receive ()\n+            do! writer.WriteLineAsync(msg) |> (Async.AwaitIAsyncResult >> Async.Ignore)\n+            return! loop () }\n+        loop ())\n+    new OutPipe (mailbox)\n+\n+let redirectToLog () = redirectTo System.Console.Out\n+\n+let inline (/) a (b: string) = System.IO.Path.Combine(a,b)","path":"tests/fsharp/PlatformHelpers.fs","position":204,"original_position":204,"commit_id":"6637c9d5fb2f1ed67ed322c976380820374c80bf","original_commit_id":"6637c9d5fb2f1ed67ed322c976380820374c80bf","user":{"login":"forki","id":57396,"avatar_url":"https://avatars.githubusercontent.com/u/57396?v=3","gravatar_id":"","url":"https://api.github.com/users/forki","html_url":"https://github.com/forki","followers_url":"https://api.github.com/users/forki/followers","following_url":"https://api.github.com/users/forki/following{/other_user}","gists_url":"https://api.github.com/users/forki/gists{/gist_id}","starred_url":"https://api.github.com/users/forki/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/forki/subscriptions","organizations_url":"https://api.github.com/users/forki/orgs","repos_url":"https://api.github.com/users/forki/repos","events_url":"https://api.github.com/users/forki/events{/privacy}","received_events_url":"https://api.github.com/users/forki/received_events","type":"User","site_admin":false},"body":"In FAKE we use </> as alias for PathCombine.\r\n \r\n@@ is customized version, which does slightly different things","created_at":"2015-11-10T15:38:22Z","updated_at":"2015-11-10T15:38:22Z","html_url":"https://github.com/Microsoft/visualfsharp/pull/90#discussion_r44420630","pull_request_url":"https://api.github.com/repos/Microsoft/visualfsharp/pulls/90","_links":{"self":{"href":"https://api.github.com/repos/Microsoft/visualfsharp/pulls/comments/44420630"},"html":{"href":"https://github.com/Microsoft/visualfsharp/pull/90#discussion_r44420630"},"pull_request":{"href":"https://api.github.com/repos/Microsoft/visualfsharp/pulls/90"}}},"pull_request":{"url":"https://api.github.com/repos/Microsoft/visualfsharp/pulls/90","id":27896885,"html_url":"https://github.com/Microsoft/visualfsharp/pull/90","diff_url":"https://github.com/Microsoft/visualfsharp/pull/90.diff","patch_url":"https://github.com/Microsoft/visualfsharp/pull/90.patch","issue_url":"https://api.github.com/repos/Microsoft/visualfsharp/issues/90","number":90,"state":"open","locked":false,"title":"Migrate Cambridge test suite (tests/fsharp) runner to NUnit","user":{"login":"enricosada","id":147243,"avatar_url":"https://avatars.githubusercontent.com/u/147243?v=3","gravatar_id":"","url":"https://api.github.com/users/enricosada","html_url":"https://github.com/enricosada","followers_url":"https://api.github.com/users/enricosada/followers","following_url":"https://api.github.com/users/enricosada/following{/other_user}","gists_url":"https://api.github.com/users/enricosada/gists{/gist_id}","starred_url":"https://api.github.com/users/enricosada/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/enricosada/subscriptions","organizations_url":"https://api.github.com/users/enricosada/orgs","repos_url":"https://api.github.com/users/enricosada/repos","events_url":"https://api.github.com/users/enricosada/events{/privacy}","received_events_url":"https://api.github.com/users/enricosada/received_events","type":"User","site_admin":false},"body":"This is a spike to explore replacing current .bat based test runner with NUnit, for Cambridge suite ( `tests/fsharp` ).\r\n\r\nThere is a [discussion on codeplex](https://visualfsharp.codeplex.com/discussions/541792) about the Redmond suite ( `tests/fsharpqa` ), the idea is the same, Cambridge is easier to port before attempt Redmond suite\r\n\r\nCurrent .bat based runner has some problems:\r\n\r\n- windows only\r\n- no integration with ide test runner\r\n- test run flow and rules ( 'dont.use.empty.signature' files, config, env vars ) are in multiple files and not documented \r\n\r\n## New runner\r\n\r\n- **tests are not modified**, a new runner is added side by side to current\r\n- in library proj -> `tests\\fsharp\\FSharp.Tests.fsproj`\r\n- group by modules and tag with [NUnit categories](http://www.nunit.org/index.php?p=category&r=2.6.3)\r\n- core\\access -> module `FSharp-Tests-Core.Access` inside `tests/fsharp/core/_test.fs`\r\n- generate nunit test with [TestCaseSource](http://www.nunit.org/index.php?p=testCaseSource&r=2.6.3) and alike\r\n- add categories programmatically to generated test\r\n- convert .bat files to fsharp ( `single-test-build.bat` -> `single-test-build.fs` ), easier to convert and diff\r\n\r\n## This pr when complete\r\n\r\n1. [X] smoke test fsi/fsc before run tests (failfast)\r\n1. [X] improve command log (log every command, path and arguments)\r\n1. [X] run tests inside ide ( [X] vs, [ ] xamarin, [ ] resharper )\r\n1. [ ] cross platform\r\n1. [X] filter tests by category\r\n   - [X] by directory ( like core, core/events )\r\n   - [X] by tags inside .fs files ( like `#Records` in `tests\\fsharp\\core\\access\\test.fsx` )\r\n   - [X] failed previous run\r\n   - [X] custom tag with NUnit CategoryAttribute\r\n1. [x] run tests from command line using nunit test runner\r\n1. [x] run tests from command line using `tests\\RunTests.cmd`\r\n\r\n## I need some feedback\r\n\r\n- usefull?\r\n- how to improve readability of code ( line by line .bat -> .fs ) for easier port, like in `tests\\config.fs` ref/mutable mess\r\n- how to remove workaround for ITestAction.Targets property (see `tests/fsharp/nunitConf.fs:114` )\r\n- some :eyes: to discover opportunity of cleanup\r\n  - already converted nested ``match Ok -> | ErrorLevel ->`` to computation expression\r\n- missing features of old runner?\r\n\r\n## workflow\r\n\r\n1. implement new runner without changing tests\r\n1. put old .bat code inside test for easier diff, line by line\r\n\r\n   ```fsharp\r\n   // \"%FSC%\" %fsc_flags% -a -o:test.dll -g test.fs\r\n   do! fsc \"%s -a -o:test.dll -g\" cfg.fsc_flags [\"test.fs\"]\r\n   ```\r\n\r\n1. run side by side with old runner\r\n1. modify .bat suite runner  ( `fsharp\\tests\\RunTests.cmd` ) to use nunit test runner for Cambridge suite only\r\n1. remove .bat files of test runner\r\n\r\n## Future work (not this pr, but easier to implement after)\r\n\r\n1. replace file based test control (like `dont.use.empty.signature` file) with code or NUnit categories\r\n1. replace tags inside files (like `#Records`) with NUnit categories\r\n1. replace file based test result ( like `test.ok`, `build.ok` ) with exit code only or function result\r\n1. cleanup now useless workflow ( build.bat -> build.ok file )\r\n1. run test in parallel\r\n1. run multiple configuration ( net40, portable ) in parallel\r\n\r\n## Notes\r\n\r\n### VS Test Runner\r\n\r\nTo filter test inside visual studio test runner:\r\n\r\n- `Project:FSharp.Tests` to show only Cambrige suite\r\n- `Trait:FSI_FILE` to filter only FSI_FILE category (see `FSharpTestSuiteTypes.Permutation` union ) \r\n- `Trait:access` to filter 'core/access'\r\n- `-Trait:FSC_HW` to exclude `FSC_HW` tests\r\n\r\nex: `Project:FSharp.Tests Trait:FSC -Trait:FSC_HW` run all tests with FSC tag but not FSC_HW\r\n\r\n### [TEST CHANGED]\r\n\r\nI added changed test in separate commits with prefix [TEST CHANGED] because found bug/problems. \r\nThese can be evaluated before this pr, and easier to review/cherry-pick\r\n","created_at":"2015-01-23T02:30:44Z","updated_at":"2015-11-10T15:38:23Z","closed_at":null,"merged_at":null,"merge_commit_sha":"1b795737189b20a704116b4695a72347b5632576","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/Microsoft/visualfsharp/pulls/90/commits","review_comments_url":"https://api.github.com/repos/Microsoft/visualfsharp/pulls/90/comments","review_comment_url":"https://api.github.com/repos/Microsoft/visualfsharp/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Microsoft/visualfsharp/issues/90/comments","statuses_url":"https://api.github.com/repos/Microsoft/visualfsharp/statuses/6637c9d5fb2f1ed67ed322c976380820374c80bf","head":{"label":"enricosada:tests_suite_with_nunit","ref":"tests_suite_with_nunit","sha":"6637c9d5fb2f1ed67ed322c976380820374c80bf","user":{"login":"enricosada","id":147243,"avatar_url":"https://avatars.githubusercontent.com/u/147243?v=3","gravatar_id":"","url":"https://api.github.com/users/enricosada","html_url":"https://github.com/enricosada","followers_url":"https://api.github.com/users/enricosada/followers","following_url":"https://api.github.com/users/enricosada/following{/other_user}","gists_url":"https://api.github.com/users/enricosada/gists{/gist_id}","starred_url":"https://api.github.com/users/enricosada/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/enricosada/subscriptions","organizations_url":"https://api.github.com/users/enricosada/orgs","repos_url":"https://api.github.com/users/enricosada/repos","events_url":"https://api.github.com/users/enricosada/events{/privacy}","received_events_url":"https://api.github.com/users/enricosada/received_events","type":"User","site_admin":false},"repo":{"id":29712087,"name":"visualfsharp","full_name":"enricosada/visualfsharp","owner":{"login":"enricosada","id":147243,"avatar_url":"https://avatars.githubusercontent.com/u/147243?v=3","gravatar_id":"","url":"https://api.github.com/users/enricosada","html_url":"https://github.com/enricosada","followers_url":"https://api.github.com/users/enricosada/followers","following_url":"https://api.github.com/users/enricosada/following{/other_user}","gists_url":"https://api.github.com/users/enricosada/gists{/gist_id}","starred_url":"https://api.github.com/users/enricosada/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/enricosada/subscriptions","organizations_url":"https://api.github.com/users/enricosada/orgs","repos_url":"https://api.github.com/users/enricosada/repos","events_url":"https://api.github.com/users/enricosada/events{/privacy}","received_events_url":"https://api.github.com/users/enricosada/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/enricosada/visualfsharp","description":"The Visual F# compiler and tools","fork":true,"url":"https://api.github.com/repos/enricosada/visualfsharp","forks_url":"https://api.github.com/repos/enricosada/visualfsharp/forks","keys_url":"https://api.github.com/repos/enricosada/visualfsharp/keys{/key_id}","collaborators_url":"https://api.github.com/repos/enricosada/visualfsharp/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/enricosada/visualfsharp/teams","hooks_url":"https://api.github.com/repos/enricosada/visualfsharp/hooks","issue_events_url":"https://api.github.com/repos/enricosada/visualfsharp/issues/events{/number}","events_url":"https://api.github.com/repos/enricosada/visualfsharp/events","assignees_url":"https://api.github.com/repos/enricosada/visualfsharp/assignees{/user}","branches_url":"https://api.github.com/repos/enricosada/visualfsharp/branches{/branch}","tags_url":"https://api.github.com/repos/enricosada/visualfsharp/tags","blobs_url":"https://api.github.com/repos/enricosada/visualfsharp/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/enricosada/visualfsharp/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/enricosada/visualfsharp/git/refs{/sha}","trees_url":"https://api.github.com/repos/enricosada/visualfsharp/git/trees{/sha}","statuses_url":"https://api.github.com/repos/enricosada/visualfsharp/statuses/{sha}","languages_url":"https://api.github.com/repos/enricosada/visualfsharp/languages","stargazers_url":"https://api.github.com/repos/enricosada/visualfsharp/stargazers","contributors_url":"https://api.github.com/repos/enricosada/visualfsharp/contributors","subscribers_url":"https://api.github.com/repos/enricosada/visualfsharp/subscribers","subscription_url":"https://api.github.com/repos/enricosada/visualfsharp/subscription","commits_url":"https://api.github.com/repos/enricosada/visualfsharp/commits{/sha}","git_commits_url":"https://api.github.com/repos/enricosada/visualfsharp/git/commits{/sha}","comments_url":"https://api.github.com/repos/enricosada/visualfsharp/comments{/number}","issue_comment_url":"https://api.github.com/repos/enricosada/visualfsharp/issues/comments{/number}","contents_url":"https://api.github.com/repos/enricosada/visualfsharp/contents/{+path}","compare_url":"https://api.github.com/repos/enricosada/visualfsharp/compare/{base}...{head}","merges_url":"https://api.github.com/repos/enricosada/visualfsharp/merges","archive_url":"https://api.github.com/repos/enricosada/visualfsharp/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/enricosada/visualfsharp/downloads","issues_url":"https://api.github.com/repos/enricosada/visualfsharp/issues{/number}","pulls_url":"https://api.github.com/repos/enricosada/visualfsharp/pulls{/number}","milestones_url":"https://api.github.com/repos/enricosada/visualfsharp/milestones{/number}","notifications_url":"https://api.github.com/repos/enricosada/visualfsharp/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/enricosada/visualfsharp/labels{/name}","releases_url":"https://api.github.com/repos/enricosada/visualfsharp/releases{/id}","created_at":"2015-01-23T02:16:46Z","updated_at":"2015-03-02T10:13:24Z","pushed_at":"2015-11-10T15:25:24Z","git_url":"git://github.com/enricosada/visualfsharp.git","ssh_url":"git@github.com:enricosada/visualfsharp.git","clone_url":"https://github.com/enricosada/visualfsharp.git","svn_url":"https://github.com/enricosada/visualfsharp","homepage":null,"size":53138,"stargazers_count":0,"watchers_count":0,"language":"F#","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":"fsharp4"}},"base":{"label":"Microsoft:master","ref":"master","sha":"996427edccd60567ead6d3bc829d39f558d8af53","user":{"login":"Microsoft","id":6154722,"avatar_url":"https://avatars.githubusercontent.com/u/6154722?v=3","gravatar_id":"","url":"https://api.github.com/users/Microsoft","html_url":"https://github.com/Microsoft","followers_url":"https://api.github.com/users/Microsoft/followers","following_url":"https://api.github.com/users/Microsoft/following{/other_user}","gists_url":"https://api.github.com/users/Microsoft/gists{/gist_id}","starred_url":"https://api.github.com/users/Microsoft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Microsoft/subscriptions","organizations_url":"https://api.github.com/users/Microsoft/orgs","repos_url":"https://api.github.com/users/Microsoft/repos","events_url":"https://api.github.com/users/Microsoft/events{/privacy}","received_events_url":"https://api.github.com/users/Microsoft/received_events","type":"Organization","site_admin":false},"repo":{"id":29048891,"name":"visualfsharp","full_name":"Microsoft/visualfsharp","owner":{"login":"Microsoft","id":6154722,"avatar_url":"https://avatars.githubusercontent.com/u/6154722?v=3","gravatar_id":"","url":"https://api.github.com/users/Microsoft","html_url":"https://github.com/Microsoft","followers_url":"https://api.github.com/users/Microsoft/followers","following_url":"https://api.github.com/users/Microsoft/following{/other_user}","gists_url":"https://api.github.com/users/Microsoft/gists{/gist_id}","starred_url":"https://api.github.com/users/Microsoft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Microsoft/subscriptions","organizations_url":"https://api.github.com/users/Microsoft/orgs","repos_url":"https://api.github.com/users/Microsoft/repos","events_url":"https://api.github.com/users/Microsoft/events{/privacy}","received_events_url":"https://api.github.com/users/Microsoft/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Microsoft/visualfsharp","description":"The Visual F# compiler and tools","fork":false,"url":"https://api.github.com/repos/Microsoft/visualfsharp","forks_url":"https://api.github.com/repos/Microsoft/visualfsharp/forks","keys_url":"https://api.github.com/repos/Microsoft/visualfsharp/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Microsoft/visualfsharp/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Microsoft/visualfsharp/teams","hooks_url":"https://api.github.com/repos/Microsoft/visualfsharp/hooks","issue_events_url":"https://api.github.com/repos/Microsoft/visualfsharp/issues/events{/number}","events_url":"https://api.github.com/repos/Microsoft/visualfsharp/events","assignees_url":"https://api.github.com/repos/Microsoft/visualfsharp/assignees{/user}","branches_url":"https://api.github.com/repos/Microsoft/visualfsharp/branches{/branch}","tags_url":"https://api.github.com/repos/Microsoft/visualfsharp/tags","blobs_url":"https://api.github.com/repos/Microsoft/visualfsharp/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Microsoft/visualfsharp/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Microsoft/visualfsharp/git/refs{/sha}","trees_url":"https://api.github.com/repos/Microsoft/visualfsharp/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Microsoft/visualfsharp/statuses/{sha}","languages_url":"https://api.github.com/repos/Microsoft/visualfsharp/languages","stargazers_url":"https://api.github.com/repos/Microsoft/visualfsharp/stargazers","contributors_url":"https://api.github.com/repos/Microsoft/visualfsharp/contributors","subscribers_url":"https://api.github.com/repos/Microsoft/visualfsharp/subscribers","subscription_url":"https://api.github.com/repos/Microsoft/visualfsharp/subscription","commits_url":"https://api.github.com/repos/Microsoft/visualfsharp/commits{/sha}","git_commits_url":"https://api.github.com/repos/Microsoft/visualfsharp/git/commits{/sha}","comments_url":"https://api.github.com/repos/Microsoft/visualfsharp/comments{/number}","issue_comment_url":"https://api.github.com/repos/Microsoft/visualfsharp/issues/comments{/number}","contents_url":"https://api.github.com/repos/Microsoft/visualfsharp/contents/{+path}","compare_url":"https://api.github.com/repos/Microsoft/visualfsharp/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Microsoft/visualfsharp/merges","archive_url":"https://api.github.com/repos/Microsoft/visualfsharp/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Microsoft/visualfsharp/downloads","issues_url":"https://api.github.com/repos/Microsoft/visualfsharp/issues{/number}","pulls_url":"https://api.github.com/repos/Microsoft/visualfsharp/pulls{/number}","milestones_url":"https://api.github.com/repos/Microsoft/visualfsharp/milestones{/number}","notifications_url":"https://api.github.com/repos/Microsoft/visualfsharp/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Microsoft/visualfsharp/labels{/name}","releases_url":"https://api.github.com/repos/Microsoft/visualfsharp/releases{/id}","created_at":"2015-01-10T05:58:43Z","updated_at":"2015-11-06T20:21:16Z","pushed_at":"2015-11-10T15:25:24Z","git_url":"git://github.com/Microsoft/visualfsharp.git","ssh_url":"git@github.com:Microsoft/visualfsharp.git","clone_url":"https://github.com/Microsoft/visualfsharp.git","svn_url":"https://github.com/Microsoft/visualfsharp","homepage":null,"size":69413,"stargazers_count":575,"watchers_count":575,"language":"F#","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":129,"mirror_url":null,"open_issues_count":200,"forks":129,"open_issues":200,"watchers":575,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Microsoft/visualfsharp/pulls/90"},"html":{"href":"https://github.com/Microsoft/visualfsharp/pull/90"},"issue":{"href":"https://api.github.com/repos/Microsoft/visualfsharp/issues/90"},"comments":{"href":"https://api.github.com/repos/Microsoft/visualfsharp/issues/90/comments"},"review_comments":{"href":"https://api.github.com/repos/Microsoft/visualfsharp/pulls/90/comments"},"review_comment":{"href":"https://api.github.com/repos/Microsoft/visualfsharp/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Microsoft/visualfsharp/pulls/90/commits"},"statuses":{"href":"https://api.github.com/repos/Microsoft/visualfsharp/statuses/6637c9d5fb2f1ed67ed322c976380820374c80bf"}}}}