anchor.diff:          let close =
               new DreamMessage(
                   DreamStatus.Ok,
  -                new DreamHeaders([| new KeyValuePair<string, string>("Authorization", "token " + token);  new KeyValuePair<string, string>("X-HTTP-Method-Override", "PATCH") |]),
  +                new DreamHeaders([| new KeyValuePair<string, string>("Authorization", "token " + token.Value);  new KeyValuePair<string, string>("X-HTTP-Method-Override", "PATCH") |]),
                   MimeType.JSON,
  -                """{ "state":"closed"  }""")
  +                """{ "state" : "closed"  }""")
           Plug.New(new XUri(pr?pull_request?url.AsString())).Post(close)
  +        
  +    member this.CreateWebHooks(repos) =
  +        repos
  +        |> Seq.filter (fun repo -> not(this.WebHookExist(repo)))
  +        |> Seq.iter (fun repo -> this.CreateWebHook(repo))
  +        
  +    member this.WebHookExist repo =
  +        let auth =
  +            new DreamMessage(
  +                DreamStatus.Ok,
  +                new DreamHeaders([| new KeyValuePair<string, string>("Authorization", "token " + token.Value) |]),
  +                MimeType.JSON,
  +                "")
  +        let hooks : JsonValue[] = JsonValue.Parse(GITHUB_API.At("repos", owner.Value, repo, "hooks").Get(auth).ToText()).AsArray()
  +        
  +        // TODO(cesarn): Use proper pattern matching
  +        let isPullRequestEvent (events : JsonValue[]) = Seq.exists (fun (event : JsonValue) -> event.AsString() = "pull_request") events
  +        Seq.exists (fun (hook : JsonValue) -> isPullRequestEvent(hook?events.AsArray()) && hook?name.AsString() = "web" && hook?config?url.AsString() = publicUri.Value) hooks
  +        
  +    member this.CreateWebHook repo =
  +        let createHook =
  +            new DreamMessage(
  +                DreamStatus.Ok,
  +                new DreamHeaders([| new KeyValuePair<string, string>("Authorization", "token " + token.Value) |]),
  +                MimeType.JSON,
  +                String.Format("""{{ "name" : "web", "events" : ["pull_request"], "config" : {{ "url" : "{0}", "content_type" : "json" }} }}""", publicUri.Value))
  +        try
  +            ignore(GITHUB_API.At("repos", owner.Value, repo, "hooks").Post(createHook))
  +        with
  +        | _ -> ()
           
positive.code: open FSharp.Data.Json
  open FSharp.Data.Json.Extensions
  
  [<DreamService(
      "MindTouch Github Pull Request Service",
      "Copyright (C) 2013 MindTouch Inc.",
      SID = [| "sid://mindtouch.com/2013/05/pullrequestservice" |])>]
  [<DreamServiceConfig("github.token", "string", "The personal authorization token issued by GitHub for the watched repo")>]
  type PullRequestService() =
      inherit DreamService()
      let mutable token = ""
                  
      override this.Start(config : XDoc, container : ILifetimeScope, result : Result) =
          token <- config.["github.token"].AsText
  
          // TODO(cesarn): Create web hook automatically?
          // TODO(cesarn): Support multiple repos?
          result.Return()
          Seq.empty<IYield>.GetEnumerator()
          
  
negative.code:     member this.GetStatus(context : DreamContext, request : DreamMessage) =
          DreamMessage.Ok(MimeType.JSON, "Everything running smoothly ...")
          
      member this.ValidateConfig(key, value) =
          match value with
          | None -> raise(MissingConfig(key))
          | _ -> ()
  
      member this.InvalidPullRequest(pr : JsonValue) =
          let action = pr?action.AsString()
          (action = "opened" || action = "reopened") && pr.["pull_request"].["base"].["ref"].AsString() = "master"
  