This commit is contained in:
Zeev Diukman 2025-03-06 22:48:11 +00:00
parent 7fe2b621e8
commit f3e476a6c3
9 changed files with 458 additions and 130 deletions

View file

@ -1,52 +0,0 @@
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"
[build]
args_bin = []
bin = "./tmp/main"
cmd = "go build -o ./tmp/main ."
delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
exclude_file = []
exclude_regex = ["_test.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html"]
include_file = []
kill_delay = "0s"
log = "build-errors.log"
poll = false
poll_interval = 0
post_cmd = []
pre_cmd = []
rerun = false
rerun_delay = 500
send_interrupt = false
stop_on_error = false
[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"
[log]
main_only = false
silent = false
time = false
[misc]
clean_on_exit = false
[proxy]
app_port = 0
enabled = false
proxy_port = 0
[screen]
clear_on_rebuild = false
keep_scroll = true

View file

@ -1,20 +1,37 @@
http:
routers:
keycloak:
entryPoint: https
service: keycloak
rules: Host(keycloak.z.com).Path(`/`)
rules: Domain(`keycloak.z.com`).Path(`/`)
tls:
certProvider: default
app1:
service: app1_srv
rules: Host(`app1.z.com`).Path(`/`)
entryPoint: https
service: app1
rules: Domain(`app1.z.com`).Path(`/`)
tls:
certProvider: default
app2:
service: app2_srv
rules: Host(`app2.z.com`).Path(`/`)
entryPoint: https
service: app2
rules: Domain(`app2.z.com`).Path(`/`)
tls:
certProvider: default
services:
keycloak: http://192.168.10.2:8080
app1_srv: http://192.168.10.2:3001
app2_srv: http://192.168.10.2:3002
app1: http://192.168.10.2:3001
app2: http://192.168.10.2:3002
entryPoints:
https:
address: :443
tls:
enabled: true
tls:
certProviders:
default:
key: ./assets/certs/z.com.key.pem
cert: ./assets/certs/z.com.cert.pem

7
go.mod
View file

@ -1,15 +1,18 @@
module z/zprox
module github.com/zeevdiukman/zprox
go 1.24.0
require github.com/gookit/goutil v0.6.18 // indirect
require (
github.com/zeevdiukman/go-interpreter v0.0.0-20250305163450-43423a7e8ba7
github.com/zeevdiukman/go-reverseproxy v0.0.0-20250305093102-9882ad3edb31
github.com/zeevdiukman/go-router v0.0.0-20250305093130-650cd1d241f5
github.com/zeevdiukman/go-server v0.0.0-20250305093228-f3ab0096fcba
)
require (
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gookit/goutil v0.6.18 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect

4
go.sum
View file

@ -63,10 +63,14 @@ github.com/zeevdiukman/go-config v0.0.0-20250305101848-6cef80370123 h1:AYl8UZu7+
github.com/zeevdiukman/go-config v0.0.0-20250305101848-6cef80370123/go.mod h1:oK8ESatUsIFPpj/p/0iMW3HPs8+97F52O40xjotcY64=
github.com/zeevdiukman/go-helper v0.0.0-20250305091316-396bd5057e2f h1:1UyqJ/MzVw+Oxl8kryguBsObG7qVw+IhlKTE/HhpLGE=
github.com/zeevdiukman/go-helper v0.0.0-20250305091316-396bd5057e2f/go.mod h1:buB5zo+BkiM7kNOI2o33rmXBSlnjH1zpN0DtgNDbnCc=
github.com/zeevdiukman/go-interpreter v0.0.0-20250305163450-43423a7e8ba7 h1:3iW+LgqdYt9OvhcFX5aK3eI5Kr9Ue/wTpiZqBFEWMT8=
github.com/zeevdiukman/go-interpreter v0.0.0-20250305163450-43423a7e8ba7/go.mod h1:fofniVuiVQ022IcHdrRsO67GXj2jIp/D8K+DP7APUrQ=
github.com/zeevdiukman/go-reverseproxy v0.0.0-20250305093102-9882ad3edb31 h1:OaOVvayXo4yf/gg8/IuZzGnFxTXEXGOVXiNVxPC0OgM=
github.com/zeevdiukman/go-reverseproxy v0.0.0-20250305093102-9882ad3edb31/go.mod h1:RAFNKzQy/q2eDB/2WI88dHuiVC8Qqp6iAPDZ+btXACk=
github.com/zeevdiukman/go-router v0.0.0-20250305093130-650cd1d241f5 h1:ssP7N61mi0MLfnaH/ob7xOlu+prPwULl0nZ2hPw/QdE=
github.com/zeevdiukman/go-router v0.0.0-20250305093130-650cd1d241f5/go.mod h1:wY15gRD14GOWs8j6bazZypGkMfCbSdr5cQK77MwzReA=
github.com/zeevdiukman/go-server v0.0.0-20250305093228-f3ab0096fcba h1:BHG0fbASaIBXr+JyIaIt+/x1MIH+wAB5MTj2VQ1nlnU=
github.com/zeevdiukman/go-server v0.0.0-20250305093228-f3ab0096fcba/go.mod h1:HQARDR3c1btC+vNSDekVtC1KM/tVFrJqr3yGrPN3pbo=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=

241
internal/config/config.go Normal file
View file

@ -0,0 +1,241 @@
package config
import (
"regexp"
"strings"
"github.com/zeevdiukman/go-config"
)
const VIPER_NAME string = "config"
const VIPER_TYPE string = "yaml"
const VIPER_PATH string = "./assets/config/."
const SERVICES_KEY string = "http.services"
const ROUTERS_KEY string = "http.routers"
const ENTRYPOINTS_KEY string = "entrypoints"
const TLS_KEY string = "tls.certproviders"
type Config struct {
HTTP *HTTP
TLS *TLS
EntryPoints EntryPoints
}
type HTTP struct {
Routers Routers
Services Services
}
type TLS struct {
CertProviders CertProviders
}
type CertProviders map[string]*CertProvider
type CertProvider struct {
Key string
Cert string
}
type Services map[string]*Service
type Service struct {
URL string
}
type EntryPoints map[string]*EntryPoint
type EntryPoint struct {
Address string
TLS *EntryPointTLS
}
type EntryPointTLS struct {
Enabled bool
}
type Routers map[string]*Router
type Router struct {
EntryPoint string
Service string
Rules *Rules
TLS *RouterTLS
}
type RouterTLS struct {
CertProvider string
}
type Rules struct {
Raw string
Map map[string]*Rule
}
type Rule struct {
Name string
Value string
}
func NewConfig() *Config {
c := config.NewConfig(VIPER_NAME, VIPER_TYPE, VIPER_PATH)
c.Load()
appConfig := &Config{
HTTP: &HTTP{
Routers: Routers{},
Services: Services{},
},
TLS: &TLS{
CertProviders: CertProviders{},
},
EntryPoints: EntryPoints{},
}
appConfig.InitRouters(c)
appConfig.InitServices(c)
appConfig.InitEntryPoints(c)
appConfig.InitTLS(c)
return appConfig
}
func (r Routers) ForEach(fn func(routerName string, routerConfig *Router)) {
for k, v := range r {
fn(k, v)
}
}
func (ep EntryPoints) ForEach(fn func(entryPointName string, entryPointConfig *EntryPoint)) {
forEach(ep, fn)
}
func (s Services) ForEach(fn func(serviceName string, serviceConfig *Service)) {
forEach(s, fn)
}
func (c *Config) InitRouters(vConfig *config.Config) {
c.HTTP.Routers = make(Routers)
for k, v := range vConfig.Sub(ROUTERS_KEY).AllSettings() {
val := v.(map[string]any)
var tls string = ""
var services string = ""
var rawRules string = ""
var entryPoint string = ""
if value, ok := val["service"]; ok {
services = value.(string)
}
if value, ok := val["rules"]; ok {
rawRules = value.(string)
}
if value, ok := val["entrypoint"]; ok {
entryPoint = value.(string)
}
if value, ok := val["tls"]; ok {
tls = value.(map[string]any)["certprovider"].(string)
}
rls := &Rules{
Raw: rawRules,
Map: make(map[string]*Rule),
}
r := &Router{
Service: services,
Rules: rls,
EntryPoint: entryPoint,
TLS: &RouterTLS{CertProvider: tls},
}
r.ForRuleFunc("Domain", func(domain string) {
r.Rules.Map["Domain"] = &Rule{
Name: "Domain",
Value: domain,
}
})
r.ForRuleFunc("Path", func(path string) {
r.Rules.Map["Path"] = &Rule{
Name: "Path",
Value: path,
}
})
c.HTTP.Routers[k] = r
}
}
func (c *Config) InitServices(vConfig *config.Config) {
c.HTTP.Services = make(map[string]*Service)
for k, v := range vConfig.Sub(SERVICES_KEY).AllSettings() {
c.HTTP.Services[k] = &Service{
URL: v.(string),
}
}
}
func (c *Config) InitEntryPoints(vConfig *config.Config) {
c.EntryPoints = make(EntryPoints)
for k, v := range vConfig.Sub(ENTRYPOINTS_KEY).AllSettings() {
v := v.(map[string]any)
address := ""
enabled := false
if v, ok := v["tls"]; ok {
if v, ok := v.(map[string]any)["enabled"]; ok {
enabled = v.(bool)
}
}
if value, ok := v["address"]; ok {
address = value.(string)
}
c.EntryPoints[k] = &EntryPoint{
Address: address,
TLS: &EntryPointTLS{
Enabled: enabled,
},
}
}
}
func (c *Config) InitTLS(vConfig *config.Config) {
c.TLS.CertProviders = make(map[string]*CertProvider)
for k, v := range vConfig.Sub(TLS_KEY).AllSettings() {
cert := v.(map[string]any)["cert"].(string)
key := v.(map[string]any)["key"].(string)
c.TLS.CertProviders[k] = &CertProvider{
Cert: cert,
Key: key,
}
}
}
func forEach[K comparable, V comparable](mp map[K]V, fn func(key K, value V)) {
for k, v := range mp {
fn(k, v)
}
}
func (r *Router) ForRuleFunc(ruleName string, fn func(string)) {
rules := r.Rules.Raw
rulesSlice := splitStatementByRegex(rules, "\\(`(.*?)`\\)")
for idx, rule := range rulesSlice {
rule, _ = strings.CutPrefix(rule, ".")
if rule == ruleName {
fn(rulesSlice[idx+1])
}
}
}
func splitStatementByRegex(str string, regx string) []string {
input := str
re := regexp.MustCompile(regx)
matches := re.FindAllStringSubmatch(input, -1)
if len(matches) == 0 {
return []string{str} // Return original if no backticks found
}
result := []string{}
lastIndex := 0
for _, match := range matches {
startIndex := strings.Index(input, match[0])
if startIndex > lastIndex {
result = append(result, input[lastIndex:startIndex])
}
result = append(result, match[1]) // Append the content within backticks
lastIndex = startIndex + len(match[0])
}
if lastIndex < len(input) {
result = append(result, input[lastIndex:])
}
return result
}

View file

@ -0,0 +1,43 @@
package interpreter
import (
"strings"
"github.com/zeevdiukman/go-interpreter"
)
type Interp struct {
*interpreter.Interpreter
}
func New() *Interp {
interp := &Interp{interpreter.New()}
return interp
}
func (interp *Interp) PathAction(rules string, fn func(fn interpreter.Function)) {
name := "router_rules"
regx := interp.Regex(name, "\\(`(.*?)`\\)")
interp.Func(name, func(args ...any) string {
// argsStmntName := args[0].(string)
argsPathAction := args[0].(func(string))
interp.AddStatment(name, rules).SplitStatementByRegex(regx)
interp.Statments.ForEach(func(stmnt *interpreter.Statment) {
if stmnt.Name == name {
for idx, splitVal := range stmnt.RegexSplit {
splitVal, _ = strings.CutPrefix(splitVal, ".")
switch splitVal {
case "Path":
{
path := stmnt.RegexSplit[idx+1]
argsPathAction(path)
}
}
}
}
})
return ""
})
interp.Funcs[name].Function()
}

204
main.go
View file

@ -1,11 +1,34 @@
/*
Example:
rp1 := reverseproxy.New(ctx, "http://localhost:8080")
rp2 := reverseproxy.New(ctx, "http://localhost:3001")
rp3 := reverseproxy.New(ctx, "http://localhost:3002")
router := router.NewRouter()
pr1 := router.NewHostRouter("keycloak.z.com")
pr1.Handler(rp1)
go func() {
s := server.New().Name("proxy1").Port(443).Router(router)
s.CertKey(CERTS_PATH, "z.com.cert.pem", "z.com.key.pem")
err := s.ListenAndServeTLS()
if err != nil {
log.Println(err.Error())
}
}()
*/
package main
import (
"fmt"
"context"
"strconv"
"strings"
"github.com/gookit/goutil/dump"
"github.com/zeevdiukman/go-config"
"github.com/zeevdiukman/go-helper"
"github.com/zeevdiukman/go-reverseproxy"
"github.com/zeevdiukman/go-router"
"github.com/zeevdiukman/go-server"
"github.com/zeevdiukman/zprox/internal/config"
)
// type ReverseProxy struct {
@ -16,78 +39,127 @@ import (
const CERTS_PATH string = "./assets/certs/"
type App struct {
// Routers struct {
// Maps map[string]*router.HostRouter
// }
// map[string]*router.HostRouter
// Rules map[string]map[string]string
// Services map[string]string
DomainRouters DomainRouters
EntryPoints EntryPoints
}
type DomainRouters map[string]*router.DomainRouter
type EntryPoints map[string]*EntryPoint
type EntryPoint struct {
*server.Server
*router.Router
HostRouters HostRouters
}
type HostRouters map[string]*router.DomainRouter
func New() *App {
return &App{}
}
func (ep EntryPoints) ForEach(f func(string, *EntryPoint)) {
forEach(ep, f)
}
func forEach[K comparable, V any](mp map[K]V, f func(K, V)) {
for k, v := range mp {
f(k, v)
}
}
// main is the entry point of the z application.
// It initializes and configures the application, sets up entry points,
// configures routers, and starts the servers. It also starts test HTTP servers
// for demonstration purposes.
func main() {
helper.AppRunner(true, func() {
// ctx := context.Background()
c := config.NewConfig("config", "yaml", "./assets/config")
c.Load()
helper.Clear()
ctx := context.Background()
app := New()
conf := config.NewConfig()
activeEntryPoints := make(map[string]bool)
conf.EntryPoints.ForEach(func(entryPointName string, entryPointConfig *config.EntryPoint) {
conf.HTTP.Routers.ForEach(func(rName string, rConfig *config.Router) {
if rConfig.EntryPoint == entryPointName {
activeEntryPoints[entryPointName] = true
// routersMap := make(map[string]*router.HostRouter)
routersMap := make(map[string]map[string]string)
firstPart, subKeys := c.GetSubKeys("http.routers", false)
subKeys.ForEach(func(idx int, key config.Key) {
fullKey := helper.AddDotBetween(firstPart, string(key))
p := key.GetKeyPartByLevel(0)
name := string(p)
fmt.Println(name + ":")
if _, ok := routersMap[string(name)]; !ok {
routersMap[string(name)] = make(map[string]string)
}
key.ForEach(func(idx int, part config.KeyPart, isFirst bool) {
if !isFirst {
field := string(part)
val := c.Get(fullKey).(string)
routersMap[string(name)][field] = val
}
})
// router.NewHostRouter("keycloak.z.com")
// router.NewHostRouter("keycloak.z.com").Handler(proxy)
})
dump.Println(routersMap)
conf.EntryPoints.ForEach(func(entryPointName string, entryPointConfig *config.EntryPoint) {
if isUsed, ok := activeEntryPoints[entryPointName]; ok && isUsed {
if _, ok := app.EntryPoints[entryPointName]; !ok {
app.EntryPoints = make(map[string]*EntryPoint)
}
r := router.NewRouter()
_, portStr, _ := strings.Cut(entryPointConfig.Address, ":")
port, _ := strconv.Atoi(portStr)
s := server.New().Name(entryPointName).Port(port)
s.Router(r)
app.EntryPoints[entryPointName] = &EntryPoint{
Server: s,
Router: r,
HostRouters: make(map[string]*router.DomainRouter),
}
}
})
conf.HTTP.Routers.ForEach(func(rName string, rConfig *config.Router) {
if isUsed, ok := activeEntryPoints[rConfig.EntryPoint]; ok && isUsed {
domain := rConfig.Rules.Map["Domain"].Value
serviceURL := conf.HTTP.Services[rConfig.Service].URL
if _, ok := app.EntryPoints[rConfig.EntryPoint]; ok {
entryPoint := app.EntryPoints[rConfig.EntryPoint]
if _, ok := entryPoint.HostRouters[domain]; !ok {
entryPoint.HostRouters = make(map[string]*router.DomainRouter)
}
rpHandler := reverseproxy.New(ctx, serviceURL)
r := app.EntryPoints[rConfig.EntryPoint].Router
hostRouter := r.NewDomainRouter(domain)
hostRouter.Handler(rpHandler)
app.EntryPoints[rConfig.EntryPoint].HostRouters[domain] = hostRouter
}
}
})
app.EntryPoints.ForEach(func(s string, ep *EntryPoint) {
conf.HTTP.Routers.ForEach(func(rName string, rConfig *config.Router) {
if s == rConfig.EntryPoint {
// proxy := reverseproxy.New(ctx, name)
/*******************************************************************************/
// z := zgate.NewGate()
// z.NewEntryPoint("https")
// z.EntryPoints["https"].Port(443).CertKey(CERTS_PATH, "z.com.cert.pem", "z.com.key.pem")
// if err := c.Load(); err != nil {
// log.Fatalln("Error:", err.Error())
// }
/*-------------------------------------------------*/
// rp1 := reverseproxy.New(ctx, "http://localhost:8080")
// rp2 := reverseproxy.New(ctx, "http://localhost:3001")
// rp3 := reverseproxy.New(ctx, "http://localhost:3002")
// router := router.NewRouter()
// pr1 := router.NewHostRouter("keycloak.z.com")
// pr1.Handler(rp1)
// pr2 := router.NewHostRouter("app1.z.com")
// pr2.Handler(rp2)
// pr3 := router.NewHostRouter("app2.z.com")
// pr3.Handler(rp3)
// go func() {
// s := server.New().Name("proxy1").Port(443).Router(router)
// s.CertKey(CERTS_PATH, "z.com.cert.pem", "z.com.key.pem")
// err := s.ListenAndServeTLS()
// if err != nil {
// log.Println(err.Error())
// }
// }()
/*-------------------------------------------------*/
}
})
ep.CertKey(CERTS_PATH, "z.com.cert.pem", "z.com.key.pem")
go ep.ListenAndServeTLS()
})
helper.StartTestHTTPServer(3001, "app1")
helper.StartTestHTTPServer(3002, "app2")
})
}
// func main() {
// Test()
// }
func Test() {
ctx := context.Background()
conf := config.NewConfig()
rp1 := reverseproxy.New(ctx, conf.HTTP.Services["keycloak"].URL)
rp2 := reverseproxy.New(ctx, conf.HTTP.Services["app1"].URL)
rp3 := reverseproxy.New(ctx, conf.HTTP.Services["app2"].URL)
r := router.NewRouter()
r.NewDomainRouter(conf.HTTP.Routers["keycloak"].Rules.Map["Domain"].Value).Handler(rp1)
r.NewDomainRouter(conf.HTTP.Routers["app1"].Rules.Map["Domain"].Value).Handler(rp2)
r.NewDomainRouter(conf.HTTP.Routers["app2"].Rules.Map["Domain"].Value).Handler(rp3)
s := server.New().Name("proxy1").Port(443).Router(r)
s.CertKey(CERTS_PATH, "z.com.cert.pem", "z.com.key.pem")
go s.ListenAndServeTLS()
helper.StartTestHTTPServer(3001, "app1")
helper.StartTestHTTPServer(3002, "app2")
select {}
}

View file

@ -1 +1 @@
exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1
exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1

BIN
tmp/main

Binary file not shown.