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 / 638871582587878566 / Created ("file1.txt", Some "a1")
12076 / 638871582587890642 / Changed ("file1.txt", Some "a1")
1924 / 638871582587892566 / Created ("file2.txt", Some "a2")
43 / 638871582587892609 / Changed ("file2.txt", Some "a2")
2488437 / 638871582590381046 / Changed ("file1.txt", Some "b1")
411 / 638871582590381457 / Changed ("file1.txt", Some "b1")
5761 / 638871582590387218 / Changed ("file2.txt", Some "b2")
2556141 / 638871582592943359 / Renamed ("file1.txt", ("file_1.txt", Some "b1"))
6421 / 638871582592949780 / Renamed ("file2.txt", ("file_2.txt", Some "b2"))
2517436 / 638871582595467216 / Changed ("file_1.txt", Some "c1")
531 / 638871582595467747 / Changed ("file_1.txt", Some "c1")
4499 / 638871582595472246 / Changed ("file_2.txt", Some "c2")
203 / 638871582595472449 / Changed ("file_2.txt", Some "c2")
2532066 / 638871582598004515 / Deleted "file_1.txt"
984 / 638871582598005499 / 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 / 638871582612441120 / Created
  ("file1.txt",
 ...11111111111111111111111111111111111111111111111a")
3121 / 638871582612444241 / Changed
  ("file1.txt"...11111111111111111111111111111111111111111111111a")
282 / 638871582612444523 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
59 / 638871582612444582 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
51 / 638871582612444633 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
505 / 638871582612445138 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
410 / 638871582612445548 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
212 / 638871582612445760 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
190 / 638871582612445950 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
292 / 638871582612446242 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
333 / 638871582612446575 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
306 / 638871582612446881 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
201 / 638871582612447082 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
110 / 638871582612447192 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
50 / 638871582612447242 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
125 / 638871582612447367 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
467 / 638871582612447834 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
172 / 638871582612448006 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
144 / 638871582612448150 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
99 / 638871582612448249 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
67 / 638871582612448316 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
703 / 638871582612449019 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
113 / 638871582612449132 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
40 / 638871582612449172 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
330 / 638871582612449502 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
186 / 638871582612449688 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
45 / 638871582612449733 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
255 / 638871582612449988 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
183 / 638871582612450171 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
46 / 638871582612450217 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
68 / 638871582612450285 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
352 / 638871582612450637 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
50 / 638871582612450687 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
232 / 638871582612450919 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
163 / 638871582612451082 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
53 / 638871582612451135 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111a")
241 / 638871582612451376 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111a")
21926 / 638871582612473302 / Created
  ("file2.txt...22222222222222222222222222222222222222222222222a")
198 / 638871582612473500 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
54 / 638871582612473554 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
761 / 638871582612474315 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
97 / 638871582612474412 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
27 / 638871582612474439 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
166 / 638871582612474605 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
52 / 638871582612474657 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
62 / 638871582612474719 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
169 / 638871582612474888 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
46 / 638871582612474934 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
210 / 638871582612475144 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
51 / 638871582612475195 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
693 / 638871582612475888 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
78 / 638871582612475966 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
240 / 638871582612476206 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
348 / 638871582612476554 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
60 / 638871582612476614 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
272 / 638871582612476886 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
188 / 638871582612477074 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
45 / 638871582612477119 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
210 / 638871582612477329 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
52 / 638871582612477381 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
244 / 638871582612477625 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
46 / 638871582612477671 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
249 / 638871582612477920 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
173 / 638871582612478093 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
47 / 638871582612478140 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
206 / 638871582612478346 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
947 / 638871582612479293 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
85 / 638871582612479378 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
58 / 638871582612479436 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
206 / 638871582612479642 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
158 / 638871582612479800 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
155 / 638871582612479955 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
151 / 638871582612480106 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
153 / 638871582612480259 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
157 / 638871582612480416 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
171 / 638871582612480587 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
47 / 638871582612480634 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
188 / 638871582612480822 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
156 / 638871582612480978 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
185 / 638871582612481163 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
153 / 638871582612481316 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
125 / 638871582612481441 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
164 / 638871582612481605 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
252 / 638871582612481857 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
39 / 638871582612481896 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
118 / 638871582612482014 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
166 / 638871582612482180 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
45 / 638871582612482225 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
200 / 638871582612482425 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
56 / 638871582612482481 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
291 / 638871582612482772 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
160 / 638871582612482932 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
277 / 638871582612483209 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
59 / 638871582612483268 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
40 / 638871582612483308 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
235 / 638871582612483543 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
182 / 638871582612483725 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
53 / 638871582612483778 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
214 / 638871582612483992 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
755 / 638871582612484747 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
41 / 638871582612484788 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
40 / 638871582612484828 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
216 / 638871582612485044 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
210 / 638871582612485254 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
198 / 638871582612485452 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
170 / 638871582612485622 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
164 / 638871582612485786 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
154 / 638871582612485940 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
210 / 638871582612486150 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
183 / 638871582612486333 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
439 / 638871582612486772 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
226 / 638871582612486998 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
30 / 638871582612487028 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
57 / 638871582612487085 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
941 / 638871582612488026 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
76 / 638871582612488102 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
214 / 638871582612488316 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
53 / 638871582612488369 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
123 / 638871582612488492 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
109 / 638871582612488601 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
126 / 638871582612488727 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222a")
46 / 638871582612488773 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222a")
15037563 / 638871582627526336 / Changed
  ("file1....11111111111111111111111111111111111111111111111b")
604 / 638871582627526940 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
95 / 638871582627527035 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
2845 / 638871582627529880 / Changed
  ("file1.txt"...11111111111111111111111111111111111111111111111b")
127 / 638871582627530007 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
44 / 638871582627530051 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
218 / 638871582627530269 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
171 / 638871582627530440 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
174 / 638871582627530614 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
183 / 638871582627530797 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
153 / 638871582627530950 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
157 / 638871582627531107 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
184 / 638871582627531291 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
158 / 638871582627531449 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
150 / 638871582627531599 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
168 / 638871582627531767 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
75 / 638871582627531842 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
221 / 638871582627532063 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
226 / 638871582627532289 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
164 / 638871582627532453 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
159 / 638871582627532612 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
805 / 638871582627533417 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
78 / 638871582627533495 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
235 / 638871582627533730 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
91 / 638871582627533821 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
178 / 638871582627533999 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
154 / 638871582627534153 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
152 / 638871582627534305 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
153 / 638871582627534458 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
199 / 638871582627534657 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
175 / 638871582627534832 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
82 / 638871582627534914 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
293 / 638871582627535207 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
50 / 638871582627535257 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
1072 / 638871582627536329 / Changed
  ("file1.txt"...11111111111111111111111111111111111111111111111b")
328 / 638871582627536657 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
255 / 638871582627536912 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
53 / 638871582627536965 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
174 / 638871582627537139 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
65 / 638871582627537204 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
175 / 638871582627537379 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
165 / 638871582627537544 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
47 / 638871582627537591 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
203 / 638871582627537794 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
131 / 638871582627537925 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
162 / 638871582627538087 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
61 / 638871582627538148 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
213 / 638871582627538361 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
249 / 638871582627538610 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
50 / 638871582627538660 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
1043 / 638871582627539703 / Changed
  ("file1.txt"...11111111111111111111111111111111111111111111111b")
65 / 638871582627539768 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
41 / 638871582627539809 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
35 / 638871582627539844 / Changed
  ("file1.txt",
...11111111111111111111111111111111111111111111111b")
313 / 638871582627540157 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
159 / 638871582627540316 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
295 / 638871582627540611 / Changed
  ("file1.txt",...11111111111111111111111111111111111111111111111b")
11651 / 638871582627552262 / Changed
  ("file1.txt...11111111111111111111111111111111111111111111111b")
11343 / 638871582627563605 / Changed
  ("file2.txt...22222222222222222222222222222222222222222222222b")
254 / 638871582627563859 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
533 / 638871582627564392 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
77 / 638871582627564469 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
323 / 638871582627564792 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
313 / 638871582627565105 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
50 / 638871582627565155 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
223 / 638871582627565378 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
47 / 638871582627565425 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
299 / 638871582627565724 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
250 / 638871582627565974 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
69 / 638871582627566043 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
543 / 638871582627566586 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
107 / 638871582627566693 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
38 / 638871582627566731 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
1980 / 638871582627568711 / Changed
  ("file2.txt"...22222222222222222222222222222222222222222222222b")
110 / 638871582627568821 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
231 / 638871582627569052 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
255 / 638871582627569307 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
269 / 638871582627569576 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
46 / 638871582627569622 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
172 / 638871582627569794 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
46 / 638871582627569840 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
169 / 638871582627570009 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
141 / 638871582627570150 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
157 / 638871582627570307 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
169 / 638871582627570476 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
173 / 638871582627570649 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
164 / 638871582627570813 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
43 / 638871582627570856 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
268 / 638871582627571124 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
162 / 638871582627571286 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
181 / 638871582627571467 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
171 / 638871582627571638 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
159 / 638871582627571797 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
59 / 638871582627571856 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
189 / 638871582627572045 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
241 / 638871582627572286 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
225 / 638871582627572511 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
163 / 638871582627572674 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
203 / 638871582627572877 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
470 / 638871582627573347 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
193 / 638871582627573540 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
116 / 638871582627573656 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
148 / 638871582627573804 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
40 / 638871582627573844 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
849 / 638871582627574693 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
66 / 638871582627574759 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
188 / 638871582627574947 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
44 / 638871582627574991 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
166 / 638871582627575157 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
154 / 638871582627575311 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
154 / 638871582627575465 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
175 / 638871582627575640 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
42 / 638871582627575682 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
170 / 638871582627575852 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
42 / 638871582627575894 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
187 / 638871582627576081 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
128 / 638871582627576209 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
300 / 638871582627576509 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
353 / 638871582627576862 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
814 / 638871582627577676 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
59 / 638871582627577735 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
192 / 638871582627577927 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
150 / 638871582627578077 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
175 / 638871582627578252 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
43 / 638871582627578295 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
172 / 638871582627578467 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
185 / 638871582627578652 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
298 / 638871582627578950 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
287 / 638871582627579237 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
165 / 638871582627579402 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
155 / 638871582627579557 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
171 / 638871582627579728 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
142 / 638871582627579870 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
156 / 638871582627580026 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
148 / 638871582627580174 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
163 / 638871582627580337 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
39 / 638871582627580376 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
182 / 638871582627580558 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
399 / 638871582627580957 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
78 / 638871582627581035 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
210 / 638871582627581245 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
164 / 638871582627581409 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
207 / 638871582627581616 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
152 / 638871582627581768 / Changed
  ("file2.txt",...22222222222222222222222222222222222222222222222b")
36 / 638871582627581804 / Changed
  ("file2.txt",
...22222222222222222222222222222222222222222222222b")
15035929 / 638871582642617733 / Renamed
  ("file1....1111111111111111111111111111111111111111111111b"))
452 / 638871582642618185 / Renamed
  ("file2.txt",...2222222222222222222222222222222222222222222222b"))
15035250 / 638871582657653435 / Changed
  ("file_1...11111111111111111111111111111111111111111111111c")
669 / 638871582657654104 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
2625 / 638871582657656729 / Changed
  ("file_1.txt...11111111111111111111111111111111111111111111111c")
288 / 638871582657657017 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
529 / 638871582657657546 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
422 / 638871582657657968 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
363 / 638871582657658331 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
266 / 638871582657658597 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
273 / 638871582657658870 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
352 / 638871582657659222 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
275 / 638871582657659497 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
504 / 638871582657660001 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
147 / 638871582657660148 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
1279 / 638871582657661427 / Changed
  ("file_1.txt...11111111111111111111111111111111111111111111111c")
117 / 638871582657661544 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
221 / 638871582657661765 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
334 / 638871582657662099 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
232 / 638871582657662331 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
229 / 638871582657662560 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
324 / 638871582657662884 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
320 / 638871582657663204 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
505 / 638871582657663709 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
66 / 638871582657663775 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
228 / 638871582657664003 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
54 / 638871582657664057 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
194 / 638871582657664251 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
342 / 638871582657664593 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
1158 / 638871582657665751 / Changed
  ("file_1.txt...11111111111111111111111111111111111111111111111c")
147 / 638871582657665898 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
102 / 638871582657666000 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
50 / 638871582657666050 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
41 / 638871582657666091 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
2262 / 638871582657668353 / Changed
  ("file_1.txt...11111111111111111111111111111111111111111111111c")
106 / 638871582657668459 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
169 / 638871582657668628 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
238 / 638871582657668866 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
244 / 638871582657669110 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
217 / 638871582657669327 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
201 / 638871582657669528 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
383 / 638871582657669911 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
63 / 638871582657669974 / Changed
  ("file_1.txt",...11111111111111111111111111111111111111111111111c")
191 / 638871582657670165 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
348 / 638871582657670513 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
244 / 638871582657670757 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
246 / 638871582657671003 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
192 / 638871582657671195 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
201 / 638871582657671396 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
204 / 638871582657671600 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
190 / 638871582657671790 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
211 / 638871582657672001 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
197 / 638871582657672198 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
191 / 638871582657672389 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
215 / 638871582657672604 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
243 / 638871582657672847 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
268 / 638871582657673115 / Changed
  ("file_1.txt"...11111111111111111111111111111111111111111111111c")
5257 / 638871582657678372 / Changed
  ("file_1.txt...11111111111111111111111111111111111111111111111c")
14951 / 638871582657693323 / Changed
  ("file_2.tx...22222222222222222222222222222222222222222222222c")
224 / 638871582657693547 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
49 / 638871582657693596 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
248 / 638871582657693844 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
33 / 638871582657693877 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
66 / 638871582657693943 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
328 / 638871582657694271 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
38 / 638871582657694309 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
57 / 638871582657694366 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
169 / 638871582657694535 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
49 / 638871582657694584 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
252 / 638871582657694836 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
211 / 638871582657695047 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
140 / 638871582657695187 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
109 / 638871582657695296 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
194 / 638871582657695490 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
56 / 638871582657695546 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
251 / 638871582657695797 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
53 / 638871582657695850 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
207 / 638871582657696057 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
220 / 638871582657696277 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
354 / 638871582657696631 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
251 / 638871582657696882 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
51 / 638871582657696933 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
50 / 638871582657696983 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
153 / 638871582657697136 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
48 / 638871582657697184 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
283 / 638871582657697467 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
116 / 638871582657697583 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
49 / 638871582657697632 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
753 / 638871582657698385 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
55 / 638871582657698440 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
48 / 638871582657698488 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
171 / 638871582657698659 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
1666 / 638871582657700325 / Changed
  ("file_2.txt...22222222222222222222222222222222222222222222222c")
1080 / 638871582657701405 / Changed
  ("file_2.txt...22222222222222222222222222222222222222222222222c")
947 / 638871582657702352 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
433 / 638871582657702785 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
85 / 638871582657702870 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
214 / 638871582657703084 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
155 / 638871582657703239 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
212 / 638871582657703451 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
382 / 638871582657703833 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
72 / 638871582657703905 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
221 / 638871582657704126 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
252 / 638871582657704378 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
614 / 638871582657704992 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
60 / 638871582657705052 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
46 / 638871582657705098 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
778 / 638871582657705876 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
86 / 638871582657705962 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
754 / 638871582657706716 / Changed
  ("file_2.txt"...22222222222222222222222222222222222222222222222c")
69 / 638871582657706785 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
66 / 638871582657706851 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
45 / 638871582657706896 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
1227 / 638871582657708123 / Changed
  ("file_2.txt...22222222222222222222222222222222222222222222222c")
85 / 638871582657708208 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
45 / 638871582657708253 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
1303 / 638871582657709556 / Changed
  ("file_2.txt...22222222222222222222222222222222222222222222222c")
76 / 638871582657709632 / Changed
  ("file_2.txt",...22222222222222222222222222222222222222222222222c")
67106 / 638871582657776738 / Changed
  ("file_2.tx...22222222222222222222222222222222222222222222222c")
14969469 / 638871582672746207 / Deleted "file_1.txt"
5411 / 638871582672751618 / 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 ()