From fe56be2a048cd072524e3101b68a7989a06f1f9e Mon Sep 17 00:00:00 2001 From: Unbewohnte Date: Sun, 2 Apr 2023 19:06:26 +0300 Subject: [PATCH] Thanks files; More code comments --- Makefile | 8 +++-- README.md | 13 +++++-- src/client/main.go | 34 ++++++++++++++---- src/server/main.go | 25 ++++++++++---- src/server/thanks/thanks.go | 57 +++++++++++++++++++++++++++++++ src/server/thanksdir/thanks01.txt | 12 +++++++ src/server/thanksdir/thanks02.txt | 16 +++++++++ src/server/thanksdir/thanks03.txt | 11 ++++++ src/server/thanksdir/thanks04.txt | 11 ++++++ src/server/thanksdir/thanks05.txt | 12 +++++++ 10 files changed, 181 insertions(+), 18 deletions(-) create mode 100644 src/server/thanks/thanks.go create mode 100644 src/server/thanksdir/thanks01.txt create mode 100644 src/server/thanksdir/thanks02.txt create mode 100644 src/server/thanksdir/thanks03.txt create mode 100644 src/server/thanksdir/thanks04.txt create mode 100644 src/server/thanksdir/thanks05.txt diff --git a/Makefile b/Makefile index 53691ea..d39502f 100644 --- a/Makefile +++ b/Makefile @@ -2,9 +2,10 @@ all: server client mkdir -p bin mv spolitewareServer* bin mv spolitewareClient* bin + mv thanksdir bin server: - cd src/server && go build && mv spolitewareServer ../../ + cd src/server && CGO_ENABLED=0 go build && mv spolitewareServer ../../ && cp -r thanksdir ../../ client: cd src/client && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build && mv spolitewareClient ../../spolitewareClient_linux_amd64 @@ -12,9 +13,10 @@ client: cd src/client && CGO_ENABLED=0 GOOS=windows GOARCH=386 go build && mv spolitewareClient.exe ../../spolitewareClient_windows_x32.exe cd src/client && CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build && mv spolitewareClient.exe ../../spolitewareClient_windows_amd64.exe -release: client +release: client server mkdir -p release/spoliteware cp LICENSE release/spoliteware - cd src/server && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build && mv spolitewareServer ../../release/spoliteware + mv spolitewareServer release/spoliteware + mv thanksdir release/spoliteware mv spolitewareClient* release/spoliteware cd release && zip -r spoliteware spoliteware \ No newline at end of file diff --git a/README.md b/README.md index 90bf6a9..9b6f9e8 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,19 @@ # Spoliteware - a polite and considerate spyware -A spyware that asks permission to collect data beforehand. +A polite spyware that asks permission to collect data beforehand. ## Features +### v0.1.1 + +### Client +- Display thanks message from the server + +### Server +- Thanks system and thanksfiles + +### v0.1.0 + ### Client - System information @@ -12,7 +22,6 @@ A spyware that asks permission to collect data beforehand. - TLS support ## TODO -- Give some sort of "reward" for permitting to scan client's machine - More green telemetry options - Be more open on what the program does diff --git a/src/client/main.go b/src/client/main.go index 5f47ab8..4c3a69a 100644 --- a/src/client/main.go +++ b/src/client/main.go @@ -18,6 +18,7 @@ import ( "encoding/json" "flag" "fmt" + "io" "net/http" "os" "path/filepath" @@ -27,7 +28,7 @@ import ( ) const ( - Version string = "client v0.1.0" + Version string = "client v0.1.1" ) var ( @@ -35,21 +36,25 @@ var ( serverAddr *string = flag.String("server", "http://localhost:13370/", "Set scheme://addr:port for receiving server") ) +// The structure of the generalised per computer data that is identical to the server's +// representation type Data struct { Hostname string `json:"hostname"` Username string `json:"username"` System map[string]string `json:"system"` } +// Prints notification on the state of things func greeting() { fmt.Printf( - `I'm sorry to inform you, but you've (intentionally or not) launched a spyware on your machine ! + `I'm sorry to inform you, but you've (intentionally or not) launched a spyware on your machine! But rest assured, I will do no harm to your computer and am to withdraw if you would wish so. No data will be collected and sent without your permission. `) } +// Asks for permission to collect all kinds of data on the machine func askForAllPerms() bool { fmt.Printf(`Would you grant me a permission to [system information; files lookup; ] (If no -> (optional) specify separate permissions afterwards) y/N: `) @@ -65,6 +70,7 @@ func askForAllPerms() bool { } } +// Asks for permission to collect system information func askForSystemInfo() bool { fmt.Printf("\nWould you allow me to look around and collect some information about your computer ? [y/N]: ") var input string = "n" @@ -80,6 +86,7 @@ func askForSystemInfo() bool { } } +// Asks whether a local copy of the whole collected data is needed func localCopyNeeded() bool { fmt.Printf("\nDo you want to save a local copy as well ? [y/N]: ") var input string = "n" @@ -113,6 +120,7 @@ func main() { var data Data data.System = nil + // Greet and ask for permissions greeting() if askForAllPerms() { data.System = osutil.GetSystemInfo() @@ -123,6 +131,7 @@ func main() { } if data.System == nil { + // NOTICE! add new checks for new fields when they're added fmt.Printf("\nNothing to send. Bailing out\n") return } @@ -135,24 +144,26 @@ func main() { return } + // Try to send collected information to the server postBody := bytes.NewBuffer(dataJson) var retries uint8 = 0 + var response *http.Response for { if retries == 5 { fmt.Printf("\nFailed to send data\n") return } - response, err := http.Post(*serverAddr, "application/json", postBody) + response, err = http.Post(*serverAddr, "application/json", postBody) if err != nil || response == nil { - // try to resend + // Try to resend time.Sleep(time.Second * 5) retries++ continue } if response.StatusCode != http.StatusOK { - // try to resend + // Try to resend time.Sleep(time.Second * 5) retries++ continue @@ -160,8 +171,18 @@ func main() { break } - fmt.Printf("\nSuccesfully sent data. Thank you !\n") + // Successfully sent + fmt.Printf("\nSuccesfully sent data\n") + // Print thanks from the server + defer response.Body.Close() + thanks, err := io.ReadAll(response.Body) + if err != nil { + fmt.Printf("\nFailed to read thanks message from the server. Better luck next time. Thank you !\n") + } + fmt.Printf("\n%s\n", thanks) + + // Create local copy if needed if localCopyNeeded() { wdir, err := os.Getwd() if err != nil { @@ -182,6 +203,7 @@ func main() { fmt.Printf("Saved to %s\n", copyPath) } + // Don't close the console window for windows users if runtime.GOOS == "windows" { fmt.Scanln() } diff --git a/src/server/main.go b/src/server/main.go index 10f31ea..2a596bf 100644 --- a/src/server/main.go +++ b/src/server/main.go @@ -13,6 +13,7 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I package main import ( + "Unbewohnte/spolitewareServer/thanks" "encoding/json" "flag" "fmt" @@ -31,14 +32,15 @@ type Data struct { System map[string]string `json:"system"` } -const Version string = "server v0.1.0" +const Version string = "server v0.1.1" var ( - version *bool = flag.Bool("version", false, "Print version information and exit") - port *uint = flag.Uint("port", 13370, "Set port to listen on") - keyFile *string = flag.String("key", "", "SSL private key file path") - certFile *string = flag.String("cert", "", "SSL certificate file path") - verbose *bool = flag.Bool("verbose", false, "Print user data-centric messages or not") + version *bool = flag.Bool("version", false, "Print version information and exit") + port *uint = flag.Uint("port", 13370, "Set port to listen on") + keyFile *string = flag.String("key", "", "SSL private key file path") + certFile *string = flag.String("cert", "", "SSL certificate file path") + verbose *bool = flag.Bool("verbose", false, "Print user data-centric messages or not") + thanksdirName *string = flag.String("thanksdirname", "thanksdir", "Select the NAME of the thanks directory with thanks files") ) func main() { @@ -72,6 +74,8 @@ func main() { return } + thanksdir := filepath.Join(filepath.Dir(executablePath), *thanksdirName) + mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { if *keyFile != "" && *certFile != "" { @@ -147,7 +151,14 @@ func main() { return } - w.WriteHeader(http.StatusOK) + // Send thanks + thanksStr, err := thanks.GetRandom(thanksdir) + if err != nil { + w.Write([]byte(thanks.Default())) + } else { + w.Write([]byte(thanksStr)) + } + if *verbose { fmt.Printf("[INFO] Received data from %s_%s_%s\n", clientData.Hostname, clientData.Username, ip) } diff --git a/src/server/thanks/thanks.go b/src/server/thanks/thanks.go new file mode 100644 index 0000000..e5fa247 --- /dev/null +++ b/src/server/thanks/thanks.go @@ -0,0 +1,57 @@ +package thanks + +import ( + "io" + "math/rand" + "os" + "path/filepath" +) + +// Default thanks +func Default() string { + return ` + Thank you ! +⠀⠀⠀⠀⠀⠀⠀⢰⠒⠒⠒⠒⠒⠒⢲⡖⣶⣶⡆⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⢀⡀⣯⠉⠉⠉⣖⣲⣶⡆⠀⠀⠈⠉⠉⠉⠉⠉⠉⢱⠀⠀⠀⠀ +⢀⣀⣸⠀⠀⠀⠀⠀⠈⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣇⣀⡀ +⢸⣿⣀⣀⡀⠀⠿⠿⠀⠀⠀⣸⣙⣿⣿⠀⢸⣿⠀⠀⠀⠀⠀⠀⢰⡇ +⢸⡿⠾⠿⠟⠀⠀⠀⣤⡄⠀⠸⠿⠿⠟⠀⠸⠿⠀⠀⠀⣠⣤⠀⢸⡇ +⢸⡃⠀⠀⠀⠀⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠛⠀⢸⡇ +⢸⣖⠀⠀⠀⠀⠀⠀⠙⠋⠀⢴⣶⣶⣶⠀⠀⠀⣶⣶⠀⠀⠀⠀⢸⡇ +⢸⣿⣶⠀⠀⠀⣶⣶⠀⠀⠀⠈⠉⠉⠉⠀⠀⠀⠉⠉⠀⠀⠀⣷⣾⡇ +⠈⠉⢹⣿⣿⣀⣀⣠⠀⠀⠀⠀⠀⠀⠸⣿⡇⠀⣀⣀⣀⣿⣿⡏⠉⠁ +⠀⠀⠀⠀⢿⠿⠿⢿⣀⣀⣀⣀⣠⣤⣤⣤⣤⣤⣿⠿⠿⡿⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠸⠿⠿⠿⠿⠿⣿⣿⣿⣿⠿⠇⠀⠀⠀⠀⠀⠀⠀ +` +} + +// Fetches random thanks file from thanksdir +func GetRandom(thanksdir string) (string, error) { + entries, err := os.ReadDir(thanksdir) + if err != nil { + return Default(), err + } + + fileIndex := rand.Intn(len(entries)) + entryInfo, err := entries[fileIndex].Info() + if err != nil { + return Default(), err + } + + if entryInfo.IsDir() { + return Default(), nil + } + + thanksfile, err := os.Open(filepath.Join(thanksdir, entryInfo.Name())) + if err != nil { + return Default(), err + } + defer thanksfile.Close() + + thanks, err := io.ReadAll(thanksfile) + if err != nil { + return Default(), err + } + + return string(thanks), nil +} diff --git a/src/server/thanksdir/thanks01.txt b/src/server/thanksdir/thanks01.txt new file mode 100644 index 0000000..d49117a --- /dev/null +++ b/src/server/thanksdir/thanks01.txt @@ -0,0 +1,12 @@ +Thank you! Have a nice day! +⠀⠀⠀⠀⠀⠀⠀⢰⠒⠒⠒⠒⠒⠒⢲⡖⣶⣶⡆⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⢀⡀⣯⠉⠉⠉⣖⣲⣶⡆⠀⠀⠈⠉⠉⠉⠉⠉⠉⢱⠀⠀⠀⠀ +⢀⣀⣸⠀⠀⠀⠀⠀⠈⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣇⣀⡀ +⢸⣿⣀⣀⡀⠀⠿⠿⠀⠀⠀⣸⣙⣿⣿⠀⢸⣿⠀⠀⠀⠀⠀⠀⢰⡇ +⢸⡿⠾⠿⠟⠀⠀⠀⣤⡄⠀⠸⠿⠿⠟⠀⠸⠿⠀⠀⠀⣠⣤⠀⢸⡇ +⢸⡃⠀⠀⠀⠀⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠛⠀⢸⡇ +⢸⣖⠀⠀⠀⠀⠀⠀⠙⠋⠀⢴⣶⣶⣶⠀⠀⠀⣶⣶⠀⠀⠀⠀⢸⡇ +⢸⣿⣶⠀⠀⠀⣶⣶⠀⠀⠀⠈⠉⠉⠉⠀⠀⠀⠉⠉⠀⠀⠀⣷⣾⡇ +⠈⠉⢹⣿⣿⣀⣀⣠⠀⠀⠀⠀⠀⠀⠸⣿⡇⠀⣀⣀⣀⣿⣿⡏⠉⠁ +⠀⠀⠀⠀⢿⠿⠿⢿⣀⣀⣀⣀⣠⣤⣤⣤⣤⣤⣿⠿⠿⡿⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠸⠿⠿⠿⠿⠿⣿⣿⣿⣿⠿⠇⠀⠀⠀⠀⠀⠀⠀ diff --git a/src/server/thanksdir/thanks02.txt b/src/server/thanksdir/thanks02.txt new file mode 100644 index 0000000..a8520b3 --- /dev/null +++ b/src/server/thanksdir/thanks02.txt @@ -0,0 +1,16 @@ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⡴⠚⣉⡙⠲⠦⠤⠤⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⢀⣴⠛⠉⠉⠀⣾⣷⣿⡆⠀⠀⠀⠐⠛⠿⢟⡲⢦⡀⠀⠀⠀⠀ +⠀⠀⠀⠀⣠⢞⣭⠎⠀⠀⠀⠀⠘⠛⠛⠀⠀⢀⡀⠀⠀⠀⠀⠈⠓⠿⣄⠀⠀⠀ +⠀⠀⠀⡜⣱⠋⠀⠀⣠⣤⢄⠀⠀⠀⠀⠀⠀⣿⡟⣆⠀⠀⠀⠀⠀⠀⠻⢷⡄⠀ +⠀⢀⣜⠜⠁⠀⠀⠀⢿⣿⣷⣵⠀⠀⠀⠀⠀⠿⠿⠿⠀⠀⣴⣶⣦⡀⠀⠰⣹⡆ +⢀⡞⠆⠀⣀⡀⠀⠀⠘⠛⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣶⠇⠀⢠⢻⡇ +⢸⠃⠘⣾⣏⡇⠀⠀⠀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⣠⣤⣤⡉⠁⠀⠀⠈⠫⣧ +⡸⡄⠀⠘⠟⠀⠀⠀⠀⠀⠀⣰⣿⣟⢧⠀⠀⠀⠀⠰⡿⣿⣿⢿⠀⠀⣰⣷⢡⢸ +⣿⡇⠀⠀⠀⣰⣿⡻⡆⠀⠀⠻⣿⣿⣟⠀⠀⠀⠀⠀⠉⠉⠉⠀⠀⠘⢿⡿⣸⡞ +⠹⣽⣤⣤⣤⣹⣿⡿⠇⠀⠀⠀⠀⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡔⣽⠀ +⠀⠙⢻⡙⠟⣹⠟⢷⣶⣄⢀⣴⣶⣄⠀⠀⠀⠀⠀⢀⣤⡦⣄⠀⠀⢠⣾⢸⠏⠀ +⠀⠀⠘⠀⠀⠀⠀⠀⠈⢷⢼⣿⡿⡽⠀⠀⠀⠀⠀⠸⣿⣿⣾⠀⣼⡿⣣⠟⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⢠⡾⣆⠑⠋⠀⢀⣀⠀⠀⠀⠀⠈⠈⢁⣴⢫⡿⠁⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⣧⣄⡄⠴⣿⣶⣿⢀⣤⠶⣞⣋⣩⣵⠏⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⢺⣿⢯⣭⣭⣯⣯⣥⡵⠿⠟⠛⠉⠉⠀⠀⠀⠀⠀⠀⠀ +Thank you! You are the tallest when you first wake up. diff --git a/src/server/thanksdir/thanks03.txt b/src/server/thanksdir/thanks03.txt new file mode 100644 index 0000000..8f42a88 --- /dev/null +++ b/src/server/thanksdir/thanks03.txt @@ -0,0 +1,11 @@ +⠀⠀⠀⣖⠲⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠉⡇⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠸⡆⠹⡀⣠⢤⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡏⠀⡧⢤⡄⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⡧⢄⣹⣅⣜⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠁⠀⢹⠚⠃⠀⠀⠀⠀⠀ +⠀⣀⠴⢒⣉⡹⣶⣤⣀⡉⠉⠒⠒⠒⠤⠤⣀⣀⣀⠇⠀⠀⢸⠠⣄⠀⠀⠀⠀⠀ +⠀⠈⠉⠁⠀⠀⠀⠉⠒⠯⣟⣲⠦⣤⣀⡀⠀⠀⠈⠉⠉⠉⠛⠒⠻⢥⣀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⣲⡬⠭⠿⢷⣦⣤⢄⣀⠀⠀⠚⠛⠛⠓⢦⡀ +⠀⠀⠀⠀⠀⠀⠀⢀⣀⠤⠴⠚⠉⠁⠀⠀⠀⠀⣀⣉⡽⣕⣯⡉⠉⠉⠑⢒⣒⡾ +⠀⠀⣀⡠⠴⠒⠉⠉⠀⢀⣀⣀⠤⡤⢶⣶⣋⠉⠉⠀⠀⠀⠈⠉⠉⠉⠉⠉⠁⠀ +⣖⣉⣁⣠⠤⠶⡶⡶⢍⡉⠀⠀⠀⠙⠒⠯⠜⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠁⠀⠀⠀⠀⠑⢦⣯⠇ +Thank you! 2 is the only even prime number. diff --git a/src/server/thanksdir/thanks04.txt b/src/server/thanksdir/thanks04.txt new file mode 100644 index 0000000..8c584a8 --- /dev/null +++ b/src/server/thanksdir/thanks04.txt @@ -0,0 +1,11 @@ +Thank you! Wikipedia is downloadable. +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠄⠒⡢⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡀⣠⡀⠀⠀⢰⡣⢀⠀⡃⢀⠀ +⠀⠀⢀⡾⢇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠔⡡⠒⣒⠫⣆⣈⣴⡡⠁⠹⠓⠐⠂ +⠀⠀⢸⠀⡞⠀⠀⠀⡀⠀⠀⠀⠀⠀⣄⡈⢎⠀⠻⠃⠈⡇⠊⠉⠔⠁⠀⠀⠀⠀ +⠀⠀⣠⡿⠇⠒⣒⣒⣏⡤⢤⣀⠀⠀⢁⡿⡌⠄⠀⠀⣴⠇⠈⠀⠁⠀⠀⠀⠀⠀ +⠀⣾⠋⣡⣈⠄⠀⠚⠃⠩⢹⢛⠨⠟⠇⠠⡐⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠸⡇⣾⠙⡟⣿⠀⠀⠀⠘⠛⠨⠀⡃⠀⠘⡹⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠱⢌⣂⡧⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⣀⡀⢡⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠈⢻⠥⠌⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ diff --git a/src/server/thanksdir/thanks05.txt b/src/server/thanksdir/thanks05.txt new file mode 100644 index 0000000..d86a044 --- /dev/null +++ b/src/server/thanksdir/thanks05.txt @@ -0,0 +1,12 @@ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠳⢶⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣤⣤⣤⣤⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⣯⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⢸⣛⣟⣻⣟⣻⣟⣻⣟⣻⣛⣿⣛⣿⣛⣿⣟⣛⣛⣻⣿⣿⣟⣛⣻⡇⠀⠀ +⠀⠀⢸⣉⣹⣏⣹⣏⣹⣏⣻⣋⣿⣉⣿⣉⣿⣙⣟⣉⣹⣏⣹⣏⣹⣏⣻⡇⠀⠀ +⠀⠀⢸⣹⣏⣹⣏⣹⣏⣹⣏⣿⣉⣿⣉⣿⣉⣿⠈⡿⢿⣏⣹⣏⣹⣏⣿⡇⠀⠀ +⠀⠀⢸⣉⣹⣏⣹⣏⣹⣏⣽⣍⣿⣉⣿⣉⣿⣏⣠⣷⣾⣏⣹⣏⣹⣏⣽⡇⠀⠀ +⠀⠀⢸⣭⣯⣽⣯⣭⣭⣭⣭⣭⣭⣭⣭⣿⣭⣿⣭⣯⣽⣯⣭⣭⣽⣯⣽⡇⠀⠀ + +Thank you! Crazy how people made sand to do math