gretmn102 3 년 전
커밋
4de385a327
18개의 변경된 파일1528개의 추가작업 그리고 0개의 파일을 삭제
  1. 397 0
      .gitignore
  2. 494 0
      .paket/Paket.Restore.targets
  3. BIN
      .paket/paket.bootstrapper.exe
  4. 37 0
      .vscode/tasks.json
  5. 343 0
      QspServer/Program.fs
  6. 25 0
      QspServer/QspServer.fsproj
  7. 11 0
      QspServer/Test.fsx
  8. 5 0
      QspServer/paket.references
  9. 0 0
      TODO
  10. 6 0
      Test/App.config
  11. 36 0
      Test/Test.fs
  12. 23 0
      Test/Test.fsproj
  13. 2 0
      Test/paket.references
  14. 17 0
      build.cmd
  15. 90 0
      build.fsx
  16. 5 0
      global.json
  17. 17 0
      paket.dependencies
  18. 20 0
      paket.lock

+ 397 - 0
.gitignore

@@ -0,0 +1,397 @@
+# Created by https://www.gitignore.io/api/f#,linux,windows,macos,vim,emacs,visualstudio,visualstudiocode
+
+### F# ###
+lib/debug
+lib/release
+Debug
+*.suo
+*.user
+obj
+bin
+*.exe
+!/.paket/paket.bootstrapper.exe
+
+
+### Linux ###
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+
+### Windows ###
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+
+### macOS ###
+*.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+
+### Vim ###
+# swap
+[._]*.s[a-w][a-z]
+[._]s[a-w][a-z]
+# session
+Session.vim
+# temporary
+.netrwhist
+*~
+# auto-generated tag files
+tags
+
+
+### Emacs ###
+# -*- mode: gitignore; -*-
+*~
+\#*\#
+/.emacs.desktop
+/.emacs.desktop.lock
+*.elc
+auto-save-list
+tramp
+.\#*
+
+# Org-mode
+.org-id-locations
+*_archive
+
+# flymake-mode
+*_flymake.*
+
+# eshell files
+/eshell/history
+/eshell/lastdir
+
+# elpa packages
+/elpa/
+
+# reftex files
+*.rel
+
+# AUCTeX auto folder
+/auto/
+
+# cask packages
+.cask/
+dist/
+
+# Flycheck
+flycheck_*.el
+
+# server auth directory
+/server/
+
+# projectiles files
+.projectile
+
+### VisualStudioCode ###
+# .vscode
+
+
+
+### VisualStudio ###
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+bld/
+build/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# DNX
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# TODO: Comment the next line if you want to checkin your web deploy settings
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/packages/*
+# # except build/, which is used as an MSBuild target.
+# !**/packages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/packages/repositories.config
+# NuGet v3's project.json files produces more ignoreable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.pfx
+*.publishsettings
+node_modules/
+orleans.codegen.cs
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+/Output/
+/.ionide/

+ 494 - 0
.paket/Paket.Restore.targets

@@ -0,0 +1,494 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <!-- Prevent dotnet template engine to parse this file -->
+  <!--/-:cnd:noEmit-->
+  <PropertyGroup>
+    <!-- make MSBuild track this file for incremental builds. -->
+    <!-- ref https://blogs.msdn.microsoft.com/msbuild/2005/09/26/how-to-ensure-changes-to-a-custom-target-file-prompt-a-rebuild/ -->
+    <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+
+    <DetectedMSBuildVersion>$(MSBuildVersion)</DetectedMSBuildVersion>
+    <DetectedMSBuildVersion Condition="'$(MSBuildVersion)' == ''">15.0.0</DetectedMSBuildVersion>
+    <MSBuildSupportsHashing>false</MSBuildSupportsHashing>
+    <MSBuildSupportsHashing Condition=" '$(DetectedMSBuildVersion)' &gt; '15.8.0' ">true</MSBuildSupportsHashing>
+    <!-- Mark that this target file has been loaded.  -->
+    <IsPaketRestoreTargetsFileLoaded>true</IsPaketRestoreTargetsFileLoaded>
+    <PaketToolsPath>$(MSBuildThisFileDirectory)</PaketToolsPath>
+    <PaketRootPath>$(MSBuildThisFileDirectory)..\</PaketRootPath>
+    <PaketRestoreCacheFile>$(PaketRootPath)paket-files\paket.restore.cached</PaketRestoreCacheFile>
+    <PaketLockFilePath>$(PaketRootPath)paket.lock</PaketLockFilePath>
+    <PaketBootstrapperStyle>classic</PaketBootstrapperStyle>
+    <PaketBootstrapperStyle Condition="Exists('$(PaketToolsPath)paket.bootstrapper.proj')">proj</PaketBootstrapperStyle>
+    <PaketExeImage>assembly</PaketExeImage>
+    <PaketExeImage Condition=" '$(PaketBootstrapperStyle)' == 'proj' ">native</PaketExeImage>
+    <MonoPath Condition="'$(MonoPath)' == '' AND Exists('/Library/Frameworks/Mono.framework/Commands/mono')">/Library/Frameworks/Mono.framework/Commands/mono</MonoPath>
+    <MonoPath Condition="'$(MonoPath)' == ''">mono</MonoPath>
+
+    <!-- PaketBootStrapper  -->
+    <PaketBootStrapperExePath Condition=" '$(PaketBootStrapperExePath)' == '' AND Exists('$(PaketRootPath)paket.bootstrapper.exe')">$(PaketRootPath)paket.bootstrapper.exe</PaketBootStrapperExePath>
+    <PaketBootStrapperExePath Condition=" '$(PaketBootStrapperExePath)' == '' ">$(PaketToolsPath)paket.bootstrapper.exe</PaketBootStrapperExePath>
+    <PaketBootStrapperExeDir Condition=" Exists('$(PaketBootStrapperExePath)') " >$([System.IO.Path]::GetDirectoryName("$(PaketBootStrapperExePath)"))\</PaketBootStrapperExeDir>
+
+    <PaketBootStrapperCommand Condition=" '$(OS)' == 'Windows_NT' ">"$(PaketBootStrapperExePath)"</PaketBootStrapperCommand>
+    <PaketBootStrapperCommand Condition=" '$(OS)' != 'Windows_NT' ">$(MonoPath) --runtime=v4.0.30319 "$(PaketBootStrapperExePath)"</PaketBootStrapperCommand>
+
+    <!-- Disable automagic references for F# DotNet SDK -->
+    <!-- This will not do anything for other project types -->
+    <!-- see https://github.com/fsharp/fslang-design/blob/master/tooling/FST-1002-fsharp-in-dotnet-sdk.md -->
+    <DisableImplicitFSharpCoreReference>true</DisableImplicitFSharpCoreReference>
+    <DisableImplicitSystemValueTupleReference>true</DisableImplicitSystemValueTupleReference>
+
+    <!-- Disable Paket restore under NCrunch build -->
+    <PaketRestoreDisabled Condition="'$(NCrunch)' == '1'">True</PaketRestoreDisabled>
+
+    <!-- Disable test for CLI tool completely - overrideable via properties in projects or via environment variables -->
+    <PaketDisableCliTest Condition=" '$(PaketDisableCliTest)' == '' ">False</PaketDisableCliTest>
+
+    <PaketIntermediateOutputPath Condition=" '$(PaketIntermediateOutputPath)' == '' ">$(BaseIntermediateOutputPath.TrimEnd('\').TrimEnd('\/'))</PaketIntermediateOutputPath>
+  </PropertyGroup>
+
+  <!-- Resolve how paket should be called -->
+  <!-- Current priority is: local (1: repo root, 2: .paket folder) => 3: as CLI tool => as bootstrapper (4: proj Bootstrapper style, 5: BootstrapperExeDir) => 6: global path variable -->
+  <Target Name="SetPaketCommand" >
+    <!-- Test if paket is available in the standard locations. If so, that takes priority. Case 1/2 - non-windows specific -->
+    <PropertyGroup Condition=" '$(OS)' != 'Windows_NT' ">
+      <!-- no windows, try native paket as default, root => tool -->
+      <PaketExePath Condition=" '$(PaketExePath)' == '' AND Exists('$(PaketRootPath)paket') ">$(PaketRootPath)paket</PaketExePath>
+      <PaketExePath Condition=" '$(PaketExePath)' == '' AND Exists('$(PaketToolsPath)paket') ">$(PaketToolsPath)paket</PaketExePath>
+    </PropertyGroup>
+
+    <!-- Test if paket is available in the standard locations. If so, that takes priority. Case 2/2 - same across platforms -->
+    <PropertyGroup>
+      <!-- root => tool -->
+      <PaketExePath Condition=" '$(PaketExePath)' == '' AND Exists('$(PaketRootPath)paket.exe') ">$(PaketRootPath)paket.exe</PaketExePath>
+      <PaketExePath Condition=" '$(PaketExePath)' == '' AND Exists('$(PaketToolsPath)paket.exe') ">$(PaketToolsPath)paket.exe</PaketExePath>
+    </PropertyGroup>
+
+    <!-- If paket hasn't be found in standard locations, test for CLI tool usage. -->
+    <!-- First test: Is CLI configured to be used in "dotnet-tools.json"? - can result in a false negative; only a positive outcome is reliable. -->
+    <PropertyGroup Condition=" '$(PaketExePath)' == '' ">
+      <_DotnetToolsJson Condition="Exists('$(PaketRootPath)/.config/dotnet-tools.json')">$([System.IO.File]::ReadAllText("$(PaketRootPath)/.config/dotnet-tools.json"))</_DotnetToolsJson>
+      <_ConfigContainsPaket Condition=" '$(_DotnetToolsJson)' != ''">$(_DotnetToolsJson.Contains('"paket"'))</_ConfigContainsPaket>
+      <_ConfigContainsPaket Condition=" '$(_ConfigContainsPaket)' == ''">false</_ConfigContainsPaket>
+    </PropertyGroup>
+
+    <!-- Second test: Call 'dotnet paket' and see if it returns without an error. Mute all the output. Only run if previous test failed and the test has not been disabled. -->
+    <!-- WARNING: This method can lead to processes hanging forever, and should be used as little as possible. See https://github.com/fsprojects/Paket/issues/3705 for details. -->
+    <Exec Condition=" '$(PaketExePath)' == '' AND !$(PaketDisableCliTest) AND !$(_ConfigContainsPaket)" Command="dotnet paket --version" IgnoreExitCode="true" StandardOutputImportance="low" StandardErrorImportance="low" >
+      <Output TaskParameter="ExitCode" PropertyName="LocalPaketToolExitCode" />
+    </Exec>
+
+    <!-- If paket is installed as CLI use that. Again, only if paket haven't already been found in standard locations. -->
+    <PropertyGroup Condition=" '$(PaketExePath)' == '' AND ($(_ConfigContainsPaket) OR '$(LocalPaketToolExitCode)' == '0') ">
+      <_PaketCommand>dotnet paket</_PaketCommand>
+    </PropertyGroup>
+
+    <!-- If neither local files nor CLI tool can be found, final attempt is searching for boostrapper config before falling back to global path variable. -->
+    <PropertyGroup Condition=" '$(PaketExePath)' == '' AND '$(_PaketCommand)' == '' ">
+      <!-- Test for bootstrapper setup -->
+      <PaketExePath Condition=" '$(PaketExePath)' == '' AND '$(PaketBootstrapperStyle)' == 'proj' ">$(PaketToolsPath)paket</PaketExePath>
+      <PaketExePath Condition=" '$(PaketExePath)' == '' AND Exists('$(PaketBootStrapperExeDir)') ">$(PaketBootStrapperExeDir)paket</PaketExePath>
+
+      <!-- If all else fails, use global path approach. -->
+      <PaketExePath Condition=" '$(PaketExePath)' == ''">paket</PaketExePath>
+    </PropertyGroup>
+
+    <!-- If not using CLI, setup correct execution command. -->
+    <PropertyGroup Condition=" '$(_PaketCommand)' == '' ">
+      <_PaketExeExtension>$([System.IO.Path]::GetExtension("$(PaketExePath)"))</_PaketExeExtension>
+      <_PaketCommand Condition=" '$(_PaketCommand)' == '' AND '$(_PaketExeExtension)' == '.dll' ">dotnet "$(PaketExePath)"</_PaketCommand>
+      <_PaketCommand Condition=" '$(_PaketCommand)' == '' AND '$(OS)' != 'Windows_NT' AND '$(_PaketExeExtension)' == '.exe' ">$(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)"</_PaketCommand>
+      <_PaketCommand Condition=" '$(_PaketCommand)' == '' ">"$(PaketExePath)"</_PaketCommand>
+    </PropertyGroup>
+
+    <!-- The way to get a property to be available outside the target is to use this task. -->
+    <CreateProperty Value="$(_PaketCommand)">
+      <Output TaskParameter="Value" PropertyName="PaketCommand"/>
+    </CreateProperty>
+
+  </Target>
+
+  <Target Name="PaketBootstrapping" Condition="Exists('$(PaketToolsPath)paket.bootstrapper.proj')">
+    <MSBuild Projects="$(PaketToolsPath)paket.bootstrapper.proj" Targets="Restore" />
+  </Target>
+
+  <!-- Official workaround for https://docs.microsoft.com/en-us/visualstudio/msbuild/getfilehash-task?view=vs-2019 -->
+  <UsingTask TaskName="Microsoft.Build.Tasks.GetFileHash" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Condition=" '$(MSBuildSupportsHashing)' == 'true' And '$(DetectedMSBuildVersion)' &lt; '16.0.360' " />
+  <UsingTask TaskName="Microsoft.Build.Tasks.VerifyFileHash" AssemblyName="Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Condition=" '$(MSBuildSupportsHashing)' == 'true' And '$(DetectedMSBuildVersion)' &lt; '16.0.360' " />
+  <Target Name="PaketRestore" Condition="'$(PaketRestoreDisabled)' != 'True'" BeforeTargets="_GenerateDotnetCliToolReferenceSpecs;_GenerateProjectRestoreGraphPerFramework;_GenerateRestoreGraphWalkPerFramework;CollectPackageReferences" DependsOnTargets="SetPaketCommand;PaketBootstrapping">
+
+    <!-- Step 1 Check if lockfile is properly restored (if the hash of the lockfile and the cache-file match) -->
+    <PropertyGroup>
+      <PaketRestoreRequired>true</PaketRestoreRequired>
+      <NoWarn>$(NoWarn);NU1603;NU1604;NU1605;NU1608</NoWarn>
+      <CacheFilesExist>false</CacheFilesExist>
+      <CacheFilesExist Condition=" Exists('$(PaketRestoreCacheFile)') And Exists('$(PaketLockFilePath)') ">true</CacheFilesExist>
+    </PropertyGroup>
+
+    <!-- Read the hash of the lockfile -->
+    <GetFileHash Condition=" '$(MSBuildSupportsHashing)' == 'true' And '$(CacheFilesExist)' == 'true' " Files="$(PaketLockFilePath)" Algorithm="SHA256" HashEncoding="hex" >
+      <Output TaskParameter="Hash" PropertyName="PaketRestoreLockFileHash" />
+    </GetFileHash>
+    <!-- Read the hash of the cache, which is json, but a very simple key value object -->
+    <PropertyGroup Condition=" '$(MSBuildSupportsHashing)' == 'true' And '$(CacheFilesExist)' == 'true' ">
+        <PaketRestoreCachedContents>$([System.IO.File]::ReadAllText('$(PaketRestoreCacheFile)'))</PaketRestoreCachedContents>
+    </PropertyGroup>
+    <ItemGroup Condition=" '$(MSBuildSupportsHashing)' == 'true' And '$(CacheFilesExist)' == 'true' ">
+        <!-- Parse our simple 'paket.restore.cached' json ...-->
+        <PaketRestoreCachedSplitObject Include="$([System.Text.RegularExpressions.Regex]::Split(`$(PaketRestoreCachedContents)`, `{|}|,`))"></PaketRestoreCachedSplitObject>
+        <!-- Keep Key, Value ItemGroup-->
+        <PaketRestoreCachedKeyValue Include="@(PaketRestoreCachedSplitObject)"
+            Condition=" $([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `&quot;: &quot;`).Length) &gt; 1 ">
+          <Key>$([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[0].Replace(`"`, ``).Replace(` `, ``))</Key>
+          <Value>$([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[1].Replace(`"`, ``).Replace(` `, ``))</Value>
+        </PaketRestoreCachedKeyValue>
+    </ItemGroup>
+    <PropertyGroup Condition=" '$(MSBuildSupportsHashing)' == 'true' And '$(CacheFilesExist)' == 'true' ">
+        <!-- Retrieve the hashes we are interested in -->
+        <PackagesDownloadedHash Condition=" '%(PaketRestoreCachedKeyValue.Key)' == 'packagesDownloadedHash' ">%(PaketRestoreCachedKeyValue.Value)</PackagesDownloadedHash>
+        <ProjectsRestoredHash Condition=" '%(PaketRestoreCachedKeyValue.Key)' == 'projectsRestoredHash' ">%(PaketRestoreCachedKeyValue.Value)</ProjectsRestoredHash>
+    </PropertyGroup>
+
+    <PropertyGroup Condition=" '$(MSBuildSupportsHashing)' == 'true' And '$(CacheFilesExist)' == 'true' ">
+      <!-- If the restore file doesn't exist we need to restore, otherwise only if hashes don't match -->
+      <PaketRestoreRequired>true</PaketRestoreRequired>
+      <PaketRestoreRequired Condition=" '$(PaketRestoreLockFileHash)' == '$(ProjectsRestoredHash)' ">false</PaketRestoreRequired>
+      <PaketRestoreRequired Condition=" '$(PaketRestoreLockFileHash)' == '' ">true</PaketRestoreRequired>
+    </PropertyGroup>
+
+	<!--
+		This value should match the version in the props generated by paket
+		If they differ, this means we need to do a restore in order to ensure correct dependencies
+	-->
+    <PropertyGroup Condition="'$(PaketPropsVersion)' != '5.185.3' ">
+      <PaketRestoreRequired>true</PaketRestoreRequired>
+    </PropertyGroup>
+
+    <!-- Do a global restore if required -->
+    <Warning Text="This version of MSBuild (we assume '$(DetectedMSBuildVersion)' or older) doesn't support GetFileHash, so paket fast restore is disabled." Condition=" '$(MSBuildSupportsHashing)' != 'true' " />
+    <Error Text="Stop build because of PAKET_ERROR_ON_MSBUILD_EXEC and we always call the bootstrapper" Condition=" '$(PAKET_ERROR_ON_MSBUILD_EXEC)' == 'true' AND '$(PaketBootstrapperStyle)' == 'classic' AND Exists('$(PaketBootStrapperExePath)') AND !(Exists('$(PaketExePath)'))" />
+    <Exec Command='$(PaketBootStrapperCommand)' Condition=" '$(PaketBootstrapperStyle)' == 'classic' AND Exists('$(PaketBootStrapperExePath)') AND !(Exists('$(PaketExePath)'))" ContinueOnError="false" />
+    <Error Text="Stop build because of PAKET_ERROR_ON_MSBUILD_EXEC and we need a full restore (hashes don't match)" Condition=" '$(PAKET_ERROR_ON_MSBUILD_EXEC)' == 'true' AND '$(PaketRestoreRequired)' == 'true' AND '$(PaketDisableGlobalRestore)' != 'true'" />
+    <Exec Command='$(PaketCommand) restore' Condition=" '$(PaketRestoreRequired)' == 'true' AND '$(PaketDisableGlobalRestore)' != 'true' " ContinueOnError="false" />
+
+    <!-- Step 2 Detect project specific changes -->
+    <ItemGroup>
+      <MyTargetFrameworks Condition="'$(TargetFramework)' != '' " Include="$(TargetFramework)"></MyTargetFrameworks>
+      <!-- Don't include all frameworks when msbuild explicitly asks for a single one -->
+      <MyTargetFrameworks Condition="'$(TargetFrameworks)' != '' AND '$(TargetFramework)' == '' " Include="$(TargetFrameworks)"></MyTargetFrameworks>
+      <PaketResolvedFilePaths Include="@(MyTargetFrameworks -> '$(PaketIntermediateOutputPath)\$(MSBuildProjectFile).%(Identity).paket.resolved')"></PaketResolvedFilePaths>
+    </ItemGroup>
+
+    <PropertyGroup>
+      <PaketReferencesCachedFilePath>$(PaketIntermediateOutputPath)\$(MSBuildProjectFile).paket.references.cached</PaketReferencesCachedFilePath>
+      <!-- MyProject.fsproj.paket.references has the highest precedence -->
+      <PaketOriginalReferencesFilePath>$(MSBuildProjectFullPath).paket.references</PaketOriginalReferencesFilePath>
+      <!-- MyProject.paket.references -->
+      <PaketOriginalReferencesFilePath Condition=" !Exists('$(PaketOriginalReferencesFilePath)')">$(MSBuildProjectDirectory)\$(MSBuildProjectName).paket.references</PaketOriginalReferencesFilePath>
+      <!-- paket.references -->
+      <PaketOriginalReferencesFilePath Condition=" !Exists('$(PaketOriginalReferencesFilePath)')">$(MSBuildProjectDirectory)\paket.references</PaketOriginalReferencesFilePath>
+
+      <DoAllResolvedFilesExist>false</DoAllResolvedFilesExist>
+      <DoAllResolvedFilesExist Condition="Exists(%(PaketResolvedFilePaths.Identity))">true</DoAllResolvedFilesExist>
+      <PaketRestoreRequired>true</PaketRestoreRequired>
+      <PaketRestoreRequiredReason>references-file-or-cache-not-found</PaketRestoreRequiredReason>
+    </PropertyGroup>
+
+    <!-- Step 2 a Detect changes in references file -->
+    <PropertyGroup Condition="Exists('$(PaketOriginalReferencesFilePath)') AND Exists('$(PaketReferencesCachedFilePath)') ">
+      <PaketRestoreCachedHash>$([System.IO.File]::ReadAllText('$(PaketReferencesCachedFilePath)'))</PaketRestoreCachedHash>
+      <PaketRestoreReferencesFileHash>$([System.IO.File]::ReadAllText('$(PaketOriginalReferencesFilePath)'))</PaketRestoreReferencesFileHash>
+      <PaketRestoreRequiredReason>references-file</PaketRestoreRequiredReason>
+      <PaketRestoreRequired Condition=" '$(PaketRestoreReferencesFileHash)' == '$(PaketRestoreCachedHash)' ">false</PaketRestoreRequired>
+    </PropertyGroup>
+
+    <PropertyGroup Condition="!Exists('$(PaketOriginalReferencesFilePath)') AND !Exists('$(PaketReferencesCachedFilePath)') ">
+      <!-- If both don't exist there is nothing to do. -->
+      <PaketRestoreRequired>false</PaketRestoreRequired>
+    </PropertyGroup>
+
+    <!-- Step 2 b detect relevant changes in project file (new targetframework) -->
+    <PropertyGroup Condition=" '$(DoAllResolvedFilesExist)' != 'true' ">
+      <PaketRestoreRequired>true</PaketRestoreRequired>
+      <PaketRestoreRequiredReason>target-framework '$(TargetFramework)' or '$(TargetFrameworks)' files @(PaketResolvedFilePaths)</PaketRestoreRequiredReason>
+    </PropertyGroup>
+
+    <!-- Step 3 Restore project specific stuff if required -->
+    <Message Condition=" '$(PaketRestoreRequired)' == 'true' " Importance="low" Text="Detected a change ('$(PaketRestoreRequiredReason)') in the project file '$(MSBuildProjectFullPath)', calling paket restore" />
+    <Error Text="Stop build because of PAKET_ERROR_ON_MSBUILD_EXEC and we detected a change ('$(PaketRestoreRequiredReason)') in the project file '$(MSBuildProjectFullPath)'" Condition=" '$(PAKET_ERROR_ON_MSBUILD_EXEC)' == 'true' AND '$(PaketRestoreRequired)' == 'true' " />
+    <Exec Command='$(PaketCommand) restore --project "$(MSBuildProjectFullPath)" --output-path "$(PaketIntermediateOutputPath)" --target-framework "$(TargetFrameworks)"' Condition=" '$(PaketRestoreRequired)' == 'true' AND '$(TargetFramework)' == '' " ContinueOnError="false" />
+    <Exec Command='$(PaketCommand) restore --project "$(MSBuildProjectFullPath)" --output-path "$(PaketIntermediateOutputPath)" --target-framework "$(TargetFramework)"' Condition=" '$(PaketRestoreRequired)' == 'true' AND '$(TargetFramework)' != '' " ContinueOnError="false" />
+
+    <!-- This shouldn't actually happen, but just to be sure. -->
+    <PropertyGroup>
+      <DoAllResolvedFilesExist>false</DoAllResolvedFilesExist>
+      <DoAllResolvedFilesExist Condition="Exists(%(PaketResolvedFilePaths.Identity))">true</DoAllResolvedFilesExist>
+    </PropertyGroup>
+    <Error Condition=" '$(DoAllResolvedFilesExist)' != 'true' AND '$(ResolveNuGetPackages)' != 'False' " Text="One Paket file '@(PaketResolvedFilePaths)' is missing while restoring $(MSBuildProjectFile). Please delete 'paket-files/paket.restore.cached' and call 'paket restore'." />
+
+    <!-- Step 4 forward all msbuild properties (PackageReference, DotNetCliToolReference) to msbuild -->
+    <ReadLinesFromFile Condition="($(DesignTimeBuild) != true OR '$(PaketPropsLoaded)' != 'true') AND '@(PaketResolvedFilePaths)' != ''" File="%(PaketResolvedFilePaths.Identity)" >
+      <Output TaskParameter="Lines" ItemName="PaketReferencesFileLines"/>
+    </ReadLinesFromFile>
+
+    <ItemGroup Condition="($(DesignTimeBuild) != true OR '$(PaketPropsLoaded)' != 'true') AND '@(PaketReferencesFileLines)' != '' " >
+      <PaketReferencesFileLinesInfo Include="@(PaketReferencesFileLines)" >
+        <Splits>$([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',').Length)</Splits>
+        <PackageName>$([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[0])</PackageName>
+        <PackageVersion>$([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[1])</PackageVersion>
+        <AllPrivateAssets>$([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[4])</AllPrivateAssets>
+        <CopyLocal Condition="'%(PaketReferencesFileLinesInfo.Splits)' == '6'">$([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[5])</CopyLocal>
+      </PaketReferencesFileLinesInfo>
+      <PackageReference Include="%(PaketReferencesFileLinesInfo.PackageName)">
+        <Version>%(PaketReferencesFileLinesInfo.PackageVersion)</Version>
+        <PrivateAssets Condition=" ('%(PaketReferencesFileLinesInfo.AllPrivateAssets)' == 'true') Or ('$(PackAsTool)' == 'true') ">All</PrivateAssets>
+        <ExcludeAssets Condition=" '%(PaketReferencesFileLinesInfo.Splits)' == '6' And %(PaketReferencesFileLinesInfo.CopyLocal) == 'false'">runtime</ExcludeAssets>
+        <ExcludeAssets Condition=" '%(PaketReferencesFileLinesInfo.Splits)' != '6' And %(PaketReferencesFileLinesInfo.AllPrivateAssets) == 'exclude'">runtime</ExcludeAssets>
+        <Publish Condition=" '$(PackAsTool)' == 'true' ">true</Publish>
+        <AllowExplicitVersion>true</AllowExplicitVersion>
+      </PackageReference>
+    </ItemGroup>
+
+    <PropertyGroup>
+      <PaketCliToolFilePath>$(PaketIntermediateOutputPath)/$(MSBuildProjectFile).paket.clitools</PaketCliToolFilePath>
+    </PropertyGroup>
+
+    <ReadLinesFromFile File="$(PaketCliToolFilePath)" >
+      <Output TaskParameter="Lines" ItemName="PaketCliToolFileLines"/>
+    </ReadLinesFromFile>
+
+    <ItemGroup Condition=" '@(PaketCliToolFileLines)' != '' " >
+      <PaketCliToolFileLinesInfo Include="@(PaketCliToolFileLines)" >
+        <PackageName>$([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[0])</PackageName>
+        <PackageVersion>$([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[1])</PackageVersion>
+      </PaketCliToolFileLinesInfo>
+      <DotNetCliToolReference Include="%(PaketCliToolFileLinesInfo.PackageName)">
+        <Version>%(PaketCliToolFileLinesInfo.PackageVersion)</Version>
+      </DotNetCliToolReference>
+    </ItemGroup>
+
+    <!-- Disabled for now until we know what to do with runtime deps - https://github.com/fsprojects/Paket/issues/2964
+    <PropertyGroup>
+      <RestoreConfigFile>$(PaketIntermediateOutputPath)/$(MSBuildProjectFile).NuGet.Config</RestoreConfigFile>
+    </PropertyGroup> -->
+
+  </Target>
+
+  <Target Name="PaketDisableDirectPack" AfterTargets="_IntermediatePack" BeforeTargets="GenerateNuspec" Condition="('$(IsPackable)' == '' Or '$(IsPackable)' == 'true') And Exists('$(PaketIntermediateOutputPath)/$(MSBuildProjectFile).references')" >
+    <PropertyGroup>
+      <ContinuePackingAfterGeneratingNuspec>false</ContinuePackingAfterGeneratingNuspec>
+    </PropertyGroup>
+  </Target>
+
+  <Target Name="PaketOverrideNuspec" DependsOnTargets="SetPaketCommand" AfterTargets="GenerateNuspec" Condition="('$(IsPackable)' == '' Or '$(IsPackable)' == 'true') And Exists('$(PaketIntermediateOutputPath)/$(MSBuildProjectFile).references')" >
+    <ItemGroup>
+      <_NuspecFilesNewLocation Include="$(PaketIntermediateOutputPath)\$(Configuration)\*.nuspec"/>
+      <MSBuildMajorVersion Include="$(DetectedMSBuildVersion.Replace(`-`, `.`).Split(`.`)[0])" />
+      <MSBuildMinorVersion Include="$(DetectedMSBuildVersion.Replace(`-`, `.`).Split(`.`)[1])" />
+    </ItemGroup>
+
+    <PropertyGroup>
+      <PaketProjectFile>$(MSBuildProjectDirectory)/$(MSBuildProjectFile)</PaketProjectFile>
+      <ContinuePackingAfterGeneratingNuspec>true</ContinuePackingAfterGeneratingNuspec>
+      <UseMSBuild16_0_Pack>false</UseMSBuild16_0_Pack>
+      <UseMSBuild16_0_Pack Condition=" '@(MSBuildMajorVersion)' >= '16' ">true</UseMSBuild16_0_Pack>
+      <UseMSBuild15_9_Pack>false</UseMSBuild15_9_Pack>
+      <UseMSBuild15_9_Pack Condition=" '@(MSBuildMajorVersion)' == '15' AND '@(MSBuildMinorVersion)' > '8' ">true</UseMSBuild15_9_Pack>
+      <UseMSBuild15_8_Pack>false</UseMSBuild15_8_Pack>
+      <UseMSBuild15_8_Pack Condition=" '$(NuGetToolVersion)' != '4.0.0' AND (! $(UseMSBuild15_9_Pack)) AND (! $(UseMSBuild16_0_Pack)) ">true</UseMSBuild15_8_Pack>
+      <UseNuGet4_Pack>false</UseNuGet4_Pack>
+      <UseNuGet4_Pack Condition=" (! $(UseMSBuild15_8_Pack)) AND (! $(UseMSBuild15_9_Pack)) AND (! $(UseMSBuild16_0_Pack)) ">true</UseNuGet4_Pack>
+      <AdjustedNuspecOutputPath>$(PaketIntermediateOutputPath)\$(Configuration)</AdjustedNuspecOutputPath>
+      <AdjustedNuspecOutputPath Condition="@(_NuspecFilesNewLocation) == ''">$(PaketIntermediateOutputPath)</AdjustedNuspecOutputPath>
+    </PropertyGroup>
+
+    <ItemGroup>
+      <_NuspecFiles Include="$(AdjustedNuspecOutputPath)\*.$(PackageVersion.Split(`+`)[0]).nuspec"/>
+    </ItemGroup>
+
+    <Error Text="Error Because of PAKET_ERROR_ON_MSBUILD_EXEC (not calling fix-nuspecs)" Condition=" '$(PAKET_ERROR_ON_MSBUILD_EXEC)' == 'true' " />
+    <Exec Condition="@(_NuspecFiles) != ''" Command='$(PaketCommand) fix-nuspecs files "@(_NuspecFiles)" project-file "$(PaketProjectFile)" ' />
+    <Error Condition="@(_NuspecFiles) == ''" Text='Could not find nuspec files in "$(AdjustedNuspecOutputPath)" (Version: "$(PackageVersion)"), therefore we cannot call "paket fix-nuspecs" and have to error out!' />
+
+    <ConvertToAbsolutePath Condition="@(_NuspecFiles) != ''" Paths="@(_NuspecFiles)">
+      <Output TaskParameter="AbsolutePaths" PropertyName="NuspecFileAbsolutePath" />
+    </ConvertToAbsolutePath>
+
+    <!-- Call Pack -->
+    <PackTask Condition="$(UseMSBuild16_0_Pack)"
+              PackItem="$(PackProjectInputFile)"
+              PackageFiles="@(_PackageFiles)"
+              PackageFilesToExclude="@(_PackageFilesToExclude)"
+              PackageVersion="$(PackageVersion)"
+              PackageId="$(PackageId)"
+              Title="$(Title)"
+              Authors="$(Authors)"
+              Description="$(Description)"
+              Copyright="$(Copyright)"
+              RequireLicenseAcceptance="$(PackageRequireLicenseAcceptance)"
+              LicenseUrl="$(PackageLicenseUrl)"
+              ProjectUrl="$(PackageProjectUrl)"
+              IconUrl="$(PackageIconUrl)"
+              ReleaseNotes="$(PackageReleaseNotes)"
+              Tags="$(PackageTags)"
+              DevelopmentDependency="$(DevelopmentDependency)"
+              BuildOutputInPackage="@(_BuildOutputInPackage)"
+              TargetPathsToSymbols="@(_TargetPathsToSymbols)"
+              SymbolPackageFormat="$(SymbolPackageFormat)"
+              TargetFrameworks="@(_TargetFrameworks)"
+              AssemblyName="$(AssemblyName)"
+              PackageOutputPath="$(PackageOutputAbsolutePath)"
+              IncludeSymbols="$(IncludeSymbols)"
+              IncludeSource="$(IncludeSource)"
+              PackageTypes="$(PackageType)"
+              IsTool="$(IsTool)"
+              RepositoryUrl="$(RepositoryUrl)"
+              RepositoryType="$(RepositoryType)"
+              SourceFiles="@(_SourceFiles->Distinct())"
+              NoPackageAnalysis="$(NoPackageAnalysis)"
+              MinClientVersion="$(MinClientVersion)"
+              Serviceable="$(Serviceable)"
+              FrameworkAssemblyReferences="@(_FrameworkAssemblyReferences)"
+              ContinuePackingAfterGeneratingNuspec="$(ContinuePackingAfterGeneratingNuspec)"
+              NuspecOutputPath="$(AdjustedNuspecOutputPath)"
+              IncludeBuildOutput="$(IncludeBuildOutput)"
+              BuildOutputFolders="$(BuildOutputTargetFolder)"
+              ContentTargetFolders="$(ContentTargetFolders)"
+              RestoreOutputPath="$(RestoreOutputAbsolutePath)"
+              NuspecFile="$(NuspecFileAbsolutePath)"
+              NuspecBasePath="$(NuspecBasePath)"
+              NuspecProperties="$(NuspecProperties)"
+              PackageLicenseFile="$(PackageLicenseFile)"
+              PackageLicenseExpression="$(PackageLicenseExpression)"
+              PackageLicenseExpressionVersion="$(PackageLicenseExpressionVersion)" />
+
+    <PackTask Condition="$(UseMSBuild15_9_Pack)"
+              PackItem="$(PackProjectInputFile)"
+              PackageFiles="@(_PackageFiles)"
+              PackageFilesToExclude="@(_PackageFilesToExclude)"
+              PackageVersion="$(PackageVersion)"
+              PackageId="$(PackageId)"
+              Title="$(Title)"
+              Authors="$(Authors)"
+              Description="$(Description)"
+              Copyright="$(Copyright)"
+              RequireLicenseAcceptance="$(PackageRequireLicenseAcceptance)"
+              LicenseUrl="$(PackageLicenseUrl)"
+              ProjectUrl="$(PackageProjectUrl)"
+              IconUrl="$(PackageIconUrl)"
+              ReleaseNotes="$(PackageReleaseNotes)"
+              Tags="$(PackageTags)"
+              DevelopmentDependency="$(DevelopmentDependency)"
+              BuildOutputInPackage="@(_BuildOutputInPackage)"
+              TargetPathsToSymbols="@(_TargetPathsToSymbols)"
+              SymbolPackageFormat="$(SymbolPackageFormat)"
+              TargetFrameworks="@(_TargetFrameworks)"
+              AssemblyName="$(AssemblyName)"
+              PackageOutputPath="$(PackageOutputAbsolutePath)"
+              IncludeSymbols="$(IncludeSymbols)"
+              IncludeSource="$(IncludeSource)"
+              PackageTypes="$(PackageType)"
+              IsTool="$(IsTool)"
+              RepositoryUrl="$(RepositoryUrl)"
+              RepositoryType="$(RepositoryType)"
+              SourceFiles="@(_SourceFiles->Distinct())"
+              NoPackageAnalysis="$(NoPackageAnalysis)"
+              MinClientVersion="$(MinClientVersion)"
+              Serviceable="$(Serviceable)"
+              FrameworkAssemblyReferences="@(_FrameworkAssemblyReferences)"
+              ContinuePackingAfterGeneratingNuspec="$(ContinuePackingAfterGeneratingNuspec)"
+              NuspecOutputPath="$(AdjustedNuspecOutputPath)"
+              IncludeBuildOutput="$(IncludeBuildOutput)"
+              BuildOutputFolder="$(BuildOutputTargetFolder)"
+              ContentTargetFolders="$(ContentTargetFolders)"
+              RestoreOutputPath="$(RestoreOutputAbsolutePath)"
+              NuspecFile="$(NuspecFileAbsolutePath)"
+              NuspecBasePath="$(NuspecBasePath)"
+              NuspecProperties="$(NuspecProperties)"/>
+
+    <PackTask Condition="$(UseMSBuild15_8_Pack)"
+              PackItem="$(PackProjectInputFile)"
+              PackageFiles="@(_PackageFiles)"
+              PackageFilesToExclude="@(_PackageFilesToExclude)"
+              PackageVersion="$(PackageVersion)"
+              PackageId="$(PackageId)"
+              Title="$(Title)"
+              Authors="$(Authors)"
+              Description="$(Description)"
+              Copyright="$(Copyright)"
+              RequireLicenseAcceptance="$(PackageRequireLicenseAcceptance)"
+              LicenseUrl="$(PackageLicenseUrl)"
+              ProjectUrl="$(PackageProjectUrl)"
+              IconUrl="$(PackageIconUrl)"
+              ReleaseNotes="$(PackageReleaseNotes)"
+              Tags="$(PackageTags)"
+              DevelopmentDependency="$(DevelopmentDependency)"
+              BuildOutputInPackage="@(_BuildOutputInPackage)"
+              TargetPathsToSymbols="@(_TargetPathsToSymbols)"
+              TargetFrameworks="@(_TargetFrameworks)"
+              AssemblyName="$(AssemblyName)"
+              PackageOutputPath="$(PackageOutputAbsolutePath)"
+              IncludeSymbols="$(IncludeSymbols)"
+              IncludeSource="$(IncludeSource)"
+              PackageTypes="$(PackageType)"
+              IsTool="$(IsTool)"
+              RepositoryUrl="$(RepositoryUrl)"
+              RepositoryType="$(RepositoryType)"
+              SourceFiles="@(_SourceFiles->Distinct())"
+              NoPackageAnalysis="$(NoPackageAnalysis)"
+              MinClientVersion="$(MinClientVersion)"
+              Serviceable="$(Serviceable)"
+              FrameworkAssemblyReferences="@(_FrameworkAssemblyReferences)"
+              ContinuePackingAfterGeneratingNuspec="$(ContinuePackingAfterGeneratingNuspec)"
+              NuspecOutputPath="$(AdjustedNuspecOutputPath)"
+              IncludeBuildOutput="$(IncludeBuildOutput)"
+              BuildOutputFolder="$(BuildOutputTargetFolder)"
+              ContentTargetFolders="$(ContentTargetFolders)"
+              RestoreOutputPath="$(RestoreOutputAbsolutePath)"
+              NuspecFile="$(NuspecFileAbsolutePath)"
+              NuspecBasePath="$(NuspecBasePath)"
+              NuspecProperties="$(NuspecProperties)"/>
+
+    <PackTask Condition="$(UseNuGet4_Pack)"
+              PackItem="$(PackProjectInputFile)"
+              PackageFiles="@(_PackageFiles)"
+              PackageFilesToExclude="@(_PackageFilesToExclude)"
+              PackageVersion="$(PackageVersion)"
+              PackageId="$(PackageId)"
+              Title="$(Title)"
+              Authors="$(Authors)"
+              Description="$(Description)"
+              Copyright="$(Copyright)"
+              RequireLicenseAcceptance="$(PackageRequireLicenseAcceptance)"
+              LicenseUrl="$(PackageLicenseUrl)"
+              ProjectUrl="$(PackageProjectUrl)"
+              IconUrl="$(PackageIconUrl)"
+              ReleaseNotes="$(PackageReleaseNotes)"
+              Tags="$(PackageTags)"
+              TargetPathsToAssemblies="@(_TargetPathsToAssemblies->'%(FinalOutputPath)')"
+              TargetPathsToSymbols="@(_TargetPathsToSymbols)"
+              TargetFrameworks="@(_TargetFrameworks)"
+              AssemblyName="$(AssemblyName)"
+              PackageOutputPath="$(PackageOutputAbsolutePath)"
+              IncludeSymbols="$(IncludeSymbols)"
+              IncludeSource="$(IncludeSource)"
+              PackageTypes="$(PackageType)"
+              IsTool="$(IsTool)"
+              RepositoryUrl="$(RepositoryUrl)"
+              RepositoryType="$(RepositoryType)"
+              SourceFiles="@(_SourceFiles->Distinct())"
+              NoPackageAnalysis="$(NoPackageAnalysis)"
+              MinClientVersion="$(MinClientVersion)"
+              Serviceable="$(Serviceable)"
+              AssemblyReferences="@(_References)"
+              ContinuePackingAfterGeneratingNuspec="$(ContinuePackingAfterGeneratingNuspec)"
+              NuspecOutputPath="$(AdjustedNuspecOutputPath)"
+              IncludeBuildOutput="$(IncludeBuildOutput)"
+              BuildOutputFolder="$(BuildOutputTargetFolder)"
+              ContentTargetFolders="$(ContentTargetFolders)"
+              RestoreOutputPath="$(RestoreOutputAbsolutePath)"
+              NuspecFile="$(NuspecFileAbsolutePath)"
+              NuspecBasePath="$(NuspecBasePath)"
+              NuspecProperties="$(NuspecProperties)"/>
+  </Target>
+  <!--/+:cnd:noEmit-->
+</Project>

BIN
.paket/paket.bootstrapper.exe


+ 37 - 0
.vscode/tasks.json

@@ -0,0 +1,37 @@
+{
+    // See https://go.microsoft.com/fwlink/?LinkId=733558
+    // for the documentation about the tasks.json format
+    "version": "2.0.0",
+    "tasks": [
+        {
+            "label": "build",
+            "type": "shell",
+            "command": "build.cmd",
+            "args": [
+                "RunTest"
+            ],
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            },
+            "problemMatcher": []
+        },
+        {
+            "label": "build&run",
+            "type": "shell",
+            "command": "build.cmd",
+            "args": [
+                "RunMainProj"
+            ]
+        },
+        {
+            "label": "TrimTrailingWhitespace",
+            "type": "shell",
+            "command": "build.cmd",
+            "args": [
+                "TrimTrailingWhitespace"
+            ],
+            "problemMatcher": []
+        }
+    ]
+}

+ 343 - 0
QspServer/Program.fs

@@ -0,0 +1,343 @@
+module Program
+open FsharpMyExtension
+open FsharpMyExtension.Either
+open LanguageServerProtocol
+open LanguageServerProtocol.Server
+open LanguageServerProtocol.Types
+
+// type Msg = { Value: string }
+type SourceFilePath = string
+
+
+type FsacClient(sendServerRequest: ClientNotificationSender) =
+    inherit LspClient ()
+
+    override __.WindowShowMessage(p) =
+        sendServerRequest "window/showMessage" (box p) |> Async.Ignore
+
+    override __.WindowLogMessage(p) =
+        sendServerRequest "window/logMessage" (box p) |> Async.Ignore
+
+    override __.TextDocumentPublishDiagnostics(p) =
+        sendServerRequest "textDocument/publishDiagnostics" (box p) |> Async.Ignore
+
+type State = {
+    DicPath : string
+}
+
+type UpdateFileParms = {
+    // File: BackgroundFileCheckType
+    Content: string
+    Version: int
+}
+
+type YASpellChecker =
+    { SpellcheckIgnore : DocumentUri Set }
+type Config =
+    { YASpellChecker : YASpellChecker option }
+    static member Default =
+        {
+            YASpellChecker = None
+        }
+/// Перезапускающийся таймер: как только подаются новые данные, старый счетчик сбрасывается, и наступает вновь отсчет, но уже с новыми данными. Если счетчик дойдет до нуля, то вызовется функция.
+let restartableTimer interval f =
+    let m = MailboxProcessor.Start(fun agent ->
+        let mutable data = None
+        let rec loop (timer:System.Timers.Timer) =
+            async {
+                let! msg = agent.Receive()
+                data <- Some msg
+
+                timer.Stop()
+                timer.Start()
+                return! loop timer
+            }
+        let timer = new System.Timers.Timer(interval)
+        timer.AutoReset <- false
+        timer.Elapsed.Add(fun x -> f x data.Value)
+        loop timer
+    )
+    m.Post
+let test () =
+    let interval = 1500.
+    let time = restartableTimer interval (fun e (x:string, y:int) -> printfn "%A" (x, y))
+    time("1", 1)
+    time("2", 1)
+    time("3", 1)
+
+type BackgroundServiceServer(state: State, client: FsacClient) =
+    inherit LspServer()
+    let mutable clientCapabilities = None
+
+    let mutable documentVersion : int option = None
+    let mutable lastWords = Map.empty
+    let publishDiagnostics uri (text:string) =
+        let publishDiagnostics (res:list<_>) =
+            res
+            |> List.map (fun (range, word) ->
+                {
+                    Range = range
+                    Severity = Some (DiagnosticSeverity.Hint)
+                    Code = None
+                    Source = "qsp"
+                    Message = sprintf "unknown '%s'" word
+                    RelatedInformation = None
+                    Tags = None
+                })
+            |> Array.ofList
+        async {
+            match parser text with
+            | Right res2 ->
+                let res =
+                    res2
+                    |> List.map (fun (word, pos) ->
+                        let range =
+                            {
+                                Start = { Line = int pos.StartLine - 1
+                                          Character = int pos.StartColumn - 1 }
+                                End = { Line = int pos.EndLine - 1
+                                        Character = int pos.EndColumn - 1 }
+                            }
+                        range, word
+                    )
+                lastWords <- Map.ofList res
+                do! client.TextDocumentPublishDiagnostics {
+                    Uri = uri
+                    Diagnostics = publishDiagnostics res
+                }
+
+                do! client.SpellcheckDecorate (res2 |> List.map snd)
+            | Left x ->
+                do! client.WindowLogMessage {
+                    Type = MessageType.Error
+                    Message = sprintf "Parser error:\n%A" x
+                }
+        }
+    let interval = 500.
+    let reactor =
+        restartableTimer interval
+            (fun e (uri, text) ->
+                publishDiagnostics uri text
+                |> Async.RunSynchronously
+            )
+
+    override __.TextDocumentDidChange(p) = async {
+        if Set.contains (p.TextDocument.Uri.ToLower()) spellcheckIgnore then
+            // Удаляет ошибки, если были проставлены до того, как документ попал в фильтр
+            do! client.TextDocumentPublishDiagnostics {
+                Uri = p.TextDocument.Uri
+                Diagnostics = [||]
+            }
+            do! client.SpellcheckDecorate []
+        else
+            do! client.WindowLogMessage {
+                Type = MessageType.Info
+                Message = sprintf "TextDocumentDidChange\n%A" p.TextDocument
+            }
+
+            documentVersion <- p.TextDocument.Version
+            match Array.tryExactlyOne p.ContentChanges with
+            | Some x ->
+                reactor (p.TextDocument.Uri, x.Text)
+            | None ->
+                do! client.WindowLogMessage {
+                    Type = MessageType.Error
+                    Message = sprintf "Array.tryExactlyOne p.ContentChanges error:\n%A" p.ContentChanges
+                }
+    }
+    override __.TextDocumentDidOpen(p: DidOpenTextDocumentParams) = async {
+        // Вот что, этот негодяй одновременно открывает целую кучу всего: здесь и git, и обычный файл, и даже output. Надо бы как-то за всем этим уследить.
+        // TODO: когда найду способ выделять именно текущий документ, тогда и раскомментирую
+        // do! client.WindowLogMessage {
+        //     Type = MessageType.Info
+        //     Message =
+        //         let txt = p.TextDocument
+        //         sprintf "TextDocumentDidOpen\n%A"
+        //             ( txt.LanguageId, txt.Uri, txt.Version)
+        // }
+        // if Set.contains (p.TextDocument.Uri.ToLower()) spellcheckIgnore then
+        //     do! client.SpellcheckDecorate []
+        // else
+        //     let textDoc = p.TextDocument
+        //     documentVersion <- Some textDoc.Version
+        //     do! client.WindowLogMessage {
+        //         Type = MessageType.Info
+        //         Message = "TextDocumentDidOpen"
+        //     }
+        //     reactor (textDoc.Uri, textDoc.Text)
+        ()
+    }
+    member private __.IfDiagnostic (str: string) handler p =
+        let diag =
+            p.Context.Diagnostics |> Seq.tryFind (fun n -> n.Message.Contains str)
+        match diag with
+        | None -> async.Return []
+        | Some d -> handler d
+
+    member private __.CreateFix uri ver title (d: Diagnostic option) range replacement =
+        let e =
+            {
+                Range = range
+                NewText = replacement
+            }
+        let edit =
+            {
+                TextDocument =
+                    {
+                        Uri = uri
+                        Version = ver
+                    }
+                Edits = [|e|]
+            }
+        let we = WorkspaceEdit.Create([|edit|], clientCapabilities.Value)
+
+        { CodeAction.Title = title
+          Kind = Some "quickfix"
+          Diagnostics = d |> Option.map Array.singleton
+          Edit = we
+          Command = None}
+
+    override this.TextDocumentCodeAction p = async {
+        if Set.contains (p.TextDocument.Uri.ToLower()) spellcheckIgnore then
+            // TODO: если текущий файл отсеивается, то самое время как-то избавить весь документ от ошибок, вот только как это сделать?
+            // return LspResult.Ok None // Пробовал — выбивает ошибку
+            return LspResult.success (Some (TextDocumentCodeActionResult.CodeActions [||]))
+        else
+            let! res =
+                p
+                |> this.IfDiagnostic "unknown " (fun d ->
+                    async {
+                        do! client.WindowLogMessage {
+                            Type = MessageType.Info
+                            Message = (sprintf "TextDocumentCodeAction 'unknown ...'")
+                        }
+                        match Map.tryFind d.Range lastWords with
+                        | Some word ->
+                            let words =
+                                Suggestion.LevenshteinDistance.suggestions3 word dic
+                                |> Suggestion.LevenshteinDistance.mapTruncate 10
+
+                            let actions =
+                                words
+                                |> List.map (fun word ->
+                                    this.CreateFix p.TextDocument.Uri documentVersion (sprintf "replace on '%s'" word) (Some d) d.Range word)
+                            return actions
+                        | None ->
+                            do! client.WindowLogMessage {
+                                Type = MessageType.Info
+                                Message = (sprintf "range not found:\n%A" d.Range)
+                            }
+                            return []
+                    }
+                )
+            return res |> Array.ofList |> TextDocumentCodeActionResult.CodeActions |> Some |> LspResult.success
+    }
+
+
+    override __.WorkspaceDidChangeConfiguration (x) = async {
+            do! client.WindowLogMessage {
+                Type = MessageType.Info
+                Message = sprintf "WorkspaceDidChangeConfiguration\n%A" (x.Settings.ToString())
+            }
+
+            let config : Either<_, Config> =
+                let ser = Newtonsoft.Json.JsonSerializer()
+                ser.Converters.Add FSharpJsonType.SerializeOption.converter
+                try
+                    x.Settings.ToObject(ser)
+                    |> Right
+                with
+                    e -> Left e.Message
+            match config with
+            | Right x ->
+                x.YASpellChecker
+                |> Option.iter (fun x ->
+                    spellcheckIgnore <- x.SpellcheckIgnore
+                )
+            | Left msg ->
+                do! client.WindowLogMessage {
+                    Type = MessageType.Error
+                    Message = sprintf "%s\n%s" (x.Settings.ToString()) msg
+                }
+        }
+    override x.TextDocumentDocumentHighlight(p) =
+        // p.Position
+        // p.TextDocument.Uri
+        ()
+    override __.Initialize p =
+        async {
+            clientCapabilities <- p.Capabilities
+            /// { "AutomaticWorkspaceInit": false }
+            let c =
+                p.InitializationOptions
+                |> Option.map (fun x -> x.ToString())
+
+            return
+                { Types.InitializeResult.Default with
+                    Capabilities =
+                        { Types.ServerCapabilities.Default with
+                            HoverProvider = None
+                            RenameProvider = Some true
+                            DefinitionProvider = Some true
+                            TypeDefinitionProvider = Some true
+                            ImplementationProvider = Some true
+                            ReferencesProvider = Some true
+                            DocumentHighlightProvider = Some true
+                            DocumentSymbolProvider = None
+                            WorkspaceSymbolProvider = Some true
+                            DocumentFormattingProvider = Some true
+                            DocumentRangeFormattingProvider = Some false
+                            SignatureHelpProvider =
+                            // Some {
+                            //     SignatureHelpOptions.TriggerCharacters = Some [| "("; ","|]
+                            // }
+                                None
+                            CompletionProvider =
+                                None
+                                // Some {
+                                //     ResolveProvider = Some true
+                                //     TriggerCharacters = Some ([| "."; "'"; |])
+                                // }
+                            CodeLensProvider =
+                            // Some {
+                            //     CodeLensOptions.ResolveProvider = Some true
+                            // }
+                                None
+                            CodeActionProvider = Some true
+                            TextDocumentSync =
+                                // None
+                                Some { TextDocumentSyncOptions.Default with
+                                         OpenClose = Some true
+                                         Change = Some TextDocumentSyncKind.Full
+                                         Save = Some { IncludeText = Some true }
+                                     }
+                            FoldingRangeProvider = None
+                        }
+                }
+                |> LspResult.success
+
+    }
+type LocalSetting = {
+    DicPath : string
+}
+open FsharpMyExtension
+[<EntryPoint>]
+let main argv =
+    let localSettingPath = @"E:\Project\YetAnotherSpellCheckerServer\YacsServer\bin\Debug\net461\setting.json"
+    // Json.serf localSettingPath { DicPath = @"E:\Project\YetAnotherSpellCheckerServer\fullRussian.txt"}
+    let localSetting : LocalSetting = Json.desf localSettingPath
+    let state = {
+        State.DicPath = localSetting.DicPath
+    }
+
+    use input = System.Console.OpenStandardInput()
+    use output = System.Console.OpenStandardOutput()
+
+    let requestsHandlings =
+        defaultRequestHandlings<BackgroundServiceServer>()
+        // |> Map.add "spellcheck/setSpellcheckIgnore" (requestHandling (fun (s) p -> s.SetSpellcheckIgnore(p) ))
+
+    Server.start requestsHandlings input output FsacClient (fun lspClient -> BackgroundServiceServer(state, lspClient))
+    |> printfn "%A"
+
+    0

+ 25 - 0
QspServer/QspServer.fsproj

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net461</TargetFramework>
+    <Optimize>true</Optimize>
+    <Tailcalls>true</Tailcalls>
+  </PropertyGroup>
+  <!-- <ItemGroup>
+    <ProjectReference Include="..\LevenshteinDistance\LevenshteinDistance.csproj">
+      <Name>LevenshteinDistance.csproj</Name>
+    </ProjectReference>
+  </ItemGroup> -->
+  <ItemGroup>
+    <Compile Include="..\paket-files\fsharp\FsAutoComplete\src\LanguageServerProtocol\LanguageServerProtocol.fs">
+      <Paket>True</Paket>
+      <Link>paket-files/LanguageServerProtocol.fs</Link>
+    </Compile>
+    <Compile Include="Program.fs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Reference Include="$(FsharpMyExtension)" />
+  </ItemGroup>
+  <Import Project="..\.paket\Paket.Restore.targets" />
+</Project>

+ 11 - 0
QspServer/Test.fsx

@@ -0,0 +1,11 @@
+#I @"e:\Project\FsharpMyExtension\FsharpMyExtension\FsharpMyExtension\bin\Debug\net461\"
+#r @"FParsecCS.dll"
+#r @"FParsec.dll"
+#r @"Fuchu.dll"
+#r @"HtmlAgilityPack.dll"
+#r @"Newtonsoft.Json.dll"
+#r @"Newtonsoft.Json.Bson.dll"
+#r @"FsharpMyExtension.dll"
+
+#time
+open FsharpMyExtension

+ 5 - 0
QspServer/paket.references

@@ -0,0 +1,5 @@
+FSharp.Core
+FuChu
+Newtonsoft.Json
+FParsec
+File:LanguageServerProtocol.fs

+ 0 - 0
TODO


+ 6 - 0
Test/App.config

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
+    </startup>
+</configuration>

+ 36 - 0
Test/Test.fs

@@ -0,0 +1,36 @@
+open Fuchu
+open FsharpMyExtension
+
+[<Tests>]
+let simpleTest =
+    testCase "simpleTest" (fun _ ->
+        let exp = "a"
+        let act = "a"
+        Assert.Equal("msg", exp, act)
+    )
+// run simpleTest // <- если нужно запустить тест вручную
+
+[<Tests>]
+let simpleTestList =
+    testList "testListName" [
+        testCase "testCase1" (fun _ ->
+            let exp = true
+            let act = true
+            Assert.Equal("msg1", exp, act)
+        )
+        testCase "testCase2" (fun _ ->
+            let exp = 1
+            let act = 1
+            Assert.Equal("msg2", exp, act)
+        )
+        testCase "testCase3" (fun _ ->
+            let exp = ()
+            let act = ()
+            Assert.Equal("msg3", exp, act)
+        )
+    ]
+// run simpleTestList
+
+[<EntryPoint;System.STAThread>]
+let main arg =
+    defaultMainThisAssembly arg

+ 23 - 0
Test/Test.fsproj

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net461</TargetFramework>
+    <Optimize>true</Optimize>
+    <Tailcalls>true</Tailcalls>
+  </PropertyGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\QspServer\QspServer.fsproj">
+      <Name>QspServer.fsproj</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+    <Compile Include="Test.fs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Reference Include="System.Runtime" />
+    <Reference Include="$(FsharpMyExtension)" />
+  </ItemGroup>
+  <Import Project="..\.paket\Paket.Restore.targets" />
+</Project>

+ 2 - 0
Test/paket.references

@@ -0,0 +1,2 @@
+FSharp.Core
+FuChu

+ 17 - 0
build.cmd

@@ -0,0 +1,17 @@
+@echo off
+cls
+
+IF EXIST ".paket\paket.exe" (
+  REM Do one thing
+) ELSE (
+  .paket\paket.bootstrapper.exe
+)
+.paket\paket.exe restore
+if errorlevel 1 (
+  exit /b %errorlevel%
+)
+
+packages\build\FAKE\tools\FAKE.exe build.fsx %*
+if errorlevel 1 (
+  REM pause
+)

+ 90 - 0
build.fsx

@@ -0,0 +1,90 @@
+// --------------------------------------------------------------------------------------
+// FAKE build script
+// --------------------------------------------------------------------------------------
+#r "./packages/build/FAKE/tools/FakeLib.dll"
+open Fake.IO.Globbing.Operators
+open Fake.Core
+// --------------------------------------------------------------------------------------
+// Build variables
+// --------------------------------------------------------------------------------------
+let f projName =
+    let pattern = sprintf @"**\%s.fsproj" projName
+    let xs = !! pattern
+    xs
+    |> Seq.tryExactlyOne
+    |> Option.defaultWith (fun () ->
+        xs
+        |> List.ofSeq
+        |> failwithf "'%s' expected exactly one but:\n%A" pattern
+    )
+let testProjName = "Test"
+let testProjPath = f testProjName
+let mainProjName = "QspServer"
+let mainProjPath = f mainProjName
+// --------------------------------------------------------------------------------------
+// Helpers
+// --------------------------------------------------------------------------------------
+open Fake.DotNet
+let buildConf = DotNet.BuildConfiguration.Debug
+let dotnetSdk = lazy DotNet.install DotNet.Versions.FromGlobalJson
+let inline dtntSmpl arg = DotNet.Options.lift dotnetSdk.Value arg
+// --------------------------------------------------------------------------------------
+// Targets
+// --------------------------------------------------------------------------------------
+Target.create "BuildTest" (fun _ ->
+    testProjPath
+    |> Fake.IO.Path.getDirectory
+    |> DotNet.build (fun x ->
+        { x with Configuration = buildConf }
+        |> dtntSmpl)
+)
+
+let run projName projPath =
+    let dir = Fake.IO.Path.getDirectory projPath
+    let localpath = sprintf "bin/%A/net461/%s.exe" buildConf projName
+    let path = Fake.IO.Path.combine dir localpath
+    if not <| Fake.IO.File.exists path then
+        failwithf "not found %s" path
+
+    Command.RawCommand(path, Arguments.Empty)
+    |> CreateProcess.fromCommand
+    |> CreateProcess.withWorkingDirectory (Fake.IO.Path.getDirectory path)
+    |> Proc.run
+
+Target.create "RunTest" (fun _ ->
+    let x = run testProjName testProjPath
+    if x.ExitCode <> 0 then
+        raise <| Fake.Testing.Common.FailedTestsException "test error"
+)
+
+Target.create "RunMainProj" (fun _ ->
+    run mainProjName mainProjPath |> ignore
+)
+
+Target.create "TrimTrailingWhitespace" (fun _ ->
+    // по-хорошему, нужно использовать .gitignore, но и так пока сойдет
+    let files =
+        !! "**/*.fs"
+        ++ "**/*.fsx"
+        ++ "**/*.fsproj"
+        -- "**/obj/**"
+        -- "**/paket-files/**"
+        -- "**/packages/**"
+    files
+    |> Seq.iter (fun path ->
+        System.IO.File.ReadAllLines path
+        |> Array.map (fun x -> x.TrimEnd())
+        |> fun content -> System.IO.File.WriteAllLines(path, content)
+    )
+)
+
+// --------------------------------------------------------------------------------------
+// Build order
+// --------------------------------------------------------------------------------------
+open Fake.Core.TargetOperators
+
+"BuildTest"
+  ==> "RunTest"
+  ==> "RunMainProj"
+
+Target.runOrDefault "RunMainProj"

+ 5 - 0
global.json

@@ -0,0 +1,5 @@
+{
+    "sdk": {
+        "version": "3.1.301"
+    }
+}

+ 17 - 0
paket.dependencies

@@ -0,0 +1,17 @@
+storage: none
+source https://www.nuget.org/api/v2
+
+framework: >= net461
+nuget FAKE
+nuget FParsec
+nuget FSharp.Core
+nuget Fuchu
+nuget Newtonsoft.Json
+
+// https://github.com/fsharp/FsAutoComplete/tree/master/src/LanguageServerProtocol
+github fsharp/FsAutoComplete src/LanguageServerProtocol/LanguageServerProtocol.fs
+
+group Build
+  source https://nuget.org/api/v2
+
+  nuget FAKE

+ 20 - 0
paket.lock

@@ -0,0 +1,20 @@
+STORAGE: NONE
+RESTRICTION: >= net461
+NUGET
+  remote: https://www.nuget.org/api/v2
+    FAKE (5.16)
+    FParsec (1.1.1)
+      FSharp.Core (>= 4.3.4)
+      System.ValueTuple (>= 4.4)
+    FSharp.Core (4.7.2)
+    Fuchu (1.1)
+      FSharp.Core (>= 4.3.4)
+    Newtonsoft.Json (12.0.3)
+    System.ValueTuple (4.5)
+GITHUB
+  remote: fsharp/FsAutoComplete
+    src/LanguageServerProtocol/LanguageServerProtocol.fs (f59b0112d59c9b3440b7e174505804e4dee52ad3)
+GROUP Build
+NUGET
+  remote: https://www.nuget.org/api/v2
+    FAKE (5.16)