dagger is a fast, concurrency safe, mutable, in-memory directed graph library with zero dependencies

Overview

dagger GoDoc

dag

dagger is a blazing fast, concurrency safe, mutable, in-memory directed graph implementation with zero dependencies

import "github.com/autom8ter/dagger"

Design:

  • flexibility
  • global state
    • see primitive to manage graph state manually
  • concurrency safe
  • high performance
  • simple api

Features

  • native graph objects(nodes/edges)
  • typed graph objects(ex: user/pet)
  • labelled nodes & edges
  • depth first search
  • breadth first search
  • concurrency safe
  • import graph from JSON blob
  • export graph to JSON blob

Example

        coleman = dagger.NewNode(map[string]interface{}{
   		"_type": "user",
   		"name":  "coleman",
   	})
   	tyler = dagger.NewNode(map[string]interface{}{
   		"_type": "user",
   		"name":  "coleman",
   	})
   	sarah = dagger.NewNode(map[string]interface{}{
   		"_type": "user",
   		"name":  "sarah",
   	})
   	lacee = dagger.NewNode(map[string]interface{}{
   		"_type": "user",
   		"name":  "lacee",
   	})
   	charlie = dagger.NewNode(map[string]interface{}{
   		"_type":  "dog",
   		"name":   "charlie",
   		"weight": 25,
   	})
   
   	if _, err := coleman.Connect(tyler, "friend", true); err != nil {
   		exitErr(err)
   	}
   	if _, err := sarah.Connect(lacee, "friend", true); err != nil {
   		exitErr(err)
   	}
   	if _, err := coleman.Connect(lacee, "fiance", true); err != nil {
   		exitErr(err)
   	}
   	if _, err := tyler.Connect(sarah, "wife", true); err != nil {
   		exitErr(err)
   	}
   	if _, err := coleman.Connect(charlie, "pet", false); err != nil {
   		exitErr(err)
   	}
   	if _, err := lacee.Connect(charlie, "pet", false); err != nil {
   		exitErr(err)
   	}
   	if _, err := charlie.Connect(lacee, "owner", false); err != nil {
   		exitErr(err)
   	}
   	if _, err := charlie.Connect(coleman, "owner", false); err != nil {
   		exitErr(err)
   	}
   	charlie.Patch(map[string]interface{}{
   		"weight": 19,
   	})
   	if charlie.GetInt("weight") != 19 {
   		exit("expected charlie's weight to be 19!")
   	}
   // check to make sure edge is patched
   	coleman.EdgesFrom(dagger.AnyType(), func(e *dagger.Edge) bool {
   		if e.Type() == "pet" {
   			if e.To().GetInt("weight") != 19 {
   				exit("failed to patch charlie's weight")
   			}
   		}
   		return true
   	})
   	if coleman.GetString("name") != "coleman" {
   		exit("expected name to be coleman")
   	}
   	// remove from graph
   	charlie.Remove()
   	// no longer in graph
   	if dagger.HasNode(charlie) {
   		exit("failed to delete node - (charlie)")
   	}
   	// check to make sure edge no longer exists(cascade)
   	coleman.EdgesFrom(dagger.AnyType(), func(e *dagger.Edge) bool {
   		if e.Type() == "pet" && e.GetString("name") == "charlie" {
   			exit("failed to delete node - (charlie)")
   		}
   		return true
   	})
   	// check to make sure edge no longer exists(cascade)
   	lacee.EdgesFrom(dagger.AnyType(), func(e *dagger.Edge) bool {
   		if e.Type() == "pet" && e.GetString("name") == "charlie" {
   			exit("failed to delete node - (charlie)")
   		}
   		return true
   	})

Output:


registered node types = [dog user]registered edge types = [fiance friend owner pet wife]
found node = {"_id":"cword_1603581855577975000","_type":"user","name":"coleman"}
{"node":{"_id":"aa91881a-1e23-9b44-e059-afe6880816a9","_type":"friend"},"from":{"_id":"cword_1603581855577975000","_type":"user","name":"coleman"},"to":{"_id":"twash_1603581855577992000","_type":"user","name":"tyler"}}
{"node":{"_id":"6ec23de7-9584-964b-79ed-ace7ee06112d","_type":"fiance"},"from":{"_id":"cword_1603581855577975000","_type":"user","name":"coleman"},"to":{"_id":"ljans_1603581855577994000","_type":"user","name":"lacee"}}
{"node":{"_id":"7b86436f-28df-fff1-c198-8093397cc400","_type":"pet"},"from":{"_id":"cword_1603581855577975000","_type":"user","name":"coleman"},"to":{"_id":"85fb2e74-b125-243a-2ac8-8f13b1513824","_type":"dog","name":"charlie","weight":19}}
{"node":{"_id":"1da7e6e1-197f-c65e-a6b9-335298b9c076","_type":"friend"},"from":{"_id":"twash_1603581855577992000","_type":"user","name":"tyler"},"to":{"_id":"cword_1603581855577975000","_type":"user","name":"coleman"}}
{"node":{"_id":"1bbfe7e0-6bf1-bca3-55e3-0281e80663b7","_type":"fiance"},"from":{"_id":"ljans_1603581855577994000","_type":"user","name":"lacee"},"to":{"_id":"cword_1603581855577975000","_type":"user","name":"coleman"}}

found node = {"_id":"twash_1603581855577992000","_type":"user","name":"tyler"}
{"node":{"_id":"1da7e6e1-197f-c65e-a6b9-335298b9c076","_type":"friend"},"from":{"_id":"twash_1603581855577992000","_type":"user","name":"tyler"},"to":{"_id":"cword_1603581855577975000","_type":"user","name":"coleman"}}
{"node":{"_id":"2d6b7738-a549-5c8b-1a82-36e79ead4bc5","_type":"wife"},"from":{"_id":"twash_1603581855577992000","_type":"user","name":"tyler"},"to":{"_id":"swash_1603581855577993000","_type":"user","name":"sarah"}}
{"node":{"_id":"aa91881a-1e23-9b44-e059-afe6880816a9","_type":"friend"},"from":{"_id":"cword_1603581855577975000","_type":"user","name":"coleman"},"to":{"_id":"twash_1603581855577992000","_type":"user","name":"tyler"}}
{"node":{"_id":"3bfd44b4-3c73-0471-81be-1a09ff56e813","_type":"wife"},"from":{"_id":"swash_1603581855577993000","_type":"user","name":"sarah"},"to":{"_id":"twash_1603581855577992000","_type":"user","name":"tyler"}}

found node = {"_id":"cword_1603581855576640000","_type":"user","name":"coleman"}
{"node":{"_id":"001d526f-b4f0-6ac4-6d6f-063144400f3a","_type":"friend"},"from":{"_id":"cword_1603581855576640000","_type":"user","name":"coleman"},"to":{"_id":"twash_1603581855576673000","_type":"user","name":"tyler"}}
{"node":{"_id":"8c145e86-07c1-10f2-2062-6ba194277878","_type":"fiance"},"from":{"_id":"cword_1603581855576640000","_type":"user","name":"coleman"},"to":{"_id":"ljans_1603581855576676000","_type":"user","name":"lacee"}}
{"node":{"_id":"b674a411-949d-6c6f-4279-985d46ab0b64","_type":"pet"},"from":{"_id":"cword_1603581855576640000","_type":"user","name":"coleman"},"to":{"_id":"60a2c505-fcc1-a649-66ac-df3378bba2ec","_type":"dog","name":"charlie","weight":19}}
{"node":{"_id":"6d10e57f-bdee-7fe7-aa4d-ec1368775e09","_type":"friend"},"from":{"_id":"twash_1603581855576673000","_type":"user","name":"tyler"},"to":{"_id":"cword_1603581855576640000","_type":"user","name":"coleman"}}
{"node":{"_id":"3fbb68b7-a8f3-3313-b349-29596cf9a958","_type":"fiance"},"from":{"_id":"ljans_1603581855576676000","_type":"user","name":"lacee"},"to":{"_id":"cword_1603581855576640000","_type":"user","name":"coleman"}}

found node = {"_id":"twash_1603581855578157000","_type":"user","name":"tyler"}
{"node":{"_id":"5371ab6e-8b8b-a2df-d12e-ecf852a083f7","_type":"wife"},"from":{"_id":"twash_1603581855578157000","_type":"user","name":"tyler"},"to":{"_id":"swash_1603581855578158000","_type":"user","name":"sarah"}}
{"node":{"_id":"87c893c3-2959-da05-a390-f0ca062ed90d","_type":"friend"},"from":{"_id":"twash_1603581855578157000","_type":"user","name":"tyler"},"to":{"_id":"cword_1603581855578144000","_type":"user","name":"coleman"}}
{"node":{"_id":"a793eeb7-4e35-5b06-b51f-916bf89d30ee","_type":"friend"},"from":{"_id":"cword_1603581855578144000","_type":"user","name":"coleman"},"to":{"_id":"twash_1603581855578157000","_type":"user","name":"tyler"}}
{"node":{"_id":"ab051d4e-b3a4-7d97-2d00-53b01c92bcbb","_type":"wife"},"from":{"_id":"swash_1603581855578158000","_type":"user","name":"sarah"},"to":{"_id":"twash_1603581855578157000","_type":"user","name":"tyler"}}

found node = {"_id":"swash_1603581855578158000","_type":"user","name":"sarah"}
{"node":{"_id":"e6671030-cb2a-80b8-5453-55991b87a1f6","_type":"friend"},"from":{"_id":"swash_1603581855578158000","_type":"user","name":"sarah"},"to":{"_id":"ljans_1603581855578159000","_type":"user","name":"lacee"}}
{"node":{"_id":"ab051d4e-b3a4-7d97-2d00-53b01c92bcbb","_type":"wife"},"from":{"_id":"swash_1603581855578158000","_type":"user","name":"sarah"},"to":{"_id":"twash_1603581855578157000","_type":"user","name":"tyler"}}
{"node":{"_id":"5371ab6e-8b8b-a2df-d12e-ecf852a083f7","_type":"wife"},"from":{"_id":"twash_1603581855578157000","_type":"user","name":"tyler"},"to":{"_id":"swash_1603581855578158000","_type":"user","name":"sarah"}}
{"node":{"_id":"572ce11b-9c6e-06d0-876b-2cb43d4f9261","_type":"friend"},"from":{"_id":"ljans_1603581855578159000","_type":"user","name":"lacee"},"to":{"_id":"swash_1603581855578158000","_type":"user","name":"sarah"}}

found node = {"_id":"ljans_1603581855576676000","_type":"user","name":"lacee"}
{"node":{"_id":"99ed2178-e43c-ac5f-18be-a65855b35a6e","_type":"friend"},"from":{"_id":"ljans_1603581855576676000","_type":"user","name":"lacee"},"to":{"_id":"swash_1603581855576675000","_type":"user","name":"sarah"}}
{"node":{"_id":"3fbb68b7-a8f3-3313-b349-29596cf9a958","_type":"fiance"},"from":{"_id":"ljans_1603581855576676000","_type":"user","name":"lacee"},"to":{"_id":"cword_1603581855576640000","_type":"user","name":"coleman"}}
{"node":{"_id":"3ae8d958-2cc7-e9e5-fcbc-13b313418167","_type":"pet"},"from":{"_id":"ljans_1603581855576676000","_type":"user","name":"lacee"},"to":{"_id":"60a2c505-fcc1-a649-66ac-df3378bba2ec","_type":"dog","name":"charlie","weight":19}}
{"node":{"_id":"c0bb7318-a05a-1c96-4491-453645130c92","_type":"friend"},"from":{"_id":"swash_1603581855576675000","_type":"user","name":"sarah"},"to":{"_id":"ljans_1603581855576676000","_type":"user","name":"lacee"}}
{"node":{"_id":"8c145e86-07c1-10f2-2062-6ba194277878","_type":"fiance"},"from":{"_id":"cword_1603581855576640000","_type":"user","name":"coleman"},"to":{"_id":"ljans_1603581855576676000","_type":"user","name":"lacee"}}

found node = {"_id":"swash_1603581855577993000","_type":"user","name":"sarah"}
{"node":{"_id":"be911a98-106f-ca4b-1d6e-941715cda021","_type":"friend"},"from":{"_id":"swash_1603581855577993000","_type":"user","name":"sarah"},"to":{"_id":"ljans_1603581855577994000","_type":"user","name":"lacee"}}
{"node":{"_id":"3bfd44b4-3c73-0471-81be-1a09ff56e813","_type":"wife"},"from":{"_id":"swash_1603581855577993000","_type":"user","name":"sarah"},"to":{"_id":"twash_1603581855577992000","_type":"user","name":"tyler"}}
{"node":{"_id":"4233d57b-3c32-d551-b904-90c5aee6f126","_type":"friend"},"from":{"_id":"ljans_1603581855577994000","_type":"user","name":"lacee"},"to":{"_id":"swash_1603581855577993000","_type":"user","name":"sarah"}}
{"node":{"_id":"2d6b7738-a549-5c8b-1a82-36e79ead4bc5","_type":"wife"},"from":{"_id":"twash_1603581855577992000","_type":"user","name":"tyler"},"to":{"_id":"swash_1603581855577993000","_type":"user","name":"sarah"}}

found node = {"_id":"ljans_1603581855577994000","_type":"user","name":"lacee"}
{"node":{"_id":"1bbfe7e0-6bf1-bca3-55e3-0281e80663b7","_type":"fiance"},"from":{"_id":"ljans_1603581855577994000","_type":"user","name":"lacee"},"to":{"_id":"cword_1603581855577975000","_type":"user","name":"coleman"}}
{"node":{"_id":"bb244d0c-751b-9e71-5838-caa21d6c97ad","_type":"pet"},"from":{"_id":"ljans_1603581855577994000","_type":"user","name":"lacee"},"to":{"_id":"85fb2e74-b125-243a-2ac8-8f13b1513824","_type":"dog","name":"charlie","weight":19}}
{"node":{"_id":"4233d57b-3c32-d551-b904-90c5aee6f126","_type":"friend"},"from":{"_id":"ljans_1603581855577994000","_type":"user","name":"lacee"},"to":{"_id":"swash_1603581855577993000","_type":"user","name":"sarah"}}
{"node":{"_id":"be911a98-106f-ca4b-1d6e-941715cda021","_type":"friend"},"from":{"_id":"swash_1603581855577993000","_type":"user","name":"sarah"},"to":{"_id":"ljans_1603581855577994000","_type":"user","name":"lacee"}}
{"node":{"_id":"6ec23de7-9584-964b-79ed-ace7ee06112d","_type":"fiance"},"from":{"_id":"cword_1603581855577975000","_type":"user","name":"coleman"},"to":{"_id":"ljans_1603581855577994000","_type":"user","name":"lacee"}}

found node = {"_id":"twash_1603581855576673000","_type":"user","name":"tyler"}
{"node":{"_id":"39d8cf0b-ca55-da86-9579-9dc3e8dcb442","_type":"wife"},"from":{"_id":"twash_1603581855576673000","_type":"user","name":"tyler"},"to":{"_id":"swash_1603581855576675000","_type":"user","name":"sarah"}}
{"node":{"_id":"6d10e57f-bdee-7fe7-aa4d-ec1368775e09","_type":"friend"},"from":{"_id":"twash_1603581855576673000","_type":"user","name":"tyler"},"to":{"_id":"cword_1603581855576640000","_type":"user","name":"coleman"}}
{"node":{"_id":"001d526f-b4f0-6ac4-6d6f-063144400f3a","_type":"friend"},"from":{"_id":"cword_1603581855576640000","_type":"user","name":"coleman"},"to":{"_id":"twash_1603581855576673000","_type":"user","name":"tyler"}}
{"node":{"_id":"34b7bbd9-534c-31e8-219f-b53246ff0ed4","_type":"wife"},"from":{"_id":"swash_1603581855576675000","_type":"user","name":"sarah"},"to":{"_id":"twash_1603581855576673000","_type":"user","name":"tyler"}}

found node = {"_id":"swash_1603581855576675000","_type":"user","name":"sarah"}
{"node":{"_id":"34b7bbd9-534c-31e8-219f-b53246ff0ed4","_type":"wife"},"from":{"_id":"swash_1603581855576675000","_type":"user","name":"sarah"},"to":{"_id":"twash_1603581855576673000","_type":"user","name":"tyler"}}
{"node":{"_id":"c0bb7318-a05a-1c96-4491-453645130c92","_type":"friend"},"from":{"_id":"swash_1603581855576675000","_type":"user","name":"sarah"},"to":{"_id":"ljans_1603581855576676000","_type":"user","name":"lacee"}}
{"node":{"_id":"39d8cf0b-ca55-da86-9579-9dc3e8dcb442","_type":"wife"},"from":{"_id":"twash_1603581855576673000","_type":"user","name":"tyler"},"to":{"_id":"swash_1603581855576675000","_type":"user","name":"sarah"}}
{"node":{"_id":"99ed2178-e43c-ac5f-18be-a65855b35a6e","_type":"friend"},"from":{"_id":"ljans_1603581855576676000","_type":"user","name":"lacee"},"to":{"_id":"swash_1603581855576675000","_type":"user","name":"sarah"}}

found node = {"_id":"cword_1603581855578144000","_type":"user","name":"coleman"}
{"node":{"_id":"bfb8e908-01b7-2c5b-553b-15e2496bdd6d","_type":"pet"},"from":{"_id":"cword_1603581855578144000","_type":"user","name":"coleman"},"to":{"_id":"45d4829f-c351-ba1a-662a-289de972dcef","_type":"dog","name":"charlie","weight":19}}
{"node":{"_id":"a793eeb7-4e35-5b06-b51f-916bf89d30ee","_type":"friend"},"from":{"_id":"cword_1603581855578144000","_type":"user","name":"coleman"},"to":{"_id":"twash_1603581855578157000","_type":"user","name":"tyler"}}
{"node":{"_id":"48300cc8-ac82-ab8f-7c00-4f3423e3f0b6","_type":"fiance"},"from":{"_id":"cword_1603581855578144000","_type":"user","name":"coleman"},"to":{"_id":"ljans_1603581855578159000","_type":"user","name":"lacee"}}
{"node":{"_id":"87c893c3-2959-da05-a390-f0ca062ed90d","_type":"friend"},"from":{"_id":"twash_1603581855578157000","_type":"user","name":"tyler"},"to":{"_id":"cword_1603581855578144000","_type":"user","name":"coleman"}}
{"node":{"_id":"ffa5d8a0-e981-1836-7f83-a846c271dfe1","_type":"fiance"},"from":{"_id":"ljans_1603581855578159000","_type":"user","name":"lacee"},"to":{"_id":"cword_1603581855578144000","_type":"user","name":"coleman"}}

found node = {"_id":"ljans_1603581855578159000","_type":"user","name":"lacee"}
{"node":{"_id":"572ce11b-9c6e-06d0-876b-2cb43d4f9261","_type":"friend"},"from":{"_id":"ljans_1603581855578159000","_type":"user","name":"lacee"},"to":{"_id":"swash_1603581855578158000","_type":"user","name":"sarah"}}
{"node":{"_id":"ffa5d8a0-e981-1836-7f83-a846c271dfe1","_type":"fiance"},"from":{"_id":"ljans_1603581855578159000","_type":"user","name":"lacee"},"to":{"_id":"cword_1603581855578144000","_type":"user","name":"coleman"}}
{"node":{"_id":"7bf404ca-efe4-5d3e-81b8-297f9a4f3f2f","_type":"pet"},"from":{"_id":"ljans_1603581855578159000","_type":"user","name":"lacee"},"to":{"_id":"45d4829f-c351-ba1a-662a-289de972dcef","_type":"dog","name":"charlie","weight":19}}
{"node":{"_id":"e6671030-cb2a-80b8-5453-55991b87a1f6","_type":"friend"},"from":{"_id":"swash_1603581855578158000","_type":"user","name":"sarah"},"to":{"_id":"ljans_1603581855578159000","_type":"user","name":"lacee"}}
{"node":{"_id":"48300cc8-ac82-ab8f-7c00-4f3423e3f0b6","_type":"fiance"},"from":{"_id":"cword_1603581855578144000","_type":"user","name":"coleman"},"to":{"_id":"ljans_1603581855578159000","_type":"user","name":"lacee"}}

Issues
  • Typo in Readme

    Typo in Readme

    tyler = dagger.NewNode(map[string]interface{}{
       		"_type": "user",
       		"name":  "coleman",
       	})
    

    should be:

    tyler = dagger.NewNode(map[string]interface{}{
       		"_type": "user",
       		"name":  "tyler",
       	})
    
    opened by 89z 0
Owner
Coleman Word
Full stack(Go/Typescript) + Devops + Big Data engineer
Coleman Word
Type-safe, zero-allocation sets for Go

Set Package set is a type-safe, zero-allocation port of the excellent package fatih/set. It contains sets for most of the basic types and you can gene

ScyllaDB 795 Jun 18, 2022
Fast in-memory key:value store/cache with TTL

MCache library go-mcache - this is a fast key:value storage. Its major advantage is that, being essentially a thread-safe . map[string]interface{} wit

O.J 82 Jun 15, 2022
Zero allocation Nullable structures in one library with handy conversion functions, marshallers and unmarshallers

nan - No Allocations Nevermore Package nan - Zero allocation Nullable structures in one library with handy conversion functions, marshallers and unmar

Andrey Kuzmin 52 Jun 18, 2022
Graph algorithms and data structures

Your basic graph Golang library of basic graph algorithms Topological ordering, image by David Eppstein, CC0 1.0. This library offers efficient and we

Algorithms to Go 554 Jun 21, 2022
Graph algorithms written in Go

Graph Algorithms in Go This repository contains implementations of various graph algorithms written in Go. I’ve written them to learn about these algo

Thomas Cyron 47 Jun 21, 2022
Some algorithms in go: maxflow(min-cuts or graph-cuts), edit-distance.

Algorithms In this repository, some algorithms are implemented in go language. GoDoc link: ed maxflow About Max-flow problem: A flow network is repres

Yi Deng 14 Apr 9, 2021
Go framework to simplify CRUD of structured data using Graph operations

gocrud Go framework to simplify creating, reading, updating, and deleting arbitrary depth structured data — to make building REST services fast and ea

Manish R Jain 315 Feb 8, 2022
Graph algorithms and data structures

Your basic graph Golang library of basic graph algorithms Topological ordering, image by David Eppstein, CC0 1.0. This library offers efficient and we

Algorithms to Go 9 Jan 25, 2021
graph package by golang

graph-go sample package main import ( "fmt" "github.com/Iovesophy/graph-go" ) func main() { samplePlace := []graph.Node{ {ID: 1, Element: "plac

Iovesophy 4 Oct 24, 2021
A Connected Graph Generator tool that construct graphs of some given size

graph graph is a Connected Graph Generator tool that construct graphs of some given size. Notice that it generates all possible connected, undirected

Nicolas A Perez 0 Nov 5, 2021
Graphoscope: a solution to access multiple independent data sources from a common UI and show data relations as a graph

Graphoscope A solution to access multiple independent data sources from a common UI and show data relations as a graph: Contains a list of by default

CERT.LV 29 May 26, 2022
estruct traverses javascript projects and maps all the dependencies and relationships to a JSON. the output can be used to build network visualizations of the project and document the architecture.

EStruct traverses javascript projects and maps all the dependencies and relationships to a JSON. The output can be used to build network visualizations of the project and document the architecture.

Ray Luxembourg 11 Jan 27, 2022
Package ring provides a high performance and thread safe Go implementation of a bloom filter.

ring - high performance bloom filter Package ring provides a high performance and thread safe Go implementation of a bloom filter. Usage Please see th

Tanner Ryan 126 May 10, 2022
A thread safe map which has expiring key-value pairs

~ timedmap ~ A map which has expiring key-value pairs. go get github.com/zekroTJA/timedmap Intro This package allows to set values to a map which will

zekro 42 May 25, 2022
Null Types, Safe primitive type conversion and fetching value from complex structures.

Typ Typ is a library providing a powerful interface to impressive user experience with conversion and fetching data from built-in types in Golang Feat

Gurukami 32 Apr 21, 2022
go.fifo provides a simple fifo thread-safe queue for the Go programming language

go.fifo Description go.fifo provides a simple FIFO thread-safe queue. *fifo.Queue supports pushing an item at the end with Add(), and popping an item

Foize 41 Apr 15, 2022
A Golang lock-free thread-safe HashMap optimized for fastest read access.

hashmap Overview A Golang lock-free thread-safe HashMap optimized for fastest read access. Usage Set a value for a key in the map: m := &HashMap{} m.S

Cornel 1.2k Jun 30, 2022
A simple and efficient thread-safe sharded hashmap for Go

shardmap A simple and efficient thread-safe sharded hashmap for Go. This is an alternative to the standard Go map and sync.Map, and is optimized for w

Josh Baker 190 Apr 13, 2022
Smartsort - A smart sorting algorithm for Go to sort filename containing digits that is not zero padded

smartsort A smart sorting algorithm for Go to sort filename containing digits th

Toby Chui 1 Mar 26, 2022