FileSystem (Polyglot)¶

In [ ]:
#r @"../../../../../../../.nuget/packages/fsharp.control.asyncseq/3.2.1/lib/netstandard2.1/FSharp.Control.AsyncSeq.dll"
#r @"../../../../../../../.nuget/packages/system.reactive/6.0.1-preview.1/lib/net6.0/System.Reactive.dll"
#r @"../../../../../../../.nuget/packages/system.reactive.linq/6.0.1-preview.1/lib/netstandard2.0/System.Reactive.Linq.dll"
#r @"../../../../../../../.nuget/packages/argu/6.2.4/lib/netstandard2.0/Argu.dll"
In [ ]:
#!import ../../lib/fsharp/Notebooks.dib
#!import ../../lib/fsharp/Testing.dib
In [ ]:
#!import ../../lib/fsharp/Common.fs
#!import ../../lib/fsharp/CommonFSharp.fs
#!import ../../lib/fsharp/Async.fs
#!import ../../lib/fsharp/AsyncSeq.fs
#!import ../../lib/fsharp/Runtime.fs
In [ ]:
#if !INTERACTIVE
open Lib
#endif
In [ ]:
open Common
open SpiralFileSystem.Operators

watchDirectory¶

In [ ]:
[<RequireQualifiedAccess>]
type FileSystemChangeType =
    | Failure
    | Changed
    | Created
    | Deleted
    | Renamed

[<RequireQualifiedAccess>]
type FileSystemChange =
    | Failure of exn: exn
    | Changed of path: string * content: string option
    | Created of path: string * content: string option
    | Deleted of path: string
    | Renamed of oldPath: string * (string * string option)


let inline watchDirectoryWithFilter filter shouldReadContent path =
    let fullPath = path |> System.IO.Path.GetFullPath
    let _locals () = $"filter: {filter} / {_locals ()}"

    let watcher =
        new System.IO.FileSystemWatcher (
            Path = fullPath,
            NotifyFilter = filter,
            EnableRaisingEvents = true,
            IncludeSubdirectories = true
        )

    let inline getEventPath (path : string) =
        path |> SpiralSm.trim |> SpiralSm.replace fullPath "" |> SpiralSm.trim_start [| '/'; '\\' |]

    let inline ticks () =
        System.DateTime.UtcNow.Ticks

    let changedStream =
        AsyncSeq.subscribeEvent
            watcher.Changed
            (fun event ->
                ticks (),
                [ FileSystemChange.Changed (getEventPath event.FullPath, None) ]
            )

    let deletedStream =
        AsyncSeq.subscribeEvent
            watcher.Deleted
            (fun event ->
                ticks (),
                [ FileSystemChange.Deleted (getEventPath event.FullPath) ]
            )

    let createdStream =
        AsyncSeq.subscribeEvent
            watcher.Created
            (fun event ->
                let path = getEventPath event.FullPath
                ticks (), [
                    FileSystemChange.Created (path, None)
                    if SpiralPlatform.is_windows () then
                        FileSystemChange.Changed (path, None)
                ])

    let renamedStream =
        AsyncSeq.subscribeEvent
            watcher.Renamed
            (fun event ->
                ticks (), [
                    FileSystemChange.Renamed (
                        getEventPath event.OldFullPath,
                        (getEventPath event.FullPath, None)
                    )
                ]
            )

    let failureStream =
        AsyncSeq.subscribeEvent
            watcher.Error
            (fun event -> ticks (), [ FileSystemChange.Failure (event.GetException ()) ])

    let stream =
        [
            changedStream
            deletedStream
            createdStream
            renamedStream
            failureStream
        ]
        |> FSharp.Control.AsyncSeq.mergeAll
        |> FSharp.Control.AsyncSeq.map (fun (t, events) ->
            events
            |> List.fold
                (fun (i, events) event ->
                    i + 1L,
                    (t + i, event) :: events)
                (0L, [])
            |> snd
            |> List.rev
        )
        |> FSharp.Control.AsyncSeq.concatSeq
        |> FSharp.Control.AsyncSeq.mapAsyncParallel (fun (t, event) -> async {
            match shouldReadContent event, event with
            | true, FileSystemChange.Changed (path, _) ->
                do! Async.Sleep 5
                let! content = fullPath </> path |> SpiralFileSystem.read_all_text_retry_async
                return t, FileSystemChange.Changed (path, content)
            | true, FileSystemChange.Created (path, _) ->
                do! Async.Sleep 5
                let! content = fullPath </> path |> SpiralFileSystem.read_all_text_retry_async
                return t, FileSystemChange.Created (path, content)
            | true, FileSystemChange.Renamed (oldPath, (newPath, _)) ->
                let! content = fullPath </> newPath |> SpiralFileSystem.read_all_text_retry_async
                return t, FileSystemChange.Renamed (oldPath, (newPath, content))
            | _ -> return t, event
        })

    let disposable =
        new_disposable (fun () ->
            trace Debug (fun () -> "FileSystem.watchWithFilter / Disposing watch stream") _locals
            watcher.EnableRaisingEvents <- false
            watcher.Dispose ()
        )

    stream, disposable

let inline watchDirectory path =
    watchDirectoryWithFilter
        (System.IO.NotifyFilters.FileName
        // ||| System.IO.NotifyFilters.DirectoryName
        // ||| System.IO.NotifyFilters.Attributes
        //// ||| System.IO.NotifyFilters.Size
        ||| System.IO.NotifyFilters.LastWrite
        //// ||| System.IO.NotifyFilters.LastAccess
        // ||| System.IO.NotifyFilters.CreationTime
        // ||| System.IO.NotifyFilters.Security
        )
        path

testEventsRaw (test)¶

In [ ]:
//// test

let inline testEventsRaw
    (watchFn : (_ -> bool) -> string -> FSharp.Control.AsyncSeq<int64 * FileSystemChange> * IDisposable)
    write
    =
    let struct (tempDir, tempDisposable) =
        "FileSystem.testEventsRaw"
        |> SpiralCrypto.hash_text
        |> SpiralFileSystem.create_temp_dir'
    let stream, disposable = watchFn (fun _ -> true) tempDir

    let events = System.Collections.Concurrent.ConcurrentBag ()

    let inline iter () =
        stream
        |> FSharp.Control.AsyncSeq.iterAsyncParallel (fun event -> async { events.Add event })

    let run = async {
        let! _ = iter () |> Async.StartChild
        do! Async.Sleep 250
        return! write tempDir
    }

    try
        run
        |> Async.runWithTimeout 60000
        |> _assertEqual (Some ())
    finally
        disposable.Dispose ()
        tempDisposable.Dispose ()

    let eventsLog =
        events
        |> Seq.toList
        |> List.sortBy fst
        |> List.fold
            (fun (prev, acc) (ticks, event) ->
                ticks, (ticks, (if prev = 0L then 0L else ticks - prev), event) :: acc
            )
            (0L, [])
        |> snd
        |> List.rev
        |> List.map (fun (diff, n, event) -> $"{n} / {diff} / {event}" |> SpiralSm.ellipsis_end 100L)
        |> SpiralSm.concat "\n"
    let _locals () = $"eventsLog: \n{eventsLog} / {_locals ()}"
    trace Debug (fun () -> "FileSystem.testEventsRaw") _locals

    events
    |> Seq.toList
    |> List.sortBy fst
    |> List.map snd
    |> List.fold
        (fun acc event ->
            match acc, event with
            | FileSystemChange.Changed (lastPath, Some lastContent) as lastEvent :: acc,
                FileSystemChange.Changed (path, Some content)
                when lastPath = path && content |> SpiralSm.starts_with lastContent
                ->
                event :: acc
            | _ -> event :: acc
        )
        []
    |> List.rev

fast (test)¶

In [ ]:
//// test

let inline write path = async {
    let n = 2

    for i = 1 to n do
        do! $"a{i}" |> SpiralFileSystem.write_all_text_async (path </> $"file{i}.txt")

    do! Async.Sleep 250

    for i = 1 to n do
        do! $"b{i}" |> SpiralFileSystem.write_all_text_async (path </> $"file{i}.txt")

    do! Async.Sleep 250

    for i = 1 to n do
        do! path </> $"file{i}.txt" |> SpiralFileSystem.move_file_async (path </> $"file_{i}.txt") |> Async.Ignore

    do! Async.Sleep 250

    for i = 1 to n do
        do! $"c{i}" |> SpiralFileSystem.write_all_text_async (path </> $"file_{i}.txt")

    do! Async.Sleep 250

    for i = 1 to n do
        do! SpiralFileSystem.delete_file_async (path </> $"file_{i}.txt") |> Async.Ignore

    do! Async.Sleep 250
}

let inline run () =
    let events = testEventsRaw watchDirectory write

    events
    |> _sequenceEqual [
        FileSystemChange.Created ("file1.txt", Some "a1")
        FileSystemChange.Changed ("file1.txt", Some "a1")
        FileSystemChange.Created ("file2.txt", Some "a2")
        FileSystemChange.Changed ("file2.txt", Some "a2")

        FileSystemChange.Changed ("file1.txt", Some "b1")
        FileSystemChange.Changed ("file2.txt", Some "b2")

        FileSystemChange.Renamed ("file1.txt", ("file_1.txt", Some "b1"))
        FileSystemChange.Renamed ("file2.txt", ("file_2.txt", Some "b2"))

        FileSystemChange.Changed ("file_1.txt", Some "c1")
        FileSystemChange.Changed ("file_2.txt", Some "c2")

        FileSystemChange.Deleted "file_1.txt"
        FileSystemChange.Deleted "file_2.txt"
    ]

run
|> retry_fn 3
|> _assertEqual (Some ())
Some ()

00:00:03 d #1 FileSystem.watchWithFilter / Disposing watch stream / filter: FileName, LastWrite
00:00:03 d #2 FileSystem.testEventsRaw / eventsLog: 
0 / 638971523457474957 / Created ("file1.txt", Some "a1")
12463 / 638971523457487420 / Changed ("file1.txt", Some "a1")
1647 / 638971523457489067 / Created ("file2.txt", Some "a2")
30 / 638971523457489097 / Changed ("file2.txt", Some "a2")
2490146 / 638971523459979243 / Changed ("file1.txt", Some "b1")
365 / 638971523459979608 / Changed ("file1.txt", Some "b1")
4891 / 638971523459984499 / Changed ("file2.txt", Some "b2")
359 / 638971523459984858 / Changed ("file2.txt", Some "b2")
2558447 / 638971523462543305 / Renamed ("file1.txt", ("file_1.txt", Some "b1"))
7000 / 638971523462550305 / Renamed ("file2.txt", ("file_2.txt", Some "b2"))
2514799 / 638971523465065104 / Changed ("file_1.txt", Some "c1")
825 / 638971523465065929 / Changed ("file_1.txt", Some "c1")
4403 / 638971523465070332 / Changed ("file_2.txt", Some "c2")
466 / 638971523465070798 / Changed ("file_2.txt", Some "c2")
2531190 / 638971523467601988 / Deleted "file_1.txt"
1024 / 638971523467603012 / Deleted "file_2.txt"
[Created ("file1.txt", Some "a1"); Changed ("file1.txt", Some "a1"); Created ("file2.txt", Some "a2");
 Changed ("file2.txt", Some "a2"); Changed ("file1.txt", Some "b1"); Changed ("file2.txt", Some "b2");
 Renamed ("file1.txt", ("file_1.txt", Some "b1")); Renamed ("file2.txt", ("file_2.txt", Some "b2"));
 Changed ("file_1.txt", Some "c1"); Changed ("file_2.txt", Some "c2"); Deleted "file_1.txt"; Deleted "file_2.txt"]

Some ()

slow (test)¶

In [ ]:
//// test

let inline write path = async {
    let n = 2

    let contents =
        [ 1 .. n ]
        |> List.map (string >> String.replicate 1_000_000)

    for i = 1 to n do
        do! $"{contents.[i - 1]}a" |> SpiralFileSystem.write_all_text_async (path </> $"file{i}.txt")

    do! Async.Sleep 1500

    for i = 1 to n do
        do! $"{contents.[i - 1]}b" |> SpiralFileSystem.write_all_text_async (path </> $"file{i}.txt")

    do! Async.Sleep 1500

    for i = 1 to n do
        do! path </> $"file{i}.txt" |> SpiralFileSystem.move_file_async (path </> $"file_{i}.txt") |> Async.Ignore

    do! Async.Sleep 1500

    for i = 1 to n do
        do! $"{contents.[i - 1]}c" |> SpiralFileSystem.write_all_text_async (path </> $"file_{i}.txt")

    do! Async.Sleep 1500

    for i = 1 to n do
        do! SpiralFileSystem.delete_file_async (path </> $"file_{i}.txt") |> Async.Ignore

    do! Async.Sleep 1500
}

let inline run () =
    let events =
        testEventsRaw watchDirectory write
        |> List.map (function
            | FileSystemChange.Changed (path, Some content) ->
                FileSystemChange.Changed (path, content |> Seq.distinct |> Seq.map string |> SpiralSm.concat "" |> Some)
            | FileSystemChange.Created (path, Some content) ->
                FileSystemChange.Created (path, content |> Seq.distinct |> Seq.map string |> SpiralSm.concat "" |> Some)
            | FileSystemChange.Renamed (oldPath, (newPath, Some content)) ->
                FileSystemChange.Renamed (
                    oldPath,
                    (newPath, content |> Seq.distinct |> Seq.map string |> SpiralSm.concat "" |> Some)
                )
            | event -> event
        )

    events
    |> _sequenceEqual [
        FileSystemChange.Created ("file1.txt", Some "1a")
        FileSystemChange.Changed ("file1.txt", Some "1a")
        FileSystemChange.Created ("file2.txt", Some "2a")
        FileSystemChange.Changed ("file2.txt", Some "2a")

        FileSystemChange.Changed ("file1.txt", Some "1b")
        FileSystemChange.Changed ("file2.txt", Some "2b")

        FileSystemChange.Renamed ("file1.txt", ("file_1.txt", Some "1b"))
        FileSystemChange.Renamed ("file2.txt", ("file_2.txt", Some "2b"))

        FileSystemChange.Changed ("file_1.txt", Some "1c")
        FileSystemChange.Changed ("file_2.txt", Some "2c")

        FileSystemChange.Deleted "file_1.txt"
        FileSystemChange.Deleted "file_2.txt"
    ]

run
|> retry_fn 5
|> _assertEqual (Some ())
Some ()

00:00:12 d #3 FileSystem.watchWithFilter / Disposing watch stream / filter: FileName, LastWrite
00:00:13 d #4 FileSystem.testEventsRaw / eventsLog: 
0 / 638971523481792214 / Created
  ("file1.txt",
 ...11111111111111111111111111111111111111111111111a")
3380 / 638971523481795594 / Changed
  ("file1.txt"...11111111111111111111111111111111111111111111111a")
882 / 638971523481796476 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
125 / 638971523481796601 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
43 / 638971523481796644 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
385 / 638971523481797029 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
92 / 638971523481797121 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
82 / 638971523481797203 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
44 / 638971523481797247 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
208 / 638971523481797455 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
285 / 638971523481797740 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
98 / 638971523481797838 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
118 / 638971523481797956 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
64 / 638971523481798020 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
327 / 638971523481798347 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
103 / 638971523481798450 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
172 / 638971523481798622 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
156 / 638971523481798778 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
91 / 638971523481798869 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
65 / 638971523481798934 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
37 / 638971523481798971 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
128 / 638971523481799099 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
64 / 638971523481799163 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
186 / 638971523481799349 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
111 / 638971523481799460 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
105 / 638971523481799565 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
94 / 638971523481799659 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
171 / 638971523481799830 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
40 / 638971523481799870 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
136 / 638971523481800006 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
56 / 638971523481800062 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
92 / 638971523481800154 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
141 / 638971523481800295 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
140 / 638971523481800435 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
48 / 638971523481800483 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
188 / 638971523481800671 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
45 / 638971523481800716 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
184 / 638971523481800900 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
47 / 638971523481800947 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
146 / 638971523481801093 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
120 / 638971523481801213 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
136 / 638971523481801349 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
38 / 638971523481801387 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
122 / 638971523481801509 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
123 / 638971523481801632 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
147 / 638971523481801779 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
39 / 638971523481801818 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
229 / 638971523481802047 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
44 / 638971523481802091 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
138 / 638971523481802229 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
40 / 638971523481802269 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
165 / 638971523481802434 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
59 / 638971523481802493 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
36 / 638971523481802529 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
14264 / 638971523481816793 / Created
  ("file2.txt...22222222222222222222222222222222222222222222222a")
177 / 638971523481816970 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
315 / 638971523481817285 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
310 / 638971523481817595 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
164 / 638971523481817759 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
141 / 638971523481817900 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
47 / 638971523481817947 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
160 / 638971523481818107 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
115 / 638971523481818222 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
113 / 638971523481818335 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
114 / 638971523481818449 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
112 / 638971523481818561 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
142 / 638971523481818703 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
28 / 638971523481818731 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
163 / 638971523481818894 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
31 / 638971523481818925 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
161 / 638971523481819086 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
165 / 638971523481819251 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
108 / 638971523481819359 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
144 / 638971523481819503 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
117 / 638971523481819620 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
112 / 638971523481819732 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
134 / 638971523481819866 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
140 / 638971523481820006 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
103 / 638971523481820109 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
143 / 638971523481820252 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
28 / 638971523481820280 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
159 / 638971523481820439 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
39 / 638971523481820478 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
153 / 638971523481820631 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
27 / 638971523481820658 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
165 / 638971523481820823 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
106 / 638971523481820929 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
168 / 638971523481821097 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
73 / 638971523481821170 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
159 / 638971523481821329 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
40 / 638971523481821369 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
161 / 638971523481821530 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
112 / 638971523481821642 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
138 / 638971523481821780 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
28 / 638971523481821808 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
162 / 638971523481821970 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
107 / 638971523481822077 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
147 / 638971523481822224 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
28 / 638971523481822252 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
153 / 638971523481822405 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
77 / 638971523481822482 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
138 / 638971523481822620 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
156 / 638971523481822776 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
111 / 638971523481822887 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
138 / 638971523481823025 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
149 / 638971523481823174 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
28 / 638971523481823202 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
171 / 638971523481823373 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
72 / 638971523481823445 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
139 / 638971523481823584 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
71 / 638971523481823655 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
138 / 638971523481823793 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
123 / 638971523481823916 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
72 / 638971523481823988 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
209 / 638971523481824197 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
44 / 638971523481824241 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
204 / 638971523481824445 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
50 / 638971523481824495 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
241 / 638971523481824736 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
133 / 638971523481824869 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
183 / 638971523481825052 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
73 / 638971523481825125 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
40 / 638971523481825165 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
215 / 638971523481825380 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
60 / 638971523481825440 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
47 / 638971523481825487 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
260 / 638971523481825747 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
39 / 638971523481825786 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
66 / 638971523481825852 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
194 / 638971523481826046 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
246 / 638971523481826292 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
230 / 638971523481826522 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
57 / 638971523481826579 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
188 / 638971523481826767 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
48 / 638971523481826815 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
166 / 638971523481826981 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
71 / 638971523481827052 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
38 / 638971523481827090 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
169 / 638971523481827259 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
61 / 638971523481827320 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
41 / 638971523481827361 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
205 / 638971523481827566 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
70 / 638971523481827636 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
42 / 638971523481827678 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
191 / 638971523481827869 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
51 / 638971523481827920 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
137 / 638971523481828057 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
168 / 638971523481828225 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
200 / 638971523481828425 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
65 / 638971523481828490 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
42 / 638971523481828532 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
230 / 638971523481828762 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
35 / 638971523481828797 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
43 / 638971523481828840 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
109 / 638971523481828949 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
98 / 638971523481829047 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
167 / 638971523481829214 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
57 / 638971523481829271 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
192 / 638971523481829463 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
46 / 638971523481829509 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
159 / 638971523481829668 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
43 / 638971523481829711 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
139 / 638971523481829850 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
158 / 638971523481830008 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
51 / 638971523481830059 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
50 / 638971523481830109 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
208 / 638971523481830317 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
53 / 638971523481830370 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
42 / 638971523481830412 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
169 / 638971523481830581 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
47 / 638971523481830628 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
40 / 638971523481830668 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
196 / 638971523481830864 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
66 / 638971523481830930 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
37 / 638971523481830967 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
164 / 638971523481831131 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
152 / 638971523481831283 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
41 / 638971523481831324 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
155 / 638971523481831479 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
15049919 / 638971523496881398 / Changed
  ("file1....11111111111111111111111111111111111111111111111b")
1003 / 638971523496882401 / Changed
  ("file1.txt"...11111111111111111111111111111111111111111111111b")
111 / 638971523496882512 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
4526 / 638971523496887038 / Changed
  ("file1.txt"...11111111111111111111111111111111111111111111111b")
109 / 638971523496887147 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
44 / 638971523496887191 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
206 / 638971523496887397 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
260 / 638971523496887657 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
65 / 638971523496887722 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
209 / 638971523496887931 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
311 / 638971523496888242 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
243 / 638971523496888485 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
253 / 638971523496888738 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
275 / 638971523496889013 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
410 / 638971523496889423 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
60 / 638971523496889483 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
190 / 638971523496889673 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
147 / 638971523496889820 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
311 / 638971523496890131 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
143 / 638971523496890274 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
129 / 638971523496890403 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
123 / 638971523496890526 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
123 / 638971523496890649 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
134 / 638971523496890783 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
125 / 638971523496890908 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
124 / 638971523496891032 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
123 / 638971523496891155 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
125 / 638971523496891280 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
173 / 638971523496891453 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
194 / 638971523496891647 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
38 / 638971523496891685 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
138 / 638971523496891823 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
123 / 638971523496891946 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
124 / 638971523496892070 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
123 / 638971523496892193 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
145 / 638971523496892338 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
187 / 638971523496892525 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
301 / 638971523496892826 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
101 / 638971523496892927 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
302 / 638971523496893229 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
50 / 638971523496893279 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
192 / 638971523496893471 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
45 / 638971523496893516 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
184 / 638971523496893700 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
165 / 638971523496893865 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
155 / 638971523496894020 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
318 / 638971523496894338 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
33 / 638971523496894371 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
45 / 638971523496894416 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
158 / 638971523496894574 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
42 / 638971523496894616 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
222 / 638971523496894838 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
99 / 638971523496894937 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
175 / 638971523496895112 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
56 / 638971523496895168 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
221 / 638971523496895389 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
243 / 638971523496895632 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
762 / 638971523496896394 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
42 / 638971523496896436 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
144 / 638971523496896580 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
130 / 638971523496896710 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
136 / 638971523496896846 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
353 / 638971523496897199 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
51 / 638971523496897250 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
36 / 638971523496897286 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
189 / 638971523496897475 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
43 / 638971523496897518 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
134 / 638971523496897652 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
171 / 638971523496897823 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
46 / 638971523496897869 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
842 / 638971523496898711 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
65 / 638971523496898776 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
192 / 638971523496898968 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
173 / 638971523496899141 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
145 / 638971523496899286 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
136 / 638971523496899422 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
20311 / 638971523496919733 / Changed
  ("file2.txt...22222222222222222222222222222222222222222222222b")
115 / 638971523496919848 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
348 / 638971523496920196 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
233 / 638971523496920429 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
44 / 638971523496920473 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
254 / 638971523496920727 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
45 / 638971523496920772 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
149 / 638971523496920921 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
166 / 638971523496921087 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
50 / 638971523496921137 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
195 / 638971523496921332 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
778 / 638971523496922110 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
66 / 638971523496922176 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
21 / 638971523496922197 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
183 / 638971523496922380 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
43 / 638971523496922423 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
187 / 638971523496922610 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
141 / 638971523496922751 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
158 / 638971523496922909 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
162 / 638971523496923071 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
162 / 638971523496923233 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
612 / 638971523496923845 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
58 / 638971523496923903 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
38 / 638971523496923941 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
182 / 638971523496924123 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
42 / 638971523496924165 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
183 / 638971523496924348 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
153 / 638971523496924501 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
153 / 638971523496924654 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
152 / 638971523496924806 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
43 / 638971523496924849 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
223 / 638971523496925072 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
56 / 638971523496925128 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
164 / 638971523496925292 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
150 / 638971523496925442 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
282 / 638971523496925724 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
47 / 638971523496925771 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
200 / 638971523496925971 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
327 / 638971523496926298 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
206 / 638971523496926504 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
66 / 638971523496926570 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
151 / 638971523496926721 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
155 / 638971523496926876 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
38 / 638971523496926914 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
874 / 638971523496927788 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
61 / 638971523496927849 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
33 / 638971523496927882 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
270 / 638971523496928152 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
45 / 638971523496928197 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
179 / 638971523496928376 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
154 / 638971523496928530 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
156 / 638971523496928686 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
202 / 638971523496928888 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
181 / 638971523496929069 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
156 / 638971523496929225 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
164 / 638971523496929389 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
149 / 638971523496929538 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
194 / 638971523496929732 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
147 / 638971523496929879 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
151 / 638971523496930030 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
154 / 638971523496930184 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
149 / 638971523496930333 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
254 / 638971523496930587 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
62 / 638971523496930649 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
11387 / 638971523496942036 / Changed
  ("file2.txt...22222222222222222222222222222222222222222222222b")
15017952 / 638971523511959988 / Renamed
  ("file1....1111111111111111111111111111111111111111111111b"))
433 / 638971523511960421 / Renamed
  ("file2.txt",...2222222222222222222222222222222222222222222222b"))
15026452 / 638971523526986873 / Changed
  ("file_1...11111111111111111111111111111111111111111111111c")
651 / 638971523526987524 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
594 / 638971523526988118 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
100 / 638971523526988218 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
59 / 638971523526988277 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
396 / 638971523526988673 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
64 / 638971523526988737 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
38 / 638971523526988775 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
957 / 638971523526989732 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
85 / 638971523526989817 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
42 / 638971523526989859 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
660 / 638971523526990519 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
67 / 638971523526990586 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
44 / 638971523526990630 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
277 / 638971523526990907 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
72 / 638971523526990979 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
1383 / 638971523526992362 / Changed
  ("file_1.txt...11111111111111111111111111111111111111111111111c")
87 / 638971523526992449 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
210 / 638971523526992659 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
62 / 638971523526992721 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
237 / 638971523526992958 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
53 / 638971523526993011 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
355 / 638971523526993366 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
221 / 638971523526993587 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
254 / 638971523526993841 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
91 / 638971523526993932 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
340 / 638971523526994272 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
94 / 638971523526994366 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
104 / 638971523526994470 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
75 / 638971523526994545 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
58 / 638971523526994603 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
1796 / 638971523526996399 / Changed
  ("file_1.txt...11111111111111111111111111111111111111111111111c")
100 / 638971523526996499 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
48 / 638971523526996547 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
61 / 638971523526996608 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
866 / 638971523526997474 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
120 / 638971523526997594 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
51 / 638971523526997645 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
1213 / 638971523526998858 / Changed
  ("file_1.txt...11111111111111111111111111111111111111111111111c")
84 / 638971523526998942 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
44 / 638971523526998986 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
142 / 638971523526999128 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
217 / 638971523526999345 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
48 / 638971523526999393 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
356 / 638971523526999749 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
43 / 638971523526999792 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
731 / 638971523527000523 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
67 / 638971523527000590 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
177 / 638971523527000767 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
2369 / 638971523527003136 / Changed
  ("file_1.txt...11111111111111111111111111111111111111111111111c")
15514 / 638971523527018650 / Changed
  ("file_2.tx...22222222222222222222222222222222222222222222222c")
200 / 638971523527018850 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
362 / 638971523527019212 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
62 / 638971523527019274 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
294 / 638971523527019568 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
63 / 638971523527019631 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
283 / 638971523527019914 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
156 / 638971523527020070 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
151 / 638971523527020221 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
158 / 638971523527020379 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
300 / 638971523527020679 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
58 / 638971523527020737 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
215 / 638971523527020952 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
167 / 638971523527021119 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
158 / 638971523527021277 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
361 / 638971523527021638 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
226 / 638971523527021864 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
330 / 638971523527022194 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
40 / 638971523527022234 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
41 / 638971523527022275 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
209 / 638971523527022484 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
299 / 638971523527022783 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
33 / 638971523527022816 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
41 / 638971523527022857 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
238 / 638971523527023095 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
148 / 638971523527023243 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
50 / 638971523527023293 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
207 / 638971523527023500 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
50 / 638971523527023550 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
172 / 638971523527023722 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
352 / 638971523527024074 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
60 / 638971523527024134 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
216 / 638971523527024350 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
49 / 638971523527024399 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
284 / 638971523527024683 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
347 / 638971523527025030 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
79 / 638971523527025109 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
153 / 638971523527025262 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
181 / 638971523527025443 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
233 / 638971523527025676 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
54 / 638971523527025730 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
136 / 638971523527025866 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
348 / 638971523527026214 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
68 / 638971523527026282 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
189 / 638971523527026471 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
50 / 638971523527026521 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
209 / 638971523527026730 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
50 / 638971523527026780 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
315 / 638971523527027095 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
57 / 638971523527027152 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
45 / 638971523527027197 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
207 / 638971523527027404 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
235 / 638971523527027639 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
139 / 638971523527027778 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
144 / 638971523527027922 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
125 / 638971523527028047 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
317 / 638971523527028364 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
57 / 638971523527028421 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
167 / 638971523527028588 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
49 / 638971523527028637 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
243 / 638971523527028880 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
190 / 638971523527029070 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
43 / 638971523527029113 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
225 / 638971523527029338 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
51 / 638971523527029389 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
832 / 638971523527030221 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
91 / 638971523527030312 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
42 / 638971523527030354 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
208 / 638971523527030562 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
47 / 638971523527030609 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
170 / 638971523527030779 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
155 / 638971523527030934 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
170 / 638971523527031104 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
59 / 638971523527031163 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
163 / 638971523527031326 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
48 / 638971523527031374 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
209 / 638971523527031583 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
158 / 638971523527031741 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
217 / 638971523527031958 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
674 / 638971523527032632 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
71 / 638971523527032703 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
49 / 638971523527032752 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
45 / 638971523527032797 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
196 / 638971523527032993 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
48 / 638971523527033041 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
175 / 638971523527033216 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
201 / 638971523527033417 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
185 / 638971523527033602 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
211 / 638971523527033813 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
165 / 638971523527033978 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
161 / 638971523527034139 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
164 / 638971523527034303 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
136 / 638971523527034439 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
155 / 638971523527034594 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
38 / 638971523527034632 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
3475 / 638971523527038107 / Changed
  ("file_2.txt...22222222222222222222222222222222222222222222222c")
15026610 / 638971523542064717 / Deleted "file_1.txt"
5000 / 638971523542069717 / Deleted "file_2.txt"
[Created ("file1.txt", Some "1a"); Changed ("file1.txt", Some "1a"); Created ("file2.txt", Some "2a");
 Changed ("file2.txt", Some "2a"); Changed ("file1.txt", Some "1b"); Changed ("file2.txt", Some "2b");
 Renamed ("file1.txt", ("file_1.txt", Some "1b")); Renamed ("file2.txt", ("file_2.txt", Some "2b"));
 Changed ("file_1.txt", Some "1c"); Changed ("file_2.txt", Some "2c"); Deleted "file_1.txt"; Deleted "file_2.txt"]

Some ()

testEventsSorted (test)¶

In [ ]:
//// test

let inline sortEvent event =
    match event with
    | FileSystemChange.Failure _ -> 0
    | FileSystemChange.Created _ -> 1
    | FileSystemChange.Changed _ -> 2
    | FileSystemChange.Renamed (_oldPath, _) -> 3
    | FileSystemChange.Deleted _ -> 4

let inline formatEvents events =
    events
    |> Seq.toList
    |> List.sortBy (snd >> sortEvent)
    |> List.choose (fun (ticks, event) ->
        match event with
        | FileSystemChange.Failure _ ->
            None
        | FileSystemChange.Changed (path, _) ->
            Some (ticks, System.IO.Path.GetFileName path, nameof FileSystemChangeType.Changed)
        | FileSystemChange.Created (path, _) ->
            Some (ticks, System.IO.Path.GetFileName path, nameof FileSystemChangeType.Created)
        | FileSystemChange.Deleted path ->
            Some (ticks, System.IO.Path.GetFileName path, nameof FileSystemChangeType.Deleted)
        | FileSystemChange.Renamed (_oldPath, (path, _)) ->
            Some (ticks, System.IO.Path.GetFileName path, nameof FileSystemChangeType.Renamed)
    )
    |> List.sortBy (fun (_, path, _) -> path)
    |> List.distinctBy (fun (_, path, event) -> path, event)

let inline testEventsSorted
    (watchFn : string -> FSharp.Control.AsyncSeq<int64 * FileSystemChange> * IDisposable)
    write
    =
    let struct (tempDir, tempDisposable) =
        "FileSystem.testEventsSorted"
        |> SpiralCrypto.hash_text
        |> SpiralFileSystem.create_temp_dir'
    let stream, disposable = watchFn tempDir

    let events = System.Collections.Concurrent.ConcurrentBag ()

    let inline iter () =
        stream
        |> FSharp.Control.AsyncSeq.iterAsyncParallel (fun event -> async { events.Add event })

    let run = async {
        let! _ = iter () |> Async.StartChild
        do! Async.Sleep 250
        return! write tempDir
    }

    try
        run
        |> Async.runWithTimeout 5000
        |> _assertEqual (Some ())
    finally
        disposable.Dispose ()
        tempDisposable.Dispose ()

    let events = formatEvents events

    let eventMap =
        events
        |> List.map (fun (ticks, path, event) -> path, (event, ticks))
        |> List.groupBy fst
        |> List.map (fun (path, events) ->
            let event, _ticks =
                events
                |> List.map snd
                |> List.sortByDescending snd
                |> List.head

            path, event
        )
        |> Map.ofList

    let eventList =
        events
        |> List.map (fun (_ticks, path, event) -> path, event)

    eventMap, eventList

create and delete (test)¶

In [ ]:
//// test

let inline write path = async {
    let n = 3

    for i = 1 to n do
        do! $"{i}" |> SpiralFileSystem.write_all_text_async (path </> $"file{i}.txt")

    for i = 1 to n do
        do! SpiralFileSystem.delete_file_async (path </> $"file{i}.txt") |> Async.Ignore

    do! Async.Sleep 150
}

let inline run () =
    let eventMap, eventList = testEventsSorted (watchDirectory (fun _ -> false)) write

    [
        "file1.txt", nameof FileSystemChangeType.Created
        "file1.txt", nameof FileSystemChangeType.Changed
        "file1.txt", nameof FileSystemChangeType.Deleted

        "file2.txt", nameof FileSystemChangeType.Created
        "file2.txt", nameof FileSystemChangeType.Changed
        "file2.txt", nameof FileSystemChangeType.Deleted

        "file3.txt", nameof FileSystemChangeType.Created
        "file3.txt", nameof FileSystemChangeType.Changed
        "file3.txt", nameof FileSystemChangeType.Deleted
    ]
    |> _sequenceEqual eventList

    [
        "file1.txt", nameof FileSystemChangeType.Deleted
        "file2.txt", nameof FileSystemChangeType.Deleted
        "file3.txt", nameof FileSystemChangeType.Deleted
    ]
    |> Map.ofList
    |> _sequenceEqual eventMap

run
|> retry_fn 3
|> _assertEqual (Some ())
Some ()

00:00:15 d #5 FileSystem.watchWithFilter / Disposing watch stream / filter: FileName, LastWrite
[("file1.txt", "Created"); ("file1.txt", "Changed"); ("file1.txt", "Deleted"); ("file2.txt", "Created");
 ("file2.txt", "Changed"); ("file2.txt", "Deleted"); ("file3.txt", "Created"); ("file3.txt", "Changed");
 ("file3.txt", "Deleted")]

map [("file1.txt", "Deleted"); ("file2.txt", "Deleted"); ("file3.txt", "Deleted")]

Some ()

change (test)¶

In [ ]:
//// test

let inline write path = async {
    let n = 2

    for i = 1 to n do
        do! $"{i}" |> SpiralFileSystem.write_all_text_async (path </> $"file{i}.txt")

    for i = 1 to n do
        do! "" |> SpiralFileSystem.write_all_text_async (path </> $"file{i}.txt")

    for i = 1 to n do
        do! SpiralFileSystem.delete_file_async (path </> $"file{i}.txt") |> Async.Ignore

    do! Async.Sleep 150
}

let inline run () =
    let eventMap, eventList = testEventsSorted (watchDirectory (fun _ -> false)) write

    [
        "file1.txt", nameof FileSystemChangeType.Created
        "file1.txt", nameof FileSystemChangeType.Changed
        "file1.txt", nameof FileSystemChangeType.Deleted

        "file2.txt", nameof FileSystemChangeType.Created
        "file2.txt", nameof FileSystemChangeType.Changed
        "file2.txt", nameof FileSystemChangeType.Deleted
    ]
    |> _sequenceEqual eventList

    [
        "file1.txt", nameof FileSystemChangeType.Deleted
        "file2.txt", nameof FileSystemChangeType.Deleted
    ]
    |> Map.ofList
    |> _sequenceEqual eventMap

run
|> retry_fn 3
|> _assertEqual (Some ())
Some ()

00:00:16 d #6 FileSystem.watchWithFilter / Disposing watch stream / filter: FileName, LastWrite
[("file1.txt", "Created"); ("file1.txt", "Changed"); ("file1.txt", "Deleted"); ("file2.txt", "Created");
 ("file2.txt", "Changed"); ("file2.txt", "Deleted")]

map [("file1.txt", "Deleted"); ("file2.txt", "Deleted")]

Some ()

rename (test)¶

In [ ]:
//// test

let inline write path = async {
    let n = 2

    for i = 1 to n do
        do! $"{i}" |> SpiralFileSystem.write_all_text_async (path </> $"file{i}.txt")

    for i = 1 to n do
        do! path </> $"file{i}.txt" |> SpiralFileSystem.move_file_async (path </> $"file_{i}.txt") |> Async.Ignore

    for i = 1 to n do
        do! SpiralFileSystem.delete_file_async (path </> $"file_{i}.txt") |> Async.Ignore

    do! Async.Sleep 150
}

let inline run () =
    let eventMap, eventList = testEventsSorted (watchDirectory (fun _ -> false)) write

    [
        "file1.txt", nameof FileSystemChangeType.Created
        "file1.txt", nameof FileSystemChangeType.Changed
        "file2.txt", nameof FileSystemChangeType.Created
        "file2.txt", nameof FileSystemChangeType.Changed

        "file_1.txt", nameof FileSystemChangeType.Renamed
        "file_1.txt", nameof FileSystemChangeType.Deleted

        "file_2.txt", nameof FileSystemChangeType.Renamed
        "file_2.txt", nameof FileSystemChangeType.Deleted
    ]
    |> _sequenceEqual eventList

    [
        "file1.txt", nameof FileSystemChangeType.Changed
        "file2.txt", nameof FileSystemChangeType.Changed
        "file_1.txt", nameof FileSystemChangeType.Deleted
        "file_2.txt", nameof FileSystemChangeType.Deleted
    ]
    |> Map.ofList
    |> _sequenceEqual eventMap

run
|> retry_fn 3
|> _assertEqual (Some ())
Some ()

00:00:17 d #7 FileSystem.watchWithFilter / Disposing watch stream / filter: FileName, LastWrite
[("file1.txt", "Created"); ("file1.txt", "Changed"); ("file2.txt", "Created"); ("file2.txt", "Changed");
 ("file_1.txt", "Renamed"); ("file_1.txt", "Deleted"); ("file_2.txt", "Renamed"); ("file_2.txt", "Deleted")]

map [("file1.txt", "Changed"); ("file2.txt", "Changed"); ("file_1.txt", "Deleted"); ("file_2.txt", "Deleted")]

Some ()

full (test)¶

In [ ]:
//// test

let inline write path = async {
    let n = 2

    for i = 1 to n do
        do! $"{i}" |> SpiralFileSystem.write_all_text_async (path </> $"file{i}.txt")

    for i = 1 to n do
        do! "" |> SpiralFileSystem.write_all_text_async (path </> $"file{i}.txt")

    for i = 1 to n do
        do! path </> $"file{i}.txt" |> SpiralFileSystem.move_file_async (path </> $"file_{i}.txt") |> Async.Ignore

    for i = 1 to n do
        do! $"{i}" |> SpiralFileSystem.write_all_text_async (path </> $"file_{i}.txt")

    for i = 1 to n do
        do! SpiralFileSystem.delete_file_async (path </> $"file_{i}.txt") |> Async.Ignore

    do! Async.Sleep 150
}

let inline run () =
    let eventMap, eventList = testEventsSorted (watchDirectory (fun _ -> false)) write

    [
        "file1.txt", nameof FileSystemChangeType.Created
        "file1.txt", nameof FileSystemChangeType.Changed
        "file2.txt", nameof FileSystemChangeType.Created
        "file2.txt", nameof FileSystemChangeType.Changed

        "file_1.txt", nameof FileSystemChangeType.Changed
        "file_1.txt", nameof FileSystemChangeType.Renamed
        "file_1.txt", nameof FileSystemChangeType.Deleted

        "file_2.txt", nameof FileSystemChangeType.Changed
        "file_2.txt", nameof FileSystemChangeType.Renamed
        "file_2.txt", nameof FileSystemChangeType.Deleted
    ]
    |> _sequenceEqual eventList

    [
        "file1.txt", nameof FileSystemChangeType.Changed
        "file2.txt", nameof FileSystemChangeType.Changed
        "file_1.txt", nameof FileSystemChangeType.Deleted
        "file_2.txt", nameof FileSystemChangeType.Deleted
    ]
    |> Map.ofList
    |> _sequenceEqual eventMap

run
|> retry_fn 3
|> _assertEqual (Some ())
Some ()

00:00:18 d #8 FileSystem.watchWithFilter / Disposing watch stream / filter: FileName, LastWrite
[("file1.txt", "Created"); ("file1.txt", "Changed"); ("file2.txt", "Created"); ("file2.txt", "Changed");
 ("file_1.txt", "Changed"); ("file_1.txt", "Renamed"); ("file_1.txt", "Deleted"); ("file_2.txt", "Changed");
 ("file_2.txt", "Renamed"); ("file_2.txt", "Deleted")]

map [("file1.txt", "Changed"); ("file2.txt", "Changed"); ("file_1.txt", "Deleted"); ("file_2.txt", "Deleted")]

Some ()