anchor.diff:  
   let dotnetcliVersion = "2.0.2"
   let mutable dotnetExePath = environVarOrDefault "DOTNET" "dotnet"
  -let dotnetSDKPath = FullName "./dotnetsdk"
  -let localDotnetExePath = dotnetSDKPath </> (if isWindows then "dotnet.exe" else "dotnet")
  -
  +
  +let CWD = __SOURCE_DIRECTORY__
   let cliBuildDir = "build/fable"
   let coreBuildDir = "build/fable-core"
   let coreSrcDir = "src/dotnet/Fable.Core"
  
positive.code: #r "packages/build/FAKE/tools/FakeLib.dll"
  #r "System.IO.Compression.FileSystem"
  #load "paket-files/build/fsharp/FAKE/modules/Octokit/Octokit.fsx"
  #load "paket-files/build/fable-compiler/fake-helpers/Fable.FakeHelpers.fs"
  
  open System
  open System.IO
  open System.Text.RegularExpressions
  open System.Collections.Generic
  open Fake
  open Fake.AssemblyInfoFile
  open Fake.Git
  open Fake.ReleaseNotesHelper
  open Octokit
  
  #if MONO
  // prevent incorrect output encoding (e.g. https://github.com/fsharp/FAKE/issues/1196)
  System.Console.OutputEncoding <- System.Text.Encoding.UTF8
  #endif
  
  module Util =
      open System.Net
  
      let retryIfFails maxRetries f =
          let rec loop retriesRemaining =
              try
                  f ()
              with _ when retriesRemaining > 0 ->
                  loop (retriesRemaining - 1)
          loop maxRetries
  
      let (|RegexReplace|_|) =
          let cache = new Dictionary<string, Regex>()
          fun pattern (replacement: string) input ->
              let regex =
                  match cache.TryGetValue(pattern) with
                  | true, regex -> regex
                  | false, _ ->
                      let regex = Regex pattern
                      cache.Add(pattern, regex)
                      regex
              let m = regex.Match(input)
              if m.Success
              then regex.Replace(input, replacement) |> Some
              else None
  
      let join pathParts =
          Path.Combine(Array.ofSeq pathParts)
  
      let run workingDir fileName args =
          printfn "CWD: %s" workingDir
          let fileName, args =
              if EnvironmentHelper.isUnix
              then fileName, args else "cmd", ("/C " + fileName + " " + args)
          let ok =
              execProcess (fun info ->
                  info.FileName <- fileName
                  info.WorkingDirectory <- workingDir
                  info.Arguments <- args) TimeSpan.MaxValue
          if not ok then failwith (sprintf "'%s> %s %s' task failed" workingDir fileName args)
  
      let start workingDir fileName args =
          let p = new System.Diagnostics.Process()
          p.StartInfo.FileName <- fileName
          p.StartInfo.WorkingDirectory <- workingDir
          p.StartInfo.Arguments <- args
          p.Start() |> ignore
          p
  
      let runAndReturn workingDir fileName args =
          printfn "CWD: %s" workingDir
          let fileName, args =
              if EnvironmentHelper.isUnix
              then fileName, args else "cmd", ("/C " + args)
          ExecProcessAndReturnMessages (fun info ->
              info.FileName <- fileName
              info.WorkingDirectory <- workingDir
              info.Arguments <- args) TimeSpan.MaxValue
          |> fun p -> p.Messages |> String.concat "\n"
  
      let downloadArtifact path (url: string) =
          async {
              let tempFile = Path.ChangeExtension(Path.GetTempFileName(), ".zip")
              use client = new WebClient()
              do! client.AsyncDownloadFile(Uri url, tempFile)
              FileUtils.mkdir path
              CleanDir path
              run path "unzip" (sprintf "-q %s" tempFile)
              File.Delete tempFile
          } |> Async.RunSynchronously
  
      let rmdir dir =
          if EnvironmentHelper.isUnix
          then FileUtils.rm_rf dir
          // Use this in Windows to prevent conflicts with paths too long
          else run "." "cmd" ("/C rmdir /s /q " + Path.GetFullPath dir)
  
      let visitFile (visitor: string->string) (fileName : string) =
          File.ReadAllLines(fileName)
          |> Array.map (visitor)
          |> fun lines -> File.WriteAllLines(fileName, lines)
  
          // This code is supposed to prevent OutOfMemory exceptions but it outputs wrong BOM
          // use reader = new StreamReader(fileName, encoding)
          // let tempFileName = Path.GetTempFileName()
          // use writer = new StreamWriter(tempFileName, false, encoding)
          // while not reader.EndOfStream do
          //     reader.ReadLine() |> visitor |> writer.WriteLine
          // reader.Close()
          // writer.Close()
          // File.Delete(fileName)
          // File.Move(tempFileName, fileName)
  
      let replaceLines (replacer: string->Match->string option) (reg: Regex) (fileName: string) =
          fileName |> visitFile (fun line ->
              let m = reg.Match(line)
              if not m.Success
              then line
              else
                  match replacer line m with
                  | None -> line
                  | Some newLine -> newLine)
  
      let compileScript symbols outDir fsxPath =
          let dllFile = Path.ChangeExtension(Path.GetFileName fsxPath, ".dll")
          let opts = [
              yield FscHelper.Out (Path.Combine(outDir, dllFile))
              yield FscHelper.Target FscHelper.TargetType.Library
              yield! symbols |> List.map FscHelper.Define
          ]
          FscHelper.compile opts [fsxPath]
          |> function 0 -> () | _ -> failwithf "Cannot compile %s" fsxPath
  
      let normalizeVersion (version: string) =
          let i = version.IndexOf("-")
          if i > 0 then version.Substring(0, i) else version
  
      let assemblyInfo projectDir version extra =
          let version = normalizeVersion version
          let asmInfoPath = projectDir </> "AssemblyInfo.fs"
          (Attribute.Version version)::extra
          |> CreateFSharpAssemblyInfo asmInfoPath
  
  module Npm =
      let script workingDir script args =
          sprintf "run %s -- %s" script (String.concat " " args)
          |> Util.run workingDir "npm"
  
      let install workingDir modules =
          let npmInstall () =
              sprintf "install %s" (String.concat " " modules)
              |> Util.run workingDir "npm"
  
          // On windows, retry npm install to avoid bug related to https://github.com/npm/npm/issues/9696
          Util.retryIfFails (if isWindows then 3 else 0) npmInstall
  
      let command workingDir command args =
          sprintf "%s %s" command (String.concat " " args)
          |> Util.run workingDir "npm"
  
      let commandAndReturn workingDir command args =
          sprintf "%s %s" command (String.concat " " args)
          |> Util.runAndReturn workingDir "npm"
  
      let getLatestVersion package tag =
          let package =
              match tag with
              | Some tag -> package + "@" + tag
              | None -> package
          commandAndReturn "." "show" [package; "version"]
  
      let updatePackageKeyValue f pkgDir keys =
          let pkgJson = Path.Combine(pkgDir, "package.json")
          let reg =
              String.concat "|" keys
              |> sprintf "\"(%s)\"\\s*:\\s*\"(.*?)\""
              |> Regex
          let lines =
              File.ReadAllLines pkgJson
              |> Array.map (fun line ->
                  let m = reg.Match(line)
                  if m.Success then
                      match f(m.Groups.[1].Value, m.Groups.[2].Value) with
                      | Some(k,v) -> reg.Replace(line, sprintf "\"%s\": \"%s\"" k v)
                      | None -> line
                  else line)
          File.WriteAllLines(pkgJson, lines)
  
  module Yarn =
      open Fake.YarnHelper
  
      let install workingDir =
          Yarn (fun p ->
              { p with
                  Command = Install Standard
                  WorkingDirectory = workingDir
              })
  
  module Node =
      let run workingDir script args =
          let args = sprintf "%s %s" script (String.concat " " args)
          Util.run workingDir "node" args
  
  // Project info
  let project = "Fable"
  
negative.code:         |> Seq.tryFind (fun (s: string) -> s.Contains(gitOwner + "/" + project))
          |> function None -> gitHome + "/" + project | Some (s: string) -> s.Split().[0]
  
      // StageAll ""
      // Git.Commit.Commit "" (sprintf "Bump version to %s" release.NugetVersion)
      // Branches.pushBranch "" remote (Information.getBranchName "")
  
      Branches.tag "" release.NugetVersion
      Branches.pushTag "" remote release.NugetVersion
  