Restructure repository: organize tools by purpose, create what search tool
- Move single-file tools to tools/ organized by category (security, forensics, data, etc.) - Move multi-file projects to projects/ (go-tools, puzzlebox, timesketch, rust-tools) - Move system scripts to scripts/ (proxy, display, setup, windows) - Organize config files in config/ (shell, visidata, applications) - Move experimental tools to archive/experimental - Create 'what' fuzzy search tool with progressive enhancement (ollama->fzf->grep) - Add initial metadata database for intelligent tool discovery - Preserve git history using 'git mv' commands
This commit is contained in:
56
projects/go-tools/go/csv2json/csv2json.go
Normal file
56
projects/go-tools/go/csv2json/csv2json.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func csvToJson(inputSource *os.File) {
|
||||
csvReader := csv.NewReader(inputSource)
|
||||
headers, err := csvReader.Read()
|
||||
if err != nil {
|
||||
log.Fatal("Failed to read headers: ", err)
|
||||
}
|
||||
for {
|
||||
record, err := csvReader.Read()
|
||||
if err != nil {
|
||||
if err.Error() == "EOF" {
|
||||
break
|
||||
}
|
||||
log.Fatal("Failed to read the data: ", err)
|
||||
}
|
||||
if len(record) == len(headers) {
|
||||
jsonData := make(map[string]string)
|
||||
for i, value := range record {
|
||||
jsonData[headers[i]] = value
|
||||
}
|
||||
jsonOutput, err := json.Marshal(jsonData)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to convert to json: ", err)
|
||||
}
|
||||
fmt.Println(string(jsonOutput))
|
||||
} else {
|
||||
log.Fatal("The number of columns in the record is not equal to the number of headers")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func main() {
|
||||
inputSource := os.Stdin
|
||||
flag.Parse()
|
||||
var err error
|
||||
if flag.NArg() > 0 {
|
||||
inputSource, err = os.Open(flag.Args()[0])
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to open file: %v\n", err)
|
||||
}
|
||||
defer inputSource.Close()
|
||||
}
|
||||
csvToJson(inputSource)
|
||||
|
||||
}
|
||||
140
projects/go-tools/go/gobetween/gobetween.go
Normal file
140
projects/go-tools/go/gobetween/gobetween.go
Normal file
@@ -0,0 +1,140 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func printUsage() {
|
||||
fmt.Fprintf(os.Stderr, "Usage: %s [options] <range specification> [file]\n", os.Args[0])
|
||||
fmt.Fprintln(os.Stderr, "Options:")
|
||||
flag.PrintDefaults()
|
||||
fmt.Fprintln(os.Stderr, "\nRange specification examples:")
|
||||
fmt.Fprintln(os.Stderr, "10,20 Reads lines 10 to 20 from the input")
|
||||
fmt.Fprintln(os.Stderr, "15:+5 Reads 5 lines starting from line 15")
|
||||
fmt.Fprintln(os.Stderr, "3 Reads from line 3 to the end of the file")
|
||||
fmt.Fprintln(os.Stderr, "+2 Reads the first 2 lines")
|
||||
fmt.Fprintln(os.Stderr, "Please ensure you input valid range specifications and file paths.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func parseArgs(args []string) (int, int, string, error) {
|
||||
var filename string
|
||||
var start, length, end int
|
||||
found := false
|
||||
|
||||
// Concatenate all arguments to a single string for easier parsing
|
||||
joinedArgs := strings.Join(args, " ")
|
||||
|
||||
// Regular expression to match ranges and numbers
|
||||
rangeRegex := regexp.MustCompile(`((\d+)?([ :,;-]))(\+)?(\d+)`)
|
||||
range2Regex := regexp.MustCompile(`((\d+)([ :,;-]))`)
|
||||
range3Regex := regexp.MustCompile(`(\+)?(\d+)`)
|
||||
|
||||
matches := rangeRegex.FindStringSubmatch(joinedArgs)
|
||||
|
||||
if matches != nil {
|
||||
//check if start was defined
|
||||
if matches[2] != "" {
|
||||
start, _ = strconv.Atoi(matches[2]) // Convert start line to integer
|
||||
} else {
|
||||
start = 1
|
||||
}
|
||||
if matches[4] == "+" { // Check if it's a relative length
|
||||
length, _ = strconv.Atoi(matches[5]) // Convert length to integer
|
||||
end = start + length - 1
|
||||
} else {
|
||||
end, _ = strconv.Atoi(matches[5]) // Convert end line to integer
|
||||
}
|
||||
// Remove the matched part from the arguments
|
||||
joinedArgs = strings.Replace(joinedArgs, matches[0], "", 1)
|
||||
found = true
|
||||
} else {
|
||||
matches = range2Regex.FindStringSubmatch(joinedArgs)
|
||||
if matches != nil {
|
||||
start, _ = strconv.Atoi(matches[2]) // Convert start line to integer
|
||||
end = -1
|
||||
// Remove the matched part from the arguments
|
||||
joinedArgs = strings.Replace(joinedArgs, matches[0], "", 1)
|
||||
found = true
|
||||
} else {
|
||||
matches = range3Regex.FindStringSubmatch(joinedArgs)
|
||||
if matches != nil {
|
||||
if matches[1] == "+" { // Check if it's a relative length
|
||||
length, _ := strconv.Atoi(matches[2]) // Convert length to integer
|
||||
start = 1
|
||||
end = start + length - 1
|
||||
} else { // Otherwise convert it to an absolute length
|
||||
start, _ = strconv.Atoi(matches[2]) // Convert start line to integer
|
||||
end = -1
|
||||
// Remove the matched part from the arguments
|
||||
}
|
||||
joinedArgs = strings.Replace(joinedArgs, matches[0], "", 1)
|
||||
found = true
|
||||
} else {
|
||||
found = false
|
||||
printUsage()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up and identify the filename, if present
|
||||
joinedArgs = strings.TrimSpace(joinedArgs)
|
||||
if joinedArgs != "" && !found {
|
||||
// If we didn't find numbers, interpret the remaining as filename
|
||||
filename = joinedArgs
|
||||
} else if joinedArgs != "" {
|
||||
// Otherwise, interpret any non-empty remaining part as filename
|
||||
filename = joinedArgs
|
||||
}
|
||||
|
||||
if !found {
|
||||
return 0, 0, "", fmt.Errorf("no valid range or line number found")
|
||||
}
|
||||
|
||||
return start, end, filename, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
args := flag.Args()
|
||||
|
||||
if len(args) < 1 {
|
||||
printUsage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
startIndex, endIndex, filename, err := parseArgs(args)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error parsing arguments: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Detemine the input source (file or stdin)
|
||||
inputSource := os.Stdin
|
||||
if filename != "" {
|
||||
inputSource, err = os.Open(filename)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to open file: %v\n", err)
|
||||
}
|
||||
defer inputSource.Close()
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(inputSource)
|
||||
//print all lines from line buner start to linenumber end unless linenumber end is -1
|
||||
for i := 1; scanner.Scan(); i++ {
|
||||
if startIndex <= i && (i <= endIndex || endIndex == -1) {
|
||||
fmt.Println(scanner.Text())
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
||||
3
projects/go-tools/go/goinfo/go.mod
Normal file
3
projects/go-tools/go/goinfo/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module git.ktf.ninja/tabledevil/goinfo
|
||||
|
||||
go 1.22.5
|
||||
52
projects/go-tools/go/goinfo/goinfo.go
Normal file
52
projects/go-tools/go/goinfo/goinfo.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"os/user"
|
||||
)
|
||||
|
||||
func getHostname() string {
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
log.Println("Could not retrieve Hostname")
|
||||
return ""
|
||||
} else {
|
||||
return hostname
|
||||
}
|
||||
}
|
||||
|
||||
func getUsernameDomain() string {
|
||||
user, err := user.Current()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return user.Username
|
||||
}
|
||||
|
||||
func getIP(hostname string) string {
|
||||
addrs, err := net.LookupIP(hostname)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return addrs[0].String()
|
||||
}
|
||||
|
||||
func getGroups() []int {
|
||||
groups, err := os.Getgroups()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return groups
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("hostname: ", getHostname())
|
||||
fmt.Println("username: ", getUsernameDomain())
|
||||
fmt.Println("groups: ", getGroups())
|
||||
fmt.Println("google: ", getIP("www.google.de"))
|
||||
|
||||
}
|
||||
BIN
projects/go-tools/go/goipgrep/ipgrep
Executable file
BIN
projects/go-tools/go/goipgrep/ipgrep
Executable file
Binary file not shown.
376
projects/go-tools/go/goipgrep/ipgrep.go
Normal file
376
projects/go-tools/go/goipgrep/ipgrep.go
Normal file
@@ -0,0 +1,376 @@
|
||||
// ipgrep.go
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// IPInfo holds the data we want from ipinfo.io
|
||||
type IPInfo struct {
|
||||
IP string `json:"ip"`
|
||||
Hostname string `json:"hostname"`
|
||||
City string `json:"city"`
|
||||
Region string `json:"region"`
|
||||
Country string `json:"country"`
|
||||
Org string `json:"org"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Command-line flags.
|
||||
var (
|
||||
sortFlag bool
|
||||
uniqFlag bool
|
||||
macFlag bool
|
||||
pingable bool
|
||||
resolveFlag bool
|
||||
lookupFlag bool
|
||||
fileName string
|
||||
)
|
||||
flag.BoolVar(&uniqFlag, "u", false, "only show uniq IPs/MACs (implies -s)")
|
||||
flag.BoolVar(&sortFlag, "s", false, "sort output")
|
||||
flag.BoolVar(&macFlag, "m", false, "grep MAC-IDs instead of IPs")
|
||||
flag.BoolVar(&pingable, "p", false, "only show 'pingable' entries (MACs still beta)")
|
||||
flag.BoolVar(&resolveFlag, "r", false, "resolve (uses host for ip and arping for mac)")
|
||||
flag.BoolVar(&lookupFlag, "l", false, "lookup ip info using ipinfo.io and output CSV: ip,country,region,city,org,hostname")
|
||||
flag.StringVar(&fileName, "f", "", "input file")
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintf(os.Stderr, "Usage: %s [-u] [-s] [-m] [-p] [-r] [-l] [-f filename] [file...]\n", os.Args[0])
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
flag.Parse()
|
||||
|
||||
// If pingable is set, force sorting and uniqueness.
|
||||
if pingable || lookupFlag {
|
||||
sortFlag = true
|
||||
uniqFlag = true
|
||||
}
|
||||
|
||||
if lookupFlag && macFlag {
|
||||
fmt.Fprintln(os.Stderr, "Lookup mode (-l) only works for IP addresses, not MAC addresses.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Regular expressions for IPs or MACs.
|
||||
var pattern string
|
||||
if macFlag {
|
||||
// Supports MAC formats: xx:xx:xx:xx:xx:xx or xxxx.xxxx.xxxx
|
||||
pattern = `(([a-fA-F0-9]{2}[:-]){5}[a-fA-F0-9]{2})|([a-fA-F0-9]{4}\.[a-fA-F0-9]{4}\.[a-fA-F0-9]{4})`
|
||||
} else {
|
||||
// Matches valid IPv4 addresses.
|
||||
pattern = `(((25[0-5])|(2[0-4][0-9])|([0-1]?\d?\d))\.){3}((25[0-5])|(2[0-4][0-9])|([0-1]?\d?\d))`
|
||||
}
|
||||
re, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error compiling regex: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Read input from -f file, extra args, or stdin.
|
||||
var inputData []byte
|
||||
if fileName != "" {
|
||||
inputData, err = ioutil.ReadFile(fileName)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error reading file %s: %v\n", fileName, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else if flag.NArg() > 0 {
|
||||
var buf bytes.Buffer
|
||||
for _, fname := range flag.Args() {
|
||||
data, err := ioutil.ReadFile(fname)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error reading file %s: %v\n", fname, err)
|
||||
continue
|
||||
}
|
||||
buf.Write(data)
|
||||
buf.WriteByte('\n')
|
||||
}
|
||||
inputData = buf.Bytes()
|
||||
} else {
|
||||
inputData, err = io.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error reading stdin: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Filter matches using the regex.
|
||||
matches := re.FindAllString(string(inputData), -1)
|
||||
if matches == nil {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if sortFlag {
|
||||
sort.Strings(matches)
|
||||
}
|
||||
if uniqFlag {
|
||||
matches = unique(matches)
|
||||
}
|
||||
|
||||
if pingable {
|
||||
matches = filterPingable(matches, macFlag)
|
||||
if sortFlag {
|
||||
sort.Strings(matches)
|
||||
}
|
||||
}
|
||||
|
||||
// If lookup flag is set, perform ipinfo.io lookups with caching.
|
||||
if lookupFlag {
|
||||
cache := loadCache()
|
||||
var cacheMu sync.Mutex
|
||||
results := lookupIPInfo(matches, cache, &cacheMu)
|
||||
|
||||
// Sort the results by IP.
|
||||
sort.Slice(results, func(i, j int) bool {
|
||||
return results[i].IP < results[j].IP
|
||||
})
|
||||
|
||||
// Save the updated cache.
|
||||
saveCache(cache)
|
||||
|
||||
// Output CSV using csv.Writer for proper CSV formatting.
|
||||
w := csv.NewWriter(os.Stdout)
|
||||
// Write header.
|
||||
if err := w.Write([]string{"ip", "country", "region", "city", "org", "hostname"}); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error writing CSV header: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
for _, info := range results {
|
||||
record := []string{
|
||||
info.IP,
|
||||
info.Country,
|
||||
info.Region,
|
||||
info.City,
|
||||
info.Org,
|
||||
info.Hostname,
|
||||
}
|
||||
if err := w.Write(record); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error writing CSV record: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
w.Flush()
|
||||
if err := w.Error(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error flushing CSV data: %v\n", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// If resolve flag is set, perform resolution.
|
||||
if resolveFlag {
|
||||
results := resolveEntries(matches, macFlag)
|
||||
for _, r := range results {
|
||||
fmt.Print(r)
|
||||
if !macFlag {
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, just output the matches.
|
||||
for _, m := range matches {
|
||||
fmt.Println(m)
|
||||
}
|
||||
}
|
||||
|
||||
// unique removes duplicate strings from a slice.
|
||||
func unique(input []string) []string {
|
||||
seen := make(map[string]struct{})
|
||||
var result []string
|
||||
for _, s := range input {
|
||||
if _, ok := seen[s]; !ok {
|
||||
seen[s] = struct{}{}
|
||||
result = append(result, s)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// filterPingable runs ping (or arping) concurrently on each entry.
|
||||
func filterPingable(entries []string, mac bool) []string {
|
||||
var wg sync.WaitGroup
|
||||
var mu sync.Mutex
|
||||
var result []string
|
||||
|
||||
for _, entry := range entries {
|
||||
wg.Add(1)
|
||||
go func(e string) {
|
||||
defer wg.Done()
|
||||
if isPingable(e, mac) {
|
||||
mu.Lock()
|
||||
result = append(result, e)
|
||||
mu.Unlock()
|
||||
}
|
||||
}(entry)
|
||||
}
|
||||
wg.Wait()
|
||||
return result
|
||||
}
|
||||
|
||||
// isPingable tests if an entry is reachable using ping (or arping for MACs).
|
||||
func isPingable(entry string, mac bool) bool {
|
||||
var cmd *exec.Cmd
|
||||
if mac {
|
||||
cmd = exec.Command("arping", "-c", "1", "-w", "5000000", entry)
|
||||
} else {
|
||||
cmd = exec.Command("ping", "-c", "1", "-w", "1", entry)
|
||||
}
|
||||
cmd.Stdout = nil
|
||||
cmd.Stderr = nil
|
||||
err := cmd.Run()
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// resolveEntries performs resolution via external commands.
|
||||
func resolveEntries(entries []string, mac bool) []string {
|
||||
var wg sync.WaitGroup
|
||||
results := make([]string, len(entries))
|
||||
|
||||
for i, entry := range entries {
|
||||
wg.Add(1)
|
||||
go func(i int, e string) {
|
||||
defer wg.Done()
|
||||
if mac {
|
||||
cmd := exec.Command("arping", "-q", "-c", "1", "-w", "5000000", e)
|
||||
if err := cmd.Run(); err == nil {
|
||||
cmd2 := exec.Command("arping", "-c", "1", e)
|
||||
out, err := cmd2.CombinedOutput()
|
||||
if err == nil {
|
||||
results[i] = string(out)
|
||||
} else {
|
||||
results[i] = e + "\n"
|
||||
}
|
||||
} else {
|
||||
results[i] = e + "\n"
|
||||
}
|
||||
} else {
|
||||
cmd := exec.Command("host", e)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
// Extract the hostname via regex (similar to grep -Po '(?<=pointer ).*')
|
||||
reHost := regexp.MustCompile(`(?i)(?<=pointer\s)(\S+)`)
|
||||
match := reHost.FindString(string(out))
|
||||
if match != "" {
|
||||
results[i] = fmt.Sprintf("%s %s", e, match)
|
||||
} else {
|
||||
results[i] = e
|
||||
}
|
||||
} else {
|
||||
results[i] = e
|
||||
}
|
||||
}
|
||||
}(i, entry)
|
||||
}
|
||||
wg.Wait()
|
||||
return results
|
||||
}
|
||||
|
||||
// lookupIPInfo queries ipinfo.io for each IP concurrently,
|
||||
// checking a local cache before going to the network.
|
||||
// It returns a slice of IPInfo.
|
||||
func lookupIPInfo(entries []string, cache map[string]IPInfo, cacheMu *sync.Mutex) []IPInfo {
|
||||
var wg sync.WaitGroup
|
||||
var mu sync.Mutex
|
||||
var results []IPInfo
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: 5 * time.Second,
|
||||
}
|
||||
|
||||
for _, ip := range entries {
|
||||
wg.Add(1)
|
||||
go func(ip string) {
|
||||
defer wg.Done()
|
||||
// Check cache first.
|
||||
cacheMu.Lock()
|
||||
info, found := cache[ip]
|
||||
cacheMu.Unlock()
|
||||
if found {
|
||||
mu.Lock()
|
||||
results = append(results, info)
|
||||
mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// Not in cache; perform HTTP lookup.
|
||||
url := fmt.Sprintf("https://ipinfo.io/%s", ip)
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var newInfo IPInfo
|
||||
if err := json.Unmarshal(body, &newInfo); err != nil {
|
||||
return
|
||||
}
|
||||
// Only add valid responses.
|
||||
if newInfo.IP == "" {
|
||||
return
|
||||
}
|
||||
// Update cache.
|
||||
cacheMu.Lock()
|
||||
cache[ip] = newInfo
|
||||
cacheMu.Unlock()
|
||||
mu.Lock()
|
||||
results = append(results, newInfo)
|
||||
mu.Unlock()
|
||||
}(ip)
|
||||
}
|
||||
wg.Wait()
|
||||
return results
|
||||
}
|
||||
|
||||
// loadCache reads the cache from ~/.ipgrep.db (if present)
|
||||
// and returns it as a map[string]IPInfo.
|
||||
func loadCache() map[string]IPInfo {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return make(map[string]IPInfo)
|
||||
}
|
||||
cachePath := home + "/.ipgrep.db"
|
||||
data, err := ioutil.ReadFile(cachePath)
|
||||
if err != nil {
|
||||
// File doesn't exist or can't be read, start with an empty cache.
|
||||
return make(map[string]IPInfo)
|
||||
}
|
||||
var cache map[string]IPInfo
|
||||
if err := json.Unmarshal(data, &cache); err != nil {
|
||||
// If unmarshal fails, use an empty cache.
|
||||
return make(map[string]IPInfo)
|
||||
}
|
||||
return cache
|
||||
}
|
||||
|
||||
// saveCache writes the cache map to ~/.ipgrep.db.
|
||||
func saveCache(cache map[string]IPInfo) {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cachePath := home + "/.ipgrep.db"
|
||||
data, err := json.MarshalIndent(cache, "", " ")
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error marshaling cache: %v\n", err)
|
||||
return
|
||||
}
|
||||
if err := ioutil.WriteFile(cachePath, data, 0644); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error writing cache file: %v\n", err)
|
||||
}
|
||||
}
|
||||
BIN
projects/go-tools/go/gosoft/gosoft.exe
Executable file
BIN
projects/go-tools/go/gosoft/gosoft.exe
Executable file
Binary file not shown.
502
projects/go-tools/go/gosoft/gosoft.go
Normal file
502
projects/go-tools/go/gosoft/gosoft.go
Normal file
@@ -0,0 +1,502 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Software holds information about installed software
|
||||
type Software struct {
|
||||
Source string `json:"source"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
InstallDate string `json:"install_date"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
var softwareList []Software
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
softwareList = append(softwareList, enumerateWindows()...)
|
||||
} else if runtime.GOOS == "linux" {
|
||||
softwareList = append(softwareList, enumerateLinux()...)
|
||||
}
|
||||
|
||||
output, err := json.MarshalIndent(softwareList, "", " ")
|
||||
if err != nil {
|
||||
log.Println("Error marshalling software list:", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(output))
|
||||
}
|
||||
|
||||
// Add to the enumerateWindows function
|
||||
func enumerateWindows() []Software {
|
||||
var softwareList []Software
|
||||
|
||||
// Winget
|
||||
softwareList = append(softwareList, enumerateWinget()...)
|
||||
|
||||
// Chocolatey
|
||||
softwareList = append(softwareList, enumerateChocolatey()...)
|
||||
|
||||
// Scoop
|
||||
softwareList = append(softwareList, enumerateScoop()...)
|
||||
|
||||
// Common Windows Installations
|
||||
softwareList = append(softwareList, enumerateCommonWindows()...)
|
||||
|
||||
// NuGet
|
||||
softwareList = append(softwareList, enumerateNuGet()...)
|
||||
|
||||
// Microsoft Store
|
||||
softwareList = append(softwareList, enumerateMicrosoftStore()...)
|
||||
|
||||
return softwareList
|
||||
}
|
||||
|
||||
// Add to the enumerateLinux function
|
||||
func enumerateLinux() []Software {
|
||||
var softwareList []Software
|
||||
|
||||
// APT
|
||||
softwareList = append(softwareList, enumerateApt()...)
|
||||
|
||||
// Snap
|
||||
softwareList = append(softwareList, enumerateSnap()...)
|
||||
|
||||
// Pip
|
||||
softwareList = append(softwareList, enumeratePip()...)
|
||||
|
||||
// NPM
|
||||
softwareList = append(softwareList, enumerateNpm()...)
|
||||
|
||||
// Flatpak
|
||||
softwareList = append(softwareList, enumerateFlatpak()...)
|
||||
|
||||
// RPM
|
||||
softwareList = append(softwareList, enumerateRpm()...)
|
||||
|
||||
// Pacman
|
||||
softwareList = append(softwareList, enumeratePacman()...)
|
||||
|
||||
// Homebrew
|
||||
softwareList = append(softwareList, enumerateHomebrew()...)
|
||||
|
||||
// Conda
|
||||
softwareList = append(softwareList, enumerateConda()...)
|
||||
|
||||
return softwareList
|
||||
}
|
||||
|
||||
func enumerateNuGet() []Software {
|
||||
var softwareList []Software
|
||||
|
||||
output, err := runCommand("nuget", "list", "-AllVersions")
|
||||
if err != nil {
|
||||
log.Println("Error enumerating NuGet packages:", err)
|
||||
return softwareList
|
||||
}
|
||||
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
softwareList = append(softwareList, Software{
|
||||
Source: "nuget",
|
||||
Name: parts[0],
|
||||
Version: parts[1],
|
||||
})
|
||||
}
|
||||
|
||||
return softwareList
|
||||
}
|
||||
|
||||
func enumerateMicrosoftStore() []Software {
|
||||
var softwareList []Software
|
||||
|
||||
output, err := runCommand("powershell", "Get-AppxPackage", "|", "Select-Object", "Name,PackageFullName,InstallDate")
|
||||
if err != nil {
|
||||
log.Println("Error enumerating Microsoft Store packages:", err)
|
||||
return softwareList
|
||||
}
|
||||
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 3 {
|
||||
continue
|
||||
}
|
||||
softwareList = append(softwareList, Software{
|
||||
Source: "microsoft store",
|
||||
Name: parts[0],
|
||||
Version: parts[1],
|
||||
InstallDate: parseInstallDate(parts[2]),
|
||||
})
|
||||
}
|
||||
|
||||
return softwareList
|
||||
}
|
||||
|
||||
func enumerateFlatpak() []Software {
|
||||
var softwareList []Software
|
||||
|
||||
output, err := runCommand("flatpak", "list")
|
||||
if err != nil {
|
||||
log.Println("Error enumerating Flatpak packages:", err)
|
||||
return softwareList
|
||||
}
|
||||
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
softwareList = append(softwareList, Software{
|
||||
Source: "flatpak",
|
||||
Name: parts[0],
|
||||
Version: parts[1],
|
||||
})
|
||||
}
|
||||
|
||||
return softwareList
|
||||
}
|
||||
|
||||
func enumerateRpm() []Software {
|
||||
var softwareList []Software
|
||||
|
||||
output, err := runCommand("rpm", "-qa", "--queryformat", "%{NAME} %{VERSION}\n")
|
||||
if err != nil {
|
||||
log.Println("Error enumerating RPM packages:", err)
|
||||
return softwareList
|
||||
}
|
||||
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
softwareList = append(softwareList, Software{
|
||||
Source: "rpm",
|
||||
Name: parts[0],
|
||||
Version: parts[1],
|
||||
})
|
||||
}
|
||||
|
||||
return softwareList
|
||||
}
|
||||
|
||||
func enumeratePacman() []Software {
|
||||
var softwareList []Software
|
||||
|
||||
output, err := runCommand("pacman", "-Q")
|
||||
if err != nil {
|
||||
log.Println("Error enumerating Pacman packages:", err)
|
||||
return softwareList
|
||||
}
|
||||
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
softwareList = append(softwareList, Software{
|
||||
Source: "pacman",
|
||||
Name: parts[0],
|
||||
Version: parts[1],
|
||||
})
|
||||
}
|
||||
|
||||
return softwareList
|
||||
}
|
||||
|
||||
func enumerateHomebrew() []Software {
|
||||
var softwareList []Software
|
||||
|
||||
output, err := runCommand("brew", "list", "--versions")
|
||||
if err != nil {
|
||||
log.Println("Error enumerating Homebrew packages:", err)
|
||||
return softwareList
|
||||
}
|
||||
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
softwareList = append(softwareList, Software{
|
||||
Source: "homebrew",
|
||||
Name: parts[0],
|
||||
Version: parts[1],
|
||||
})
|
||||
}
|
||||
|
||||
return softwareList
|
||||
}
|
||||
|
||||
func enumerateConda() []Software {
|
||||
var softwareList []Software
|
||||
|
||||
output, err := runCommand("conda", "list", "--json")
|
||||
if err != nil {
|
||||
log.Println("Error enumerating Conda packages:", err)
|
||||
return softwareList
|
||||
}
|
||||
|
||||
var condaPackages []map[string]interface{}
|
||||
err = json.Unmarshal([]byte(output), &condaPackages)
|
||||
if err != nil {
|
||||
log.Println("Error parsing Conda JSON output:", err)
|
||||
return softwareList
|
||||
}
|
||||
|
||||
for _, pkg := range condaPackages {
|
||||
softwareList = append(softwareList, Software{
|
||||
Source: "conda",
|
||||
Name: pkg["name"].(string),
|
||||
Version: pkg["version"].(string),
|
||||
})
|
||||
}
|
||||
|
||||
return softwareList
|
||||
}
|
||||
|
||||
func runCommand(cmd string, args ...string) (string, error) {
|
||||
out, err := exec.Command(cmd, args...).Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(out), nil
|
||||
}
|
||||
|
||||
func parseInstallDate(dateString string) string {
|
||||
layout := "2006-01-02"
|
||||
date, err := time.Parse(layout, dateString)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return date.Format(layout)
|
||||
}
|
||||
|
||||
func enumerateWinget() []Software {
|
||||
var softwareList []Software
|
||||
|
||||
output, err := runCommand("winget", "list", "--source", "winget")
|
||||
if err != nil {
|
||||
log.Println("Error enumerating Winget packages:", err)
|
||||
return softwareList
|
||||
}
|
||||
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
parts := regexp.MustCompile(`\s+`).Split(line, -1)
|
||||
if len(parts) < 4 {
|
||||
continue
|
||||
}
|
||||
softwareList = append(softwareList, Software{
|
||||
Source: "winget",
|
||||
Name: parts[0],
|
||||
Version: parts[1],
|
||||
})
|
||||
}
|
||||
|
||||
return softwareList
|
||||
}
|
||||
|
||||
func enumerateChocolatey() []Software {
|
||||
var softwareList []Software
|
||||
|
||||
output, err := runCommand("choco", "list", "--local-only")
|
||||
if err != nil {
|
||||
log.Println("Error enumerating Chocolatey packages:", err)
|
||||
return softwareList
|
||||
}
|
||||
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
parts := strings.Split(line, "|")
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
softwareList = append(softwareList, Software{
|
||||
Source: "chocolatey",
|
||||
Name: parts[0],
|
||||
Version: parts[1],
|
||||
})
|
||||
}
|
||||
|
||||
return softwareList
|
||||
}
|
||||
|
||||
func enumerateScoop() []Software {
|
||||
var softwareList []Software
|
||||
|
||||
output, err := runCommand("scoop", "list")
|
||||
if err != nil {
|
||||
log.Println("Error enumerating Scoop packages:", err)
|
||||
return softwareList
|
||||
}
|
||||
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, "Installed apps") {
|
||||
continue
|
||||
}
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
softwareList = append(softwareList, Software{
|
||||
Source: "scoop",
|
||||
Name: parts[0],
|
||||
Version: parts[1],
|
||||
})
|
||||
}
|
||||
|
||||
return softwareList
|
||||
}
|
||||
|
||||
func enumerateCommonWindows() []Software {
|
||||
var softwareList []Software
|
||||
|
||||
output, err := runCommand("powershell", "Get-WmiObject", "-Class", "Win32_Product", "|", "Select-Object", "Name,Version,InstallDate")
|
||||
if err != nil {
|
||||
log.Println("Error enumerating common Windows installations:", err)
|
||||
return softwareList
|
||||
}
|
||||
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 3 {
|
||||
continue
|
||||
}
|
||||
softwareList = append(softwareList, Software{
|
||||
Source: "common windows installation",
|
||||
Name: parts[0],
|
||||
Version: parts[1],
|
||||
InstallDate: parseInstallDate(parts[2]),
|
||||
})
|
||||
}
|
||||
|
||||
return softwareList
|
||||
}
|
||||
|
||||
func enumerateApt() []Software {
|
||||
var softwareList []Software
|
||||
|
||||
output, err := runCommand("dpkg-query", "-W", "-f=${binary:Package} ${Version} ${Installed-Size}\n")
|
||||
if err != nil {
|
||||
log.Println("Error enumerating APT packages:", err)
|
||||
return softwareList
|
||||
}
|
||||
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
softwareList = append(softwareList, Software{
|
||||
Source: "apt",
|
||||
Name: parts[0],
|
||||
Version: parts[1],
|
||||
})
|
||||
}
|
||||
|
||||
return softwareList
|
||||
}
|
||||
|
||||
func enumerateSnap() []Software {
|
||||
var softwareList []Software
|
||||
|
||||
output, err := runCommand("snap", "list")
|
||||
if err != nil {
|
||||
log.Println("Error enumerating Snap packages:", err)
|
||||
return softwareList
|
||||
}
|
||||
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 3 {
|
||||
continue
|
||||
}
|
||||
softwareList = append(softwareList, Software{
|
||||
Source: "snap",
|
||||
Name: parts[0],
|
||||
Version: parts[1],
|
||||
})
|
||||
}
|
||||
|
||||
return softwareList
|
||||
}
|
||||
|
||||
func enumeratePip() []Software {
|
||||
var softwareList []Software
|
||||
|
||||
output, err := runCommand("pip", "list", "--format=json")
|
||||
if err != nil {
|
||||
log.Println("Error enumerating Pip packages:", err)
|
||||
return softwareList
|
||||
}
|
||||
|
||||
var pipPackages []map[string]string
|
||||
err = json.Unmarshal([]byte(output), &pipPackages)
|
||||
if err != nil {
|
||||
log.Println("Error parsing Pip JSON output:", err)
|
||||
return softwareList
|
||||
}
|
||||
|
||||
for _, pkg := range pipPackages {
|
||||
softwareList = append(softwareList, Software{
|
||||
Source: "pip",
|
||||
Name: pkg["name"],
|
||||
Version: pkg["version"],
|
||||
})
|
||||
}
|
||||
|
||||
return softwareList
|
||||
}
|
||||
|
||||
func enumerateNpm() []Software {
|
||||
var softwareList []Software
|
||||
|
||||
output, err := runCommand("npm", "list", "-g", "--depth=0", "--json")
|
||||
if err != nil {
|
||||
log.Println("Error enumerating NPM packages:", err)
|
||||
return softwareList
|
||||
}
|
||||
|
||||
var npmPackages map[string]interface{}
|
||||
err = json.Unmarshal([]byte(output), &npmPackages)
|
||||
if err != nil {
|
||||
log.Println("Error parsing NPM JSON output:", err)
|
||||
return softwareList
|
||||
}
|
||||
|
||||
dependencies := npmPackages["dependencies"].(map[string]interface{})
|
||||
for name, info := range dependencies {
|
||||
infoMap := info.(map[string]interface{})
|
||||
version := infoMap["version"].(string)
|
||||
softwareList = append(softwareList, Software{
|
||||
Source: "npm",
|
||||
Name: name,
|
||||
Version: version,
|
||||
})
|
||||
}
|
||||
|
||||
return softwareList
|
||||
}
|
||||
75
projects/go-tools/go/gouniq/gouniq.go
Normal file
75
projects/go-tools/go/gouniq/gouniq.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func hashLine(s string) uint32 {
|
||||
hasher := fnv.New32a()
|
||||
hasher.Write([]byte(s))
|
||||
return hasher.Sum32()
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Define command line flags
|
||||
reverse := flag.Bool("d", false, "Print only lines that appear more than once.")
|
||||
help := flag.Bool("h", false, "Display help and usage information.")
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintf(flag.CommandLine.Output(), "Usage of %s:\n", os.Args[0])
|
||||
fmt.Println("This program reads from a file or standard input, deduplicates lines, and outputs the results.")
|
||||
fmt.Println("Options:")
|
||||
flag.PrintDefaults()
|
||||
fmt.Println("Example usage:")
|
||||
fmt.Println("\t", os.Args[0], "[options] [filename]")
|
||||
fmt.Println("\t", os.Args[0], "-d filename # Only print duplicates")
|
||||
fmt.Println("\t", "cat /some/text/file |", os.Args[0], "# Read from standard input")
|
||||
}
|
||||
flag.Parse()
|
||||
|
||||
// Check for help flag
|
||||
if *help {
|
||||
flag.Usage()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// Detemine the input source (file or stdin)
|
||||
inputSource := os.Stdin
|
||||
var err error
|
||||
if flag.NArg() > 0 {
|
||||
inputSource, err = os.Open(flag.Args()[0])
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to open file: %v\n", err)
|
||||
}
|
||||
defer inputSource.Close()
|
||||
}
|
||||
seenLines := make(map[uint32]int)
|
||||
scanner := bufio.NewScanner(inputSource)
|
||||
|
||||
//Readin lines
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
hash := hashLine(line)
|
||||
seenLines[hash]++
|
||||
|
||||
if *reverse {
|
||||
// Print only lines that appear more than once
|
||||
if seenLines[hash] > 1 {
|
||||
fmt.Println(line)
|
||||
}
|
||||
} else {
|
||||
// Normal mode, print only unique lines
|
||||
if seenLines[hash] == 1 {
|
||||
fmt.Println(line)
|
||||
}
|
||||
}
|
||||
}
|
||||
//Check for errors during scanning
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.Fatalf("Failed to read input: %v\n", err)
|
||||
}
|
||||
}
|
||||
25
projects/puzzlebox/solution
Normal file
25
projects/puzzlebox/solution
Normal file
@@ -0,0 +1,25 @@
|
||||
[[[1, 1, 1, 1, 22],
|
||||
[6, 6, 6, 6, 22],
|
||||
[2, 6, 9, 22, 22],
|
||||
[9, 9, 9, 9, 22],
|
||||
[10, 15, 15, 15, 15]],
|
||||
[[2, 11, 1, 19, 20],
|
||||
[2, 11, 13, 19, 21],
|
||||
[2, 11, 11, 19, 23],
|
||||
[2, 11, 17, 19, 24],
|
||||
[10, 14, 18, 15, 25]],
|
||||
[[3, 3, 3, 3, 20],
|
||||
[4, 13, 13, 19, 21],
|
||||
[8, 8, 8, 8, 23],
|
||||
[10, 14, 17, 17, 24],
|
||||
[10, 14, 18, 18, 25]],
|
||||
[[4, 12, 3, 20, 20],
|
||||
[4, 12, 13, 21, 21],
|
||||
[4, 12, 8, 23, 23],
|
||||
[4, 12, 17, 24, 24],
|
||||
[10, 14, 18, 25, 25]],
|
||||
[[5, 5, 5, 5, 20],
|
||||
[7, 5, 13, 16, 21],
|
||||
[7, 12, 16, 16, 23],
|
||||
[7, 7, 17, 16, 24],
|
||||
[7, 14, 18, 16, 25]]]
|
||||
129
projects/puzzlebox/solve.py
Normal file
129
projects/puzzlebox/solve.py
Normal file
@@ -0,0 +1,129 @@
|
||||
import pprint
|
||||
import operator
|
||||
import numpy as np
|
||||
import math
|
||||
from copy import copy, deepcopy
|
||||
|
||||
piece=[[0,0,0],[0,1,0],[0,2,0],[0,3,0],[1,2,0]]
|
||||
sizeofcube=5
|
||||
|
||||
def init_cube(size=sizeofcube):
|
||||
return [[[0 for x in range(0,size)] for y in range(0,size)] for z in range(0,size)]
|
||||
|
||||
def move_start_position(piece,index):
|
||||
return [np.subtract(x, piece[index]) for x in piece]
|
||||
|
||||
def draw_cube(cube):
|
||||
from mpl_toolkits.mplot3d import Axes3D
|
||||
import matplotlib.pyplot as plt
|
||||
fig = plt.figure()
|
||||
ax = fig.gca(projection='3d')
|
||||
ax.set_aspect('equal')
|
||||
ax.set_xlabel('x', fontsize=10)
|
||||
ax.set_ylabel('y', fontsize=10)
|
||||
ax.set_zlabel('z', fontsize=10)
|
||||
|
||||
ma=np.array(cube)
|
||||
ax.voxels(ma, edgecolor="k")
|
||||
plt.show()
|
||||
|
||||
def put_piece_in_cube(piece,cube,position,index):
|
||||
cursors = [np.add(position,p) for p in piece]
|
||||
in_cube = [ max(c) < len(cube) and min(c) >= 0 for c in cursors]
|
||||
if all(in_cube):
|
||||
for cursor in cursors:
|
||||
try:
|
||||
if cube[cursor[0]][cursor[1]][cursor[2]]!=0:
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
for cursor in cursors:
|
||||
cube[cursor[0]][cursor[1]][cursor[2]]=index
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def rotate_vector(vector,axis,angle):
|
||||
x,y,z=vector
|
||||
angle=math.radians(angle)
|
||||
if axis == "z":
|
||||
return (int(round((x*math.cos(angle)) - (y*math.sin(angle)))),int(round((x*math.sin(angle)) + (y*math.cos(angle)))),z)
|
||||
if axis == "y":
|
||||
return (int(round(x*math.cos(angle) + z*math.sin(angle))),y,int(round(-x*math.sin(angle) + z*math.cos(angle))))
|
||||
if axis == "x":
|
||||
return (x,int(round(y*math.cos(angle) - z*math.sin(angle))),int(round(y*math.sin(angle) + z*math.cos(angle))))
|
||||
|
||||
def rotate_piece(piece,axis,angle):
|
||||
return [rotate_vector(x, axis, angle) for x in piece]
|
||||
|
||||
def shift_piece(piece,anchor_index):
|
||||
anchor=piece[anchor_index]
|
||||
return [np.subtract(p,anchor) for p in piece]
|
||||
|
||||
def generate_rotations(piece):
|
||||
all_rotations=set()
|
||||
for i in range(0,4):
|
||||
for j in range(0,4):
|
||||
for k in range(0,4):
|
||||
for p in range(0,5):
|
||||
rotated_piece=rotate_piece(rotate_piece(rotate_piece(shift_piece(piece,p),"x",k*90),"y",j*90),"z",i*90)
|
||||
all_rotations.add(tuple(rotated_piece))
|
||||
return frozenset(all_rotations)
|
||||
|
||||
def find_empty_spot(cube):
|
||||
for z in range(0,sizeofcube):
|
||||
for y in range(0,sizeofcube):
|
||||
for x in range(0,sizeofcube):
|
||||
if cube[x][y][z]==0:
|
||||
return (x,y,z)
|
||||
return None
|
||||
|
||||
def solve(cube,index):
|
||||
#make copy of cube
|
||||
global maxindex
|
||||
if index > maxindex:
|
||||
print(index)
|
||||
maxindex=index
|
||||
|
||||
backup=deepcopy(cube)
|
||||
# draw_cube(backup)
|
||||
#make copy of available pieces
|
||||
global all_rotations
|
||||
pieces=set(all_rotations.copy())
|
||||
|
||||
# print("{}:find empty spot#########################".format(index))
|
||||
empty_pos=find_empty_spot(backup)
|
||||
|
||||
if empty_pos==None:
|
||||
pprint.pprint(cube)
|
||||
draw_cube(cube)
|
||||
return True
|
||||
else:
|
||||
(x,y,z)=empty_pos
|
||||
# print("{}:empty_spot at ({},{},{})".format(index,x,y,z))
|
||||
#found empty space > trying to fill it
|
||||
while len(pieces)>0:
|
||||
#use copy of cube without my parts
|
||||
local_cube=deepcopy(backup)
|
||||
piece=pieces.pop()
|
||||
if put_piece_in_cube(piece, local_cube, (x,y,z), index):
|
||||
# print("{}:found fitting piece {} ({} left)".format(index,piece,len(pieces)))
|
||||
if solve(local_cube, index+1):
|
||||
return True
|
||||
else:
|
||||
# print("{}:removing ({},{},{}):{}".format(index,x,y,z,len(pieces)))
|
||||
pass
|
||||
#nothing fits return fail
|
||||
return False
|
||||
|
||||
|
||||
maxindex=0
|
||||
|
||||
|
||||
def main():
|
||||
global all_rotations
|
||||
all_rotations=generate_rotations(piece)
|
||||
solve(init_cube(),1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
85
projects/puzzlebox/solve0.py
Normal file
85
projects/puzzlebox/solve0.py
Normal file
@@ -0,0 +1,85 @@
|
||||
import numpy as np
|
||||
import math
|
||||
from operator import add
|
||||
import matplotlib.pyplot as plt
|
||||
import pprint
|
||||
from mpl_toolkits.mplot3d import Axes3D
|
||||
|
||||
# g_cube=np.zeros((10,10,10))
|
||||
n=6
|
||||
g_cube=[[[0 for k in range(0,n)] for j in range(0,n)] for i in range(0,n)]
|
||||
|
||||
form=[[0,0,0],[1,0,0],[2,0,0],[3,0,0],[2,1,0]]
|
||||
|
||||
|
||||
|
||||
def set_origin(form,index):
|
||||
newform=list()
|
||||
for x in form:
|
||||
newform.append(np.subtract(x,form[index]))
|
||||
return newform
|
||||
|
||||
def vector_rotate(vector,angle,axis):
|
||||
if axis=='x':
|
||||
result=[vector[0],( ( vector[1]*math.cos(angle) ) - ( vector[2]*math.sin(angle) ) ),( ( vector[1]*math.sin(angle) ) + ( vector[2]*math.cos(angle) ) )]
|
||||
if axis=='y':
|
||||
result=[( ( vector[0]*math.cos(angle) ) + ( vector[2]*math.sin(angle) ) ),vector[1],( ( -vector[0]*math.sin(angle) ) + ( vector[2]*math.cos(angle) ) )]
|
||||
if axis=='z':
|
||||
result=[( ( vector[0]*math.cos(angle) ) - ( vector[1]*math.sin(angle) ) ),( ( vector[0]*math.sin(angle) ) + ( vector[1]*math.cos(angle) ) )]
|
||||
|
||||
|
||||
def form_in_cube(form):
|
||||
for cursor in form:
|
||||
for element in cursor:
|
||||
if element<=0 or element>=n:
|
||||
return False
|
||||
return True
|
||||
|
||||
def put_in(form,cube,offset,piece=1):
|
||||
form_positions=[(x+offset[0],y+offset[1],z+offset[2]) for (x,y,z) in form]
|
||||
# form_positions=list([map(add,p,offset) for p in form])
|
||||
|
||||
if form_in_cube(form_positions):
|
||||
for cursor in form_positions:
|
||||
cube[cursor[0]][cursor[1]][cursor[2]]=piece
|
||||
print("set ({},{},{}) to {}".format(cursor[0],cursor[1],cursor[2],piece))
|
||||
else:
|
||||
print("out")
|
||||
|
||||
def draw_field(g_cube):
|
||||
# g_cube=np.zeros((6,6,6))
|
||||
# g_cube=cube
|
||||
# prepare some coordinates
|
||||
# x, y, z = np.indices((6, 6, 6))
|
||||
x, y, z = np.indices((len(g_cube),len(g_cube[0]), len(g_cube[0][0])))
|
||||
farben=["red","blue","green","cyan","magenta","yellow"]
|
||||
|
||||
list_of_cubes =list()
|
||||
for x_pos in range(0,len(g_cube)):
|
||||
for y_pos in range(0,len(g_cube[x_pos])):
|
||||
for z_pos in range(0,len(g_cube[x_pos][y_pos])):
|
||||
color=(g_cube[x_pos][y_pos][z_pos])
|
||||
if color>0:
|
||||
print("Voxel by ({},{},{}) : {}".format(x_pos,y_pos,z_pos,type(g_cube[x_pos][y_pos][z_pos])))
|
||||
farbe=farben[int((color+1)%len(farben))]
|
||||
list_of_cubes.append({"cube":(x < x_pos) & (x >= (x_pos-1) ) & (y < y_pos) & (y >= (y_pos-1) ) & (z < z_pos) & (z >= (z_pos-1) ),"farbe":farbe})
|
||||
|
||||
|
||||
voxels=list_of_cubes[0]["cube"]
|
||||
colors = np.empty(voxels.shape, dtype=object)
|
||||
|
||||
for x in list_of_cubes:
|
||||
voxels=voxels | x["cube"]
|
||||
colors[x["cube"]]=x["farbe"]
|
||||
|
||||
fig = plt.figure()
|
||||
ax = fig.gca(projection='3d')
|
||||
ax.voxels(voxels, facecolors=colors, edgecolor='k')
|
||||
plt.show()
|
||||
|
||||
|
||||
put_in(set_origin(form,3),g_cube,(1,2,1),1)
|
||||
put_in(set_origin(form,4),g_cube,(2,2,2),2)
|
||||
put_in(set_origin(form,3),g_cube,(3,2,3),1)
|
||||
put_in(set_origin(form,4),g_cube,(4,2,4),2)
|
||||
draw_field(g_cube)
|
||||
175
projects/puzzlebox/solve2.py
Normal file
175
projects/puzzlebox/solve2.py
Normal file
@@ -0,0 +1,175 @@
|
||||
import pprint
|
||||
import operator
|
||||
import numpy as np
|
||||
import math
|
||||
from copy import copy, deepcopy
|
||||
import profile
|
||||
|
||||
piece=[[0,0,0],[0,1,0],[0,2,0],[0,3,0],[1,2,0]]
|
||||
sizeofcube=5
|
||||
|
||||
def init_cube(size=sizeofcube):
|
||||
return [[[0 for x in range(0,size)] for y in range(0,size)] for z in range(0,size)]
|
||||
|
||||
def move_start_position(piece,index):
|
||||
return [np.subtract(x, piece[index]) for x in piece]
|
||||
|
||||
def draw_cube(cube):
|
||||
from mpl_toolkits.mplot3d import Axes3D
|
||||
import matplotlib.pyplot as plt
|
||||
fig = plt.figure()
|
||||
ax = fig.gca(projection='3d')
|
||||
ax.set_aspect('equal')
|
||||
ax.set_xlabel('x', fontsize=10)
|
||||
ax.set_ylabel('y', fontsize=10)
|
||||
ax.set_zlabel('z', fontsize=10)
|
||||
|
||||
ma=np.array(cube)
|
||||
ax.voxels(ma, edgecolor="k")
|
||||
plt.show()
|
||||
|
||||
def set_cube_vals(cursors,cube,value):
|
||||
for cursor in cursors:
|
||||
cube[cursor[0]][cursor[1]][cursor[2]]=value
|
||||
|
||||
def is_valid(piece,position):
|
||||
global sizeofcube
|
||||
upper_x=sizeofcube-position[0]
|
||||
upper_y=sizeofcube-position[1]
|
||||
upper_z=sizeofcube-position[2]
|
||||
for (x,y,z) in piece:
|
||||
if x<-position[0] or x>upper_x:
|
||||
return False
|
||||
if y<-position[1] or y>upper_y:
|
||||
return False
|
||||
if z<-position[2] or z>upper_z:
|
||||
return False
|
||||
return True
|
||||
|
||||
def put_piece_in_cube(piece,cube,position,index):
|
||||
if is_valid(piece,position):
|
||||
# cursors = [np.add(position,p) for p in piece]
|
||||
# for cursor in cursors:
|
||||
cursors=[]
|
||||
for (x,y,z) in piece:
|
||||
cursor=[(x+position[0]),(y+position[1]),(z+position[2])]
|
||||
cursors.append(cursor)
|
||||
try:
|
||||
if cube[cursor[0]][cursor[1]][cursor[2]]!=0:
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
set_cube_vals(cursors, cube, index)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def remove_piece_in_cube(piece,cube,position):
|
||||
cursors = [np.add(position,p) for p in piece]
|
||||
set_cube_vals(cursors, cube, 0)
|
||||
|
||||
def rotate_vector(vector,axis,angle):
|
||||
x,y,z=vector
|
||||
angle=math.radians(angle)
|
||||
if axis == "z":
|
||||
return (int(round((x*math.cos(angle)) - (y*math.sin(angle)))),int(round((x*math.sin(angle)) + (y*math.cos(angle)))),z)
|
||||
if axis == "y":
|
||||
return (int(round(x*math.cos(angle) + z*math.sin(angle))),y,int(round(-x*math.sin(angle) + z*math.cos(angle))))
|
||||
if axis == "x":
|
||||
return (x,int(round(y*math.cos(angle) - z*math.sin(angle))),int(round(y*math.sin(angle) + z*math.cos(angle))))
|
||||
|
||||
def rotate_piece(piece,axis,angle):
|
||||
return [rotate_vector(x, axis, angle) for x in piece]
|
||||
|
||||
def shift_piece(piece,anchor_index):
|
||||
anchor=piece[anchor_index]
|
||||
return [np.subtract(p,anchor) for p in piece]
|
||||
|
||||
def generate_rotations(piece):
|
||||
all_rotations=set()
|
||||
for i in range(0,4):
|
||||
for j in range(0,4):
|
||||
for k in range(0,4):
|
||||
for p in range(0,len(piece)):
|
||||
rotated_piece=rotate_piece(rotate_piece(rotate_piece(shift_piece(piece,p),"x",k*90),"y",j*90),"z",i*90)
|
||||
all_rotations.add(tuple(rotated_piece))
|
||||
return frozenset(all_rotations)
|
||||
|
||||
def find_empty_spot(cube):
|
||||
for z in range(0,sizeofcube):
|
||||
for y in range(0,sizeofcube):
|
||||
for x in range(0,sizeofcube):
|
||||
if cube[x][y][z]==0:
|
||||
return (x,y,z)
|
||||
return None
|
||||
|
||||
def printstats():
|
||||
global stat_counter
|
||||
global stats
|
||||
stat_counter=stat_counter+1
|
||||
if stat_counter%10000==0:
|
||||
print(stat_counter)
|
||||
for x in stats:
|
||||
print("{}:{}".format(x,stats[x]))
|
||||
if x>5:
|
||||
break
|
||||
|
||||
def parallel_pool_init():
|
||||
global stats
|
||||
global solutions
|
||||
stats=dict()
|
||||
solutions=list()
|
||||
|
||||
|
||||
def parallel_solve(cube):
|
||||
global all_rotations
|
||||
all_rotations=generate_rotations(piece)
|
||||
pieces=set(all_rotations.copy())
|
||||
first_position=(0,0,0)
|
||||
while len(pieces)>0:
|
||||
piece=pieces.pop()
|
||||
if put_piece_in_cube(piece, cube, first_position, index):
|
||||
solve(cube, 2,):
|
||||
|
||||
|
||||
def solve(cube,index):
|
||||
global stats
|
||||
global solutions
|
||||
global all_rotations
|
||||
pieces=set(all_rotations.copy())
|
||||
|
||||
# print("{}:find empty spot#########################".format(index))
|
||||
empty_pos=find_empty_spot(cube)
|
||||
|
||||
if empty_pos==None:
|
||||
pprint.pprint(cube)
|
||||
draw_cube(cube)
|
||||
solutions.append(cube)
|
||||
return False
|
||||
else:
|
||||
(x,y,z)=empty_pos
|
||||
while len(pieces)>0:
|
||||
#use copy of cube without my parts
|
||||
piece=pieces.pop()
|
||||
if put_piece_in_cube(piece, cube, (x,y,z), index):
|
||||
# print("{}:found fitting piece {} ({} left)".format(index,piece,len(pieces)))
|
||||
stats[index]=len(pieces)
|
||||
if solve(cube, index+1):
|
||||
return True
|
||||
else:
|
||||
remove_piece_in_cube(piece, cube, (x,y,z))
|
||||
#nothing fits return fail
|
||||
return False
|
||||
|
||||
|
||||
# maxindex=0
|
||||
# stat_counter=0
|
||||
# stats=dict()
|
||||
# last_stats=dict()
|
||||
|
||||
def main():
|
||||
parallel_solve(init_cube())
|
||||
|
||||
if __name__ == '__main__':
|
||||
# profile.run('main()')
|
||||
main()
|
||||
177
projects/puzzlebox/solve_mp.py
Normal file
177
projects/puzzlebox/solve_mp.py
Normal file
@@ -0,0 +1,177 @@
|
||||
import pprint
|
||||
import operator
|
||||
import numpy as np
|
||||
import math
|
||||
from copy import copy, deepcopy
|
||||
import profile
|
||||
|
||||
piece=[[0,0,0],[0,1,0],[0,2,0],[0,3,0],[1,2,0]]
|
||||
sizeofcube=5
|
||||
|
||||
def init_cube(size=sizeofcube):
|
||||
return [[[0 for x in range(0,size)] for y in range(0,size)] for z in range(0,size)]
|
||||
|
||||
def move_start_position(piece,index):
|
||||
return [np.subtract(x, piece[index]) for x in piece]
|
||||
|
||||
def draw_cube(cube):
|
||||
from mpl_toolkits.mplot3d import Axes3D
|
||||
import matplotlib.pyplot as plt
|
||||
fig = plt.figure()
|
||||
ax = fig.gca(projection='3d')
|
||||
ax.set_aspect('equal')
|
||||
ax.set_xlabel('x', fontsize=10)
|
||||
ax.set_ylabel('y', fontsize=10)
|
||||
ax.set_zlabel('z', fontsize=10)
|
||||
|
||||
ma=np.array(cube)
|
||||
ax.voxels(ma, edgecolor="k")
|
||||
plt.show()
|
||||
|
||||
def set_cube_vals(cursors,cube,value):
|
||||
for cursor in cursors:
|
||||
cube[cursor[0]][cursor[1]][cursor[2]]=value
|
||||
|
||||
def is_valid(piece,position):
|
||||
global sizeofcube
|
||||
upper_x=sizeofcube-position[0]
|
||||
upper_y=sizeofcube-position[1]
|
||||
upper_z=sizeofcube-position[2]
|
||||
for (x,y,z) in piece:
|
||||
if x<-position[0] or x>upper_x:
|
||||
return False
|
||||
if y<-position[1] or y>upper_y:
|
||||
return False
|
||||
if z<-position[2] or z>upper_z:
|
||||
return False
|
||||
return True
|
||||
|
||||
def put_piece_in_cube(piece,cube,position,index):
|
||||
if is_valid(piece,position):
|
||||
# cursors = [np.add(position,p) for p in piece]
|
||||
# for cursor in cursors:
|
||||
cursors=[]
|
||||
for (x,y,z) in piece:
|
||||
cursor=[(x+position[0]),(y+position[1]),(z+position[2])]
|
||||
cursors.append(cursor)
|
||||
try:
|
||||
if cube[cursor[0]][cursor[1]][cursor[2]]!=0:
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
set_cube_vals(cursors, cube, index)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def remove_piece_in_cube(piece,cube,position):
|
||||
cursors = [np.add(position,p) for p in piece]
|
||||
set_cube_vals(cursors, cube, 0)
|
||||
|
||||
def rotate_vector(vector,axis,angle):
|
||||
x,y,z=vector
|
||||
angle=math.radians(angle)
|
||||
if axis == "z":
|
||||
return (int(round((x*math.cos(angle)) - (y*math.sin(angle)))),int(round((x*math.sin(angle)) + (y*math.cos(angle)))),z)
|
||||
if axis == "y":
|
||||
return (int(round(x*math.cos(angle) + z*math.sin(angle))),y,int(round(-x*math.sin(angle) + z*math.cos(angle))))
|
||||
if axis == "x":
|
||||
return (x,int(round(y*math.cos(angle) - z*math.sin(angle))),int(round(y*math.sin(angle) + z*math.cos(angle))))
|
||||
|
||||
def rotate_piece(piece,axis,angle):
|
||||
return [rotate_vector(x, axis, angle) for x in piece]
|
||||
|
||||
def shift_piece(piece,anchor_index):
|
||||
anchor=piece[anchor_index]
|
||||
return [np.subtract(p,anchor) for p in piece]
|
||||
|
||||
def generate_rotations(piece):
|
||||
all_rotations=set()
|
||||
for i in range(0,4):
|
||||
for j in range(0,4):
|
||||
for k in range(0,4):
|
||||
for p in range(0,len(piece)):
|
||||
rotated_piece=rotate_piece(rotate_piece(rotate_piece(shift_piece(piece,p),"x",k*90),"y",j*90),"z",i*90)
|
||||
all_rotations.add(tuple(rotated_piece))
|
||||
return frozenset(all_rotations)
|
||||
|
||||
def find_empty_spot(cube):
|
||||
for z in range(0,sizeofcube):
|
||||
for y in range(0,sizeofcube):
|
||||
for x in range(0,sizeofcube):
|
||||
if cube[x][y][z]==0:
|
||||
return (x,y,z)
|
||||
return None
|
||||
|
||||
def printstats():
|
||||
global stat_counter
|
||||
global stats
|
||||
stat_counter=stat_counter+1
|
||||
if stat_counter%10000==0:
|
||||
print(stat_counter)
|
||||
for x in stats:
|
||||
print("{}:{}".format(x,stats[x]))
|
||||
if x>5:
|
||||
break
|
||||
|
||||
def parallel_pool_init():
|
||||
global stats
|
||||
global solutions
|
||||
stats=dict()
|
||||
solutions=list()
|
||||
|
||||
|
||||
def parallel_solve(cube):
|
||||
global all_rotations
|
||||
all_rotations=generate_rotations(piece)
|
||||
pieces=set(all_rotations.copy())
|
||||
first_position=(0,0,0)
|
||||
while len(pieces)>0:
|
||||
piece=pieces.pop()
|
||||
if put_piece_in_cube(piece, cube, first_position, index):
|
||||
stats["jobid"]={"0"=>len(pieces)}
|
||||
|
||||
solve(cube, 2,):
|
||||
|
||||
|
||||
def solve(cube,index,jobid):
|
||||
global stats
|
||||
global solutions
|
||||
global all_rotations
|
||||
pieces=set(all_rotations.copy())
|
||||
|
||||
# print("{}:find empty spot#########################".format(index))
|
||||
empty_pos=find_empty_spot(cube)
|
||||
|
||||
if empty_pos==None:
|
||||
pprint.pprint(cube)
|
||||
draw_cube(cube)
|
||||
solutions.append(cube)
|
||||
return False
|
||||
else:
|
||||
(x,y,z)=empty_pos
|
||||
while len(pieces)>0:
|
||||
#use copy of cube without my parts
|
||||
piece=pieces.pop()
|
||||
if put_piece_in_cube(piece, cube, (x,y,z), index):
|
||||
# print("{}:found fitting piece {} ({} left)".format(index,piece,len(pieces)))
|
||||
stats[index]=len(pieces)
|
||||
if solve(cube, index+1):
|
||||
return True
|
||||
else:
|
||||
remove_piece_in_cube(piece, cube, (x,y,z))
|
||||
#nothing fits return fail
|
||||
return False
|
||||
|
||||
|
||||
# maxindex=0
|
||||
# stat_counter=0
|
||||
# stats=dict()
|
||||
# last_stats=dict()
|
||||
|
||||
def main():
|
||||
parallel_solve(init_cube())
|
||||
|
||||
if __name__ == '__main__':
|
||||
# profile.run('main()')
|
||||
main()
|
||||
99
projects/puzzlebox/voxels.py
Normal file
99
projects/puzzlebox/voxels.py
Normal file
@@ -0,0 +1,99 @@
|
||||
'''
|
||||
==========================
|
||||
3D voxel / volumetric plot
|
||||
==========================
|
||||
|
||||
Demonstrates plotting 3D volumetric objects with ``ax.voxels``
|
||||
'''
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import pprint
|
||||
import random
|
||||
from matplotlib import colors as mcolors
|
||||
|
||||
# This import registers the 3D projection, but is otherwise unused.
|
||||
from mpl_toolkits.mplot3d import Axes3D # noqa: F401 unused import
|
||||
|
||||
g_cube=np.zeros((6,6,6))
|
||||
# prepare some coordinates
|
||||
x, y, z = np.indices((6, 6, 6))
|
||||
|
||||
# farben=["red","blue","green","cyan","magenta","yellow"]
|
||||
farben=[name for name in mcolors.CSS4_COLORS]
|
||||
random.shuffle(farben)
|
||||
g_cube=[[[1, 1, 1, 1, 22],
|
||||
[6, 6, 6, 6, 22],
|
||||
[2, 6, 9, 22, 22],
|
||||
[9, 9, 9, 9, 22],
|
||||
[10, 15, 15, 15, 15]],
|
||||
[[2, 11, 1, 19, 20],
|
||||
[2, 11, 13, 19, 21],
|
||||
[2, 11, 11, 19, 23],
|
||||
[2, 11, 17, 19, 24],
|
||||
[10, 14, 18, 15, 25]],
|
||||
[[3, 3, 3, 3, 20],
|
||||
[4, 13, 13, 19, 21],
|
||||
[8, 8, 8, 8, 23],
|
||||
[10, 14, 17, 17, 24],
|
||||
[10, 14, 18, 18, 25]],
|
||||
[[4, 12, 3, 20, 20],
|
||||
[4, 12, 13, 21, 21],
|
||||
[4, 12, 8, 23, 23],
|
||||
[4, 12, 17, 24, 24],
|
||||
[10, 14, 18, 25, 25]],
|
||||
[[5, 5, 5, 5, 20],
|
||||
[7, 5, 13, 16, 21],
|
||||
[7, 12, 16, 16, 23],
|
||||
[7, 7, 17, 16, 24],
|
||||
[7, 14, 18, 16, 25]]]
|
||||
|
||||
|
||||
list_of_cubes =list()
|
||||
color_counter=0
|
||||
for x_pos in range(0,len(g_cube)):
|
||||
for y_pos in range(0,len(g_cube[x_pos])):
|
||||
for z_pos in range(0,len(g_cube[x_pos][y_pos])):
|
||||
if g_cube[x_pos][y_pos][z_pos]!=0:
|
||||
cur_farbe=g_cube[x_pos][y_pos][z_pos]%len(farben)
|
||||
print("Voxel by in {} for ({}>x>={}//{}>y>={}//{}>z>={}) )".format(farben[cur_farbe],x_pos,x_pos+1,y_pos,y_pos+1,z_pos,z_pos+1))
|
||||
list_of_cubes.append({"cube":(x > x_pos) & (x <= (x_pos+1) ) & (y > y_pos) & (y <= (y_pos+1) ) & (z > z_pos) & (z <= (z_pos+1) ),"farbe":farben[cur_farbe]})
|
||||
color_counter=(color_counter + 1) % len (farben)
|
||||
|
||||
voxels=list_of_cubes[0]["cube"]
|
||||
colors = np.empty(voxels.shape, dtype=object)
|
||||
|
||||
for x in list_of_cubes:
|
||||
voxels=voxels | x["cube"]
|
||||
colors[x["cube"]]=x["farbe"]
|
||||
|
||||
fig = plt.figure()
|
||||
ax = fig.gca(projection='3d')
|
||||
ax.voxels(voxels, facecolors=colors, edgecolor='k')
|
||||
|
||||
plt.show()
|
||||
|
||||
|
||||
|
||||
|
||||
# draw cuboids in the top left and bottom right corners, and a link between them
|
||||
#
|
||||
# cube1 = (x < 3) & (y < 3) & (z < 3)
|
||||
# cube2 = (x >= 5) & (y >= 5) & (z >= 5)
|
||||
# link = abs(x - y) + abs(y - z) + abs(z - x) <= 2
|
||||
#
|
||||
# # combine the objects into a single boolean array
|
||||
# voxels = cube1 | cube2 | link
|
||||
#
|
||||
# # set the colors of each object
|
||||
# colors = np.empty(voxels.shape, dtype=object)
|
||||
# colors[link] = 'red'
|
||||
# colors[cube1] = 'blue'
|
||||
# colors[cube2] = 'green'
|
||||
#
|
||||
# # and plot everything
|
||||
# fig = plt.figure()
|
||||
# ax = fig.gca(projection='3d')
|
||||
# ax.voxels(voxels, facecolors=colors, edgecolor='k')
|
||||
#
|
||||
# plt.show()
|
||||
55
projects/rust-tools/between.rs
Normal file
55
projects/rust-tools/between.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufRead, BufReader};
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() < 2 {
|
||||
eprintln!("Usage: {} start-end [count] [file...]", args[0]);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let range = &args[1];
|
||||
let (start, mut end) = if let Some(dash_pos) = range.find('-') {
|
||||
(range[..dash_pos].parse().unwrap(), range[dash_pos + 1..].parse().unwrap())
|
||||
} else {
|
||||
(range.parse().unwrap(), 0)
|
||||
};
|
||||
|
||||
let mut count = 1;
|
||||
let mut files_start = 2;
|
||||
|
||||
if end == 0 {
|
||||
if args.len() > 2 {
|
||||
if let Ok(c) = args[2].parse::<usize>() {
|
||||
count = c;
|
||||
files_start = 3;
|
||||
}
|
||||
}
|
||||
end = start + count - 1;
|
||||
}
|
||||
|
||||
if args.len() > files_start {
|
||||
for filename in &args[files_start..] {
|
||||
let file = File::open(filename)?;
|
||||
let reader = BufReader::new(file);
|
||||
process_lines(reader, start, end)?;
|
||||
}
|
||||
} else {
|
||||
// No files provided, read from stdin
|
||||
let stdin = io::stdin();
|
||||
let reader = stdin.lock();
|
||||
process_lines(reader, start, end)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_lines<R: BufRead>(reader: R, start: usize, end: usize) -> io::Result<()> {
|
||||
reader.lines()
|
||||
.enumerate()
|
||||
.filter_map(|(i, line)| if i + 1 >= start && i + 1 <= end { line.ok() } else { None })
|
||||
.for_each(|line| println!("{}", line));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
BIN
projects/rust-tools/uniq
Executable file
BIN
projects/rust-tools/uniq
Executable file
Binary file not shown.
41
projects/rust-tools/uniq.rs
Normal file
41
projects/rust-tools/uniq.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufRead, BufReader};
|
||||
use std::collections::HashSet;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
|
||||
if args.len() > 1 {
|
||||
for filename in &args[1..] {
|
||||
let file = File::open(filename)?;
|
||||
let reader = BufReader::new(file);
|
||||
remove_duplicates(reader)?;
|
||||
}
|
||||
} else {
|
||||
// No files provided, read from stdin
|
||||
let stdin = io::stdin();
|
||||
let reader = stdin.lock();
|
||||
remove_duplicates(reader)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn remove_duplicates<R: BufRead>(reader: R) -> io::Result<()> {
|
||||
let mut seen_hashes = HashSet::new();
|
||||
for line in reader.lines() {
|
||||
let line = line?;
|
||||
let mut hasher = DefaultHasher::new();
|
||||
line.hash(&mut hasher);
|
||||
let hash = hasher.finish();
|
||||
|
||||
if seen_hashes.insert(hash) {
|
||||
println!("{}", line);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
BIN
projects/rust-tools/uniq2
Executable file
BIN
projects/rust-tools/uniq2
Executable file
Binary file not shown.
36
projects/rust-tools/uniq2.rs
Normal file
36
projects/rust-tools/uniq2.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
use std::collections::HashSet;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
|
||||
struct HashOnlySet {
|
||||
set: HashSet<u64>,
|
||||
}
|
||||
|
||||
impl HashOnlySet {
|
||||
fn new() -> HashOnlySet {
|
||||
HashOnlySet { set: HashSet::new() }
|
||||
}
|
||||
|
||||
fn insert<T: Hash>(&mut self, item: &T) -> bool {
|
||||
let hash = Self::hash_item(item);
|
||||
self.set.insert(hash)
|
||||
}
|
||||
|
||||
fn contains<T: Hash>(&self, item: &T) -> bool {
|
||||
let hash = Self::hash_item(item);
|
||||
self.set.contains(&hash)
|
||||
}
|
||||
|
||||
fn hash_item<T: Hash>(item: &T) -> u64 {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
item.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut set = HashOnlySet::new();
|
||||
set.insert(&"Hello, world!");
|
||||
println!("Contains 'Hello, world!': {}", set.contains(&"Hello, world!"));
|
||||
println!("Contains 'Goodbye, world!': {}", set.contains(&"Goodbye, world!"));
|
||||
}
|
||||
72
projects/timesketch/deploy_timesketch.sh
Executable file
72
projects/timesketch/deploy_timesketch.sh
Executable file
@@ -0,0 +1,72 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Create dirs
|
||||
mkdir -p timesketch/{data/postgresql,data/elasticsearch,logs,etc,etc/timesketch,etc/timesketch/sigma/rules,upload}
|
||||
|
||||
echo -n "* Setting default config parameters.."
|
||||
POSTGRES_USER="timesketch"
|
||||
POSTGRES_PASSWORD="$(< /dev/urandom tr -dc A-Za-z0-9 | head -c 32 ; echo)"
|
||||
POSTGRES_ADDRESS="postgres"
|
||||
POSTGRES_PORT=5432
|
||||
SECRET_KEY="$(< /dev/urandom tr -dc A-Za-z0-9 | head -c 32 ; echo)"
|
||||
ELASTIC_ADDRESS="elasticsearch"
|
||||
ELASTIC_PORT=9200
|
||||
REDIS_ADDRESS="redis"
|
||||
REDIS_PORT=6379
|
||||
GITHUB_BASE_URL="https://raw.githubusercontent.com/google/timesketch/master"
|
||||
ELASTIC_MEM_USE_GB=$(cat /proc/meminfo | grep MemTotal | awk '{printf "%.0f", ($2 / 1000000 / 2)}')
|
||||
echo "OK"
|
||||
echo "* Setting Elasticsearch memory allocation to ${ELASTIC_MEM_USE_GB}GB"
|
||||
|
||||
# Docker compose and configuration
|
||||
echo -n "* Fetching configuration files.."
|
||||
curl $GITHUB_BASE_URL/docker/release/docker-compose.yml > timesketch/docker-compose.yml
|
||||
curl $GITHUB_BASE_URL/docker/release/config.env > timesketch/config.env
|
||||
|
||||
# Fetch default Timesketch config files
|
||||
curl $GITHUB_BASE_URL/data/timesketch.conf > timesketch/etc/timesketch/timesketch.conf
|
||||
curl $GITHUB_BASE_URL/data/tags.yaml > timesketch/etc/timesketch/tags.yaml
|
||||
curl $GITHUB_BASE_URL/data/plaso.mappings > timesketch/etc/timesketch/plaso.mappings
|
||||
curl $GITHUB_BASE_URL/data/generic.mappings > timesketch/etc/timesketch/generic.mappings
|
||||
curl $GITHUB_BASE_URL/data/features.yaml > timesketch/etc/timesketch/features.yaml
|
||||
curl $GITHUB_BASE_URL/data/sigma_config.yaml > timesketch/etc/timesketch/sigma_config.yaml
|
||||
curl $GITHUB_BASE_URL/data/sigma/rules/lnx_susp_zenmap.yml > timesketch/etc/timesketch/sigma/rules/lnx_susp_zenmap.yml
|
||||
curl $GITHUB_BASE_URL/contrib/nginx.conf > timesketch/etc/nginx.conf
|
||||
echo "OK"
|
||||
|
||||
# Create a minimal Timesketch config
|
||||
echo -n "* Edit configuration files.."
|
||||
sed -i 's#SECRET_KEY = \x27\x3CKEY_GOES_HERE\x3E\x27#SECRET_KEY = \x27'$SECRET_KEY'\x27#' timesketch/etc/timesketch/timesketch.conf
|
||||
|
||||
# Set up the Elastic connection
|
||||
sed -i 's#^ELASTIC_HOST = \x27127.0.0.1\x27#ELASTIC_HOST = \x27'$ELASTIC_ADDRESS'\x27#' timesketch/etc/timesketch/timesketch.conf
|
||||
sed -i 's#^ELASTIC_PORT = 9200#ELASTIC_PORT = '$ELASTIC_PORT'#' timesketch/etc/timesketch/timesketch.conf
|
||||
|
||||
# Set up the Redis connection
|
||||
sed -i 's#^UPLOAD_ENABLED = False#UPLOAD_ENABLED = True#' timesketch/etc/timesketch/timesketch.conf
|
||||
sed -i 's#^UPLOAD_FOLDER = \x27/tmp\x27#UPLOAD_FOLDER = \x27/usr/share/timesketch/upload\x27#' timesketch/etc/timesketch/timesketch.conf
|
||||
|
||||
sed -i 's#^CELERY_BROKER_URL =.*#CELERY_BROKER_URL = \x27redis://'$REDIS_ADDRESS':'$REDIS_PORT'\x27#' timesketch/etc/timesketch/timesketch.conf
|
||||
sed -i 's#^CELERY_RESULT_BACKEND =.*#CELERY_RESULT_BACKEND = \x27redis://'$REDIS_ADDRESS':'$REDIS_PORT'\x27#' timesketch/etc/timesketch/timesketch.conf
|
||||
|
||||
# Set up the Postgres connection
|
||||
sed -i 's#postgresql://<USERNAME>:<PASSWORD>@localhost#postgresql://'$POSTGRES_USER':'$POSTGRES_PASSWORD'@'$POSTGRES_ADDRESS':'$POSTGRES_PORT'#' timesketch/etc/timesketch/timesketch.conf
|
||||
|
||||
sed -i 's#^POSTGRES_PASSWORD=#POSTGRES_PASSWORD='$POSTGRES_PASSWORD'#' timesketch/config.env
|
||||
sed -i 's#^ELASTIC_MEM_USE_GB=#ELASTIC_MEM_USE_GB='$ELASTIC_MEM_USE_GB'#' timesketch/config.env
|
||||
|
||||
ln -s ./config.env ./timesketch/.env
|
||||
echo "OK"
|
||||
echo "* Installation done."
|
||||
|
||||
echo
|
||||
echo "Start the system:"
|
||||
echo "1. cd timesketch"
|
||||
echo "2. docker-compose up -d"
|
||||
echo "3. docker-compose exec timesketch-web tsctl add_user --username <USERNAME>"
|
||||
echo
|
||||
echo "WARNING: The server is running without encryption."
|
||||
echo "Follow the instructions to enable SSL to secure the communications:"
|
||||
echo "https://github.com/google/timesketch/blob/master/docs/Installation.md"
|
||||
echo
|
||||
echo
|
||||
Reference in New Issue
Block a user