From b96cbd393d3901633dc77544d67be61a9d5a3dc5 Mon Sep 17 00:00:00 2001 From: Toha Date: Wed, 15 Jan 2025 15:52:45 +0600 Subject: [PATCH 01/64] tasks init --- pkg/agent/main.go | 14 ++++++-- pkg/controller/main.go | 8 ++--- pkg/k8s/namespace.go | 14 ++++---- pkg/tasks/tasks.go | 78 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+), 14 deletions(-) create mode 100644 pkg/tasks/tasks.go diff --git a/pkg/agent/main.go b/pkg/agent/main.go index 3aa13d7..06ac5cd 100644 --- a/pkg/agent/main.go +++ b/pkg/agent/main.go @@ -3,6 +3,8 @@ package main import ( "context" "fmt" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/tasks" "google.golang.org/grpc/credentials/insecure" "log" "time" @@ -16,6 +18,7 @@ func main() { // For demonstration, we'll just run a single worker that belongs to "GroupA". groupName := "GroupA" authToken := "my-secret" + tasks.InitTaskRegistry() // Dial the controller's gRPC server. conn, err := grpc.NewClient("localhost:50051", grpc.WithTransportCredentials(insecure.NewCredentials())) @@ -64,8 +67,13 @@ func main() { // Here is where you do the actual business logic. // We'll just pretend to do some work and return a result. - go func(taskID, taskPayload string) { + go func(taskID, taskPayload string, task *pb.Task) { // Simulate some processing time. + newTask := tasks.TaskRegistry[task.Name] + execute, _ := newTask.TaskFunc.(func(context.Context, k8s.GetNamespaceListInputParams) (interface{}, error)) + res, err := execute(context.Background(), k8s.GetNamespaceListInputParams{}) + if err != nil { + } time.Sleep(2 * time.Second) // Build the result. @@ -74,7 +82,7 @@ func main() { TaskResult: &pb.TaskResult{ TaskId: taskID, Success: true, - Output: fmt.Sprintf("Processed payload: %s", taskPayload), + Output: fmt.Sprintf("Processed payload: %s", res), }, }, } @@ -83,7 +91,7 @@ func main() { if err := stream.Send(resultMsg); err != nil { log.Printf("Failed to send task result: %v", err) } - }(task.Id, task.Payload) + }(task.Id, task.Payload, task) case *pb.TaskStreamResponse_Ack: log.Printf("Worker received an ACK from server: %s", payload.Ack.Message) diff --git a/pkg/controller/main.go b/pkg/controller/main.go index 40e72fc..e5bee9d 100644 --- a/pkg/controller/main.go +++ b/pkg/controller/main.go @@ -121,7 +121,7 @@ func (s *serverImpl) removeWorker(w *workerConnection) { // sendTaskToWorker sends a task down a particular worker’s stream. // Returns a channel on which the result will be delivered. -func (s *serverImpl) sendTaskToWorker(w *workerConnection, payload string) (<-chan *pb.TaskResult, error) { +func (s *serverImpl) sendTaskToWorker(w *workerConnection, payload string, taskName string) (<-chan *pb.TaskResult, error) { // Generate a task ID. taskID := uuid.NewString() @@ -137,7 +137,7 @@ func (s *serverImpl) sendTaskToWorker(w *workerConnection, payload string) (<-ch Payload: &pb.TaskStreamResponse_NewTask{ NewTask: &pb.Task{ Id: taskID, - Name: "TASK_NAME", + Name: taskName, Payload: payload, }, }, @@ -179,8 +179,8 @@ func (s *serverImpl) httpExecuteHandler(w http.ResponseWriter, r *http.Request) http.Error(w, "No worker in group "+group, http.StatusServiceUnavailable) return } - - resultCh, err := s.sendTaskToWorker(worker, payload) + taskName := "GetNamespaceList" + resultCh, err := s.sendTaskToWorker(worker, payload, taskName) if err != nil { http.Error(w, "Failed to send task to worker: "+err.Error(), http.StatusInternalServerError) return diff --git a/pkg/k8s/namespace.go b/pkg/k8s/namespace.go index c592e4b..25d6062 100644 --- a/pkg/k8s/namespace.go +++ b/pkg/k8s/namespace.go @@ -161,14 +161,14 @@ func (p *GetNamespaceListInputParams) Process(c context.Context) error { } func (namespace *namespaceService) GetNamespaceList(c context.Context, p GetNamespaceListInputParams) (interface{}, error) { - err := p.Process(c) - if err != nil { - return nil, err - } - p.output.Result = p.removeNamespaceListFields() + //err := p.Process(c) + //if err != nil { + // return nil, err + //} + //p.output.Result = p.removeNamespaceListFields() return ResponseDTO{ - Status: "success", - Data: p.output, + Status: "successfully done", + Data: nil, }, nil } diff --git a/pkg/tasks/tasks.go b/pkg/tasks/tasks.go new file mode 100644 index 0000000..0c3164c --- /dev/null +++ b/pkg/tasks/tasks.go @@ -0,0 +1,78 @@ +package tasks + +import ( + "fmt" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "reflect" + "runtime" + "strings" + "time" +) + +//backlog +//Implement hash key later + +type RetryOptions struct { + InitialInterval time.Duration + Interval time.Duration + RetryAttempts int +} + +type Options struct { + Timeout time.Duration + InitialWaitTime time.Duration +} +type Task struct { + TaskId string + TaskName string + TaskGroup interface{} + TaskFunc interface{} + Options Options + RetryOptions RetryOptions +} + +var TaskRegistry = make(map[string]*Task) + +func RegisterTask(funcGroup interface{}, funcTask interface{}) { + task := &Task{TaskFunc: funcTask} + task.TaskName = GetFuncName(funcTask) + task.TaskGroup = funcGroup + fmt.Println("Printing tasks info :" + task.TaskName) + TaskRegistry[task.TaskName] = task + fmt.Println("Printing tasks ...") + fmt.Println(task) + fmt.Println("Printing tasks registry ...") + fmt.Println(TaskRegistry) +} + +func GetTask(taskName string) *Task { + task, ok := TaskRegistry[taskName] + if !ok { + log.Logger.Errorw("Task %s not found") + return nil + } + return task +} + +func InitTaskRegistry() { + RegisterTask(k8s.NamespaceService(), k8s.NamespaceService().GetNamespaceList) +} + +func GetFuncName(funcTask interface{}) string { + functionName := runtime.FuncForPC(reflect.ValueOf(funcTask).Pointer()).Name() + lastDotIndex := strings.LastIndex(functionName, ".") + if lastDotIndex != -1 { + functionName = functionName[lastDotIndex+1:] + } + lastSubsIndex := strings.Index(functionName, "-") + if lastSubsIndex != -1 { + functionName = functionName[:lastSubsIndex] + } + fmt.Println("Printing tasks Actual Name : " + functionName) + return functionName +} + +func GeneratePayloadTask() { + +} From 7cf4e3e8019a4bf5e3c3c7d64b821aed6722f86a Mon Sep 17 00:00:00 2001 From: Toha Date: Thu, 16 Jan 2025 17:09:09 +0600 Subject: [PATCH 02/64] controller input --- pkg/agent/main.go | 14 +++++++++++--- pkg/tasks/tasks.go | 7 ++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/pkg/agent/main.go b/pkg/agent/main.go index 06ac5cd..ece872f 100644 --- a/pkg/agent/main.go +++ b/pkg/agent/main.go @@ -69,10 +69,18 @@ func main() { // We'll just pretend to do some work and return a result. go func(taskID, taskPayload string, task *pb.Task) { // Simulate some processing time. + var res interface{} newTask := tasks.TaskRegistry[task.Name] - execute, _ := newTask.TaskFunc.(func(context.Context, k8s.GetNamespaceListInputParams) (interface{}, error)) - res, err := execute(context.Background(), k8s.GetNamespaceListInputParams{}) - if err != nil { + switch v := newTask.TaskInput.(type) { + case k8s.GetNamespaceInputParams: + fmt.Println("Bhua:", v) + case k8s.GetNamespaceListInputParams: + fmt.Println("Get Namespace List Input Params:", v) + execute, _ := newTask.TaskFunc.(func(context.Context, k8s.GetNamespaceListInputParams) (interface{}, error)) + res, err = execute(context.Background(), k8s.GetNamespaceListInputParams{}) + if err != nil { + log.Printf(err.Error()) + } } time.Sleep(2 * time.Second) diff --git a/pkg/tasks/tasks.go b/pkg/tasks/tasks.go index 0c3164c..7a96ef0 100644 --- a/pkg/tasks/tasks.go +++ b/pkg/tasks/tasks.go @@ -28,16 +28,17 @@ type Task struct { TaskName string TaskGroup interface{} TaskFunc interface{} + TaskInput interface{} Options Options RetryOptions RetryOptions } var TaskRegistry = make(map[string]*Task) -func RegisterTask(funcGroup interface{}, funcTask interface{}) { +func RegisterTask(funcTask interface{}, input interface{}) { task := &Task{TaskFunc: funcTask} task.TaskName = GetFuncName(funcTask) - task.TaskGroup = funcGroup + task.TaskInput = input fmt.Println("Printing tasks info :" + task.TaskName) TaskRegistry[task.TaskName] = task fmt.Println("Printing tasks ...") @@ -56,7 +57,7 @@ func GetTask(taskName string) *Task { } func InitTaskRegistry() { - RegisterTask(k8s.NamespaceService(), k8s.NamespaceService().GetNamespaceList) + RegisterTask(k8s.NamespaceService().GetNamespaceList, k8s.GetNamespaceListInputParams{}) } func GetFuncName(funcTask interface{}) string { From ed147234e0d49a297278752a181be47f0b12a64b Mon Sep 17 00:00:00 2001 From: Toha Date: Mon, 20 Jan 2025 19:27:17 +0600 Subject: [PATCH 03/64] controller input --- go.mod | 22 ++- go.sum | 51 +++++- pkg/agent/main.go | 5 +- pkg/common/pb/controller.pb.go | 271 ++++++++++------------------ pkg/common/pb/controller.proto | 1 + pkg/common/pb/controller_grpc.pb.go | 88 ++++----- pkg/config/config.go | 1 + pkg/controller/main.go | 9 +- pkg/server/router/routes.go | 20 ++ pkg/server/server.go | 33 ++++ 10 files changed, 262 insertions(+), 239 deletions(-) create mode 100644 pkg/server/router/routes.go create mode 100644 pkg/server/server.go diff --git a/go.mod b/go.mod index fa8be0e..cd7f4ee 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,8 @@ module github.com/krack8/lighthouse go 1.23.0 require ( + github.com/gin-contrib/cors v1.7.3 + github.com/gin-gonic/gin v1.10.0 github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.0 github.com/kubernetes-csi/external-snapshotter/client/v6 v6.3.0 @@ -32,8 +34,12 @@ require ( github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect + github.com/bytedance/sonic v1.12.6 // indirect + github.com/bytedance/sonic/loader v0.2.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect github.com/containerd/containerd v1.7.23 // indirect github.com/containerd/errdefs v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect @@ -53,6 +59,8 @@ require ( github.com/fatih/color v1.13.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.7 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect github.com/go-logr/logr v1.4.2 // indirect @@ -60,7 +68,11 @@ require ( github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.23.0 // indirect github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-json v0.10.4 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.0.1 // indirect @@ -79,13 +91,15 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.16.7 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect @@ -100,6 +114,7 @@ require ( github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect @@ -114,6 +129,8 @@ require ( github.com/spf13/cast v1.7.0 // indirect github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect @@ -125,8 +142,9 @@ require ( go.opentelemetry.io/otel/trace v1.31.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect go.uber.org/multierr v1.11.0 // indirect + golang.org/x/arch v0.12.0 // indirect golang.org/x/crypto v0.31.0 // indirect - golang.org/x/net v0.30.0 // indirect + golang.org/x/net v0.33.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect diff --git a/go.sum b/go.sum index 4e753bb..2f11fd6 100644 --- a/go.sum +++ b/go.sum @@ -48,6 +48,11 @@ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembj github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/bytedance/sonic v1.12.6 h1:/isNmCUF2x3Sh8RAp/4mh4ZGkcFAX/hLrzrK3AvpRzk= +github.com/bytedance/sonic v1.12.6/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E= +github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -57,6 +62,10 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= github.com/containerd/containerd v1.7.23 h1:H2CClyUkmpKAGlhQp95g2WXHfLYc7whAuvZGBNYOOwQ= @@ -117,6 +126,14 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA= +github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU= +github.com/gin-contrib/cors v1.7.3 h1:hV+a5xp8hwJoTw7OY+a70FsL8JkVVFTXw9EcfrYUdns= +github.com/gin-contrib/cors v1.7.3/go.mod h1:M3bcKZhxzsvI+rlRSkkxHyljJt1ESd93COUvemZ79j4= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= @@ -137,6 +154,14 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o= +github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -144,6 +169,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= +github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -220,6 +247,10 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -235,6 +266,8 @@ github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= @@ -247,8 +280,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= @@ -294,6 +327,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= @@ -358,6 +393,10 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -399,6 +438,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/arch v0.12.0 h1:UsYJhbzPYGsT0HbEdmYcqtCv8UNGvnaL561NnIUvaKg= +golang.org/x/arch v0.12.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -423,8 +464,8 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= -golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= @@ -450,6 +491,7 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -547,6 +589,7 @@ k8s.io/metrics v0.32.0 h1:70qJ3ZS/9DrtH0UA0NVBI6gW2ip2GAn9e7NtoKERpns= k8s.io/metrics v0.32.0/go.mod h1:skdg9pDjVjCPIQqmc5rBzDL4noY64ORhKu9KCPv1+QI= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= oras.land/oras-go v1.2.5 h1:XpYuAwAb0DfQsunIyMfeET92emK8km3W4yEzZvUbsTo= oras.land/oras-go v1.2.5/go.mod h1:PuAwRShRZCsZb7g8Ar3jKKQR/2A/qN+pkYxIOd/FAoo= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= diff --git a/pkg/agent/main.go b/pkg/agent/main.go index ece872f..727db92 100644 --- a/pkg/agent/main.go +++ b/pkg/agent/main.go @@ -2,6 +2,7 @@ package main import ( "context" + "encoding/json" "fmt" "github.com/krack8/lighthouse/pkg/k8s" "github.com/krack8/lighthouse/pkg/tasks" @@ -29,7 +30,6 @@ func main() { defer conn.Close() client := pb.NewControllerClient(conn) - // Open the bi-directional stream. stream, err := client.TaskStream(context.Background()) if err != nil { @@ -75,7 +75,10 @@ func main() { case k8s.GetNamespaceInputParams: fmt.Println("Bhua:", v) case k8s.GetNamespaceListInputParams: + input := k8s.GetNamespaceListInputParams{} + _ = json.Unmarshal([]byte(task.Input), &input) fmt.Println("Get Namespace List Input Params:", v) + fmt.Println(input.Limit, input.Search) execute, _ := newTask.TaskFunc.(func(context.Context, k8s.GetNamespaceListInputParams) (interface{}, error)) res, err = execute(context.Background(), k8s.GetNamespaceListInputParams{}) if err != nil { diff --git a/pkg/common/pb/controller.pb.go b/pkg/common/pb/controller.pb.go index 2c23240..755a58b 100644 --- a/pkg/common/pb/controller.pb.go +++ b/pkg/common/pb/controller.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.0 +// protoc-gen-go v1.36.3 +// protoc v5.29.3 // source: pkg/common/pb/controller.proto package pb @@ -24,24 +24,21 @@ const ( // 1. WorkerIdentification: "I belong to group X, here is my auth token" // 2. TaskResult: "I finished task , here is the result" type TaskStreamRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Payload: + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Payload: // // *TaskStreamRequest_WorkerInfo // *TaskStreamRequest_TaskResult - Payload isTaskStreamRequest_Payload `protobuf_oneof:"payload"` + Payload isTaskStreamRequest_Payload `protobuf_oneof:"payload"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *TaskStreamRequest) Reset() { *x = TaskStreamRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_common_pb_controller_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_pkg_common_pb_controller_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *TaskStreamRequest) String() string { @@ -52,7 +49,7 @@ func (*TaskStreamRequest) ProtoMessage() {} func (x *TaskStreamRequest) ProtoReflect() protoreflect.Message { mi := &file_pkg_common_pb_controller_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -67,23 +64,27 @@ func (*TaskStreamRequest) Descriptor() ([]byte, []int) { return file_pkg_common_pb_controller_proto_rawDescGZIP(), []int{0} } -func (m *TaskStreamRequest) GetPayload() isTaskStreamRequest_Payload { - if m != nil { - return m.Payload +func (x *TaskStreamRequest) GetPayload() isTaskStreamRequest_Payload { + if x != nil { + return x.Payload } return nil } func (x *TaskStreamRequest) GetWorkerInfo() *WorkerIdentification { - if x, ok := x.GetPayload().(*TaskStreamRequest_WorkerInfo); ok { - return x.WorkerInfo + if x != nil { + if x, ok := x.Payload.(*TaskStreamRequest_WorkerInfo); ok { + return x.WorkerInfo + } } return nil } func (x *TaskStreamRequest) GetTaskResult() *TaskResult { - if x, ok := x.GetPayload().(*TaskStreamRequest_TaskResult); ok { - return x.TaskResult + if x != nil { + if x, ok := x.Payload.(*TaskStreamRequest_TaskResult); ok { + return x.TaskResult + } } return nil } @@ -105,21 +106,18 @@ func (*TaskStreamRequest_WorkerInfo) isTaskStreamRequest_Payload() {} func (*TaskStreamRequest_TaskResult) isTaskStreamRequest_Payload() {} type WorkerIdentification struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + GroupName string `protobuf:"bytes,1,opt,name=group_name,json=groupName,proto3" json:"group_name,omitempty"` + AuthToken string `protobuf:"bytes,2,opt,name=auth_token,json=authToken,proto3" json:"auth_token,omitempty"` // could be a token or JWT, etc. unknownFields protoimpl.UnknownFields - - GroupName string `protobuf:"bytes,1,opt,name=group_name,json=groupName,proto3" json:"group_name,omitempty"` - AuthToken string `protobuf:"bytes,2,opt,name=auth_token,json=authToken,proto3" json:"auth_token,omitempty"` // could be a token or JWT, etc. + sizeCache protoimpl.SizeCache } func (x *WorkerIdentification) Reset() { *x = WorkerIdentification{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_common_pb_controller_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_pkg_common_pb_controller_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *WorkerIdentification) String() string { @@ -130,7 +128,7 @@ func (*WorkerIdentification) ProtoMessage() {} func (x *WorkerIdentification) ProtoReflect() protoreflect.Message { mi := &file_pkg_common_pb_controller_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -160,22 +158,19 @@ func (x *WorkerIdentification) GetAuthToken() string { } type TaskResult struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + TaskId string `protobuf:"bytes,1,opt,name=task_id,json=taskId,proto3" json:"task_id,omitempty"` + Success bool `protobuf:"varint,2,opt,name=success,proto3" json:"success,omitempty"` + Output string `protobuf:"bytes,3,opt,name=output,proto3" json:"output,omitempty"` unknownFields protoimpl.UnknownFields - - TaskId string `protobuf:"bytes,1,opt,name=task_id,json=taskId,proto3" json:"task_id,omitempty"` - Success bool `protobuf:"varint,2,opt,name=success,proto3" json:"success,omitempty"` - Output string `protobuf:"bytes,3,opt,name=output,proto3" json:"output,omitempty"` + sizeCache protoimpl.SizeCache } func (x *TaskResult) Reset() { *x = TaskResult{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_common_pb_controller_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_pkg_common_pb_controller_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *TaskResult) String() string { @@ -186,7 +181,7 @@ func (*TaskResult) ProtoMessage() {} func (x *TaskResult) ProtoReflect() protoreflect.Message { mi := &file_pkg_common_pb_controller_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -226,24 +221,21 @@ func (x *TaskResult) GetOutput() string { // 1. Task: "Please execute this task with ID and some payload" // 2. Ack: "Acknowledgement for something, or simple keepalive" type TaskStreamResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Payload: + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Payload: // // *TaskStreamResponse_NewTask // *TaskStreamResponse_Ack - Payload isTaskStreamResponse_Payload `protobuf_oneof:"payload"` + Payload isTaskStreamResponse_Payload `protobuf_oneof:"payload"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *TaskStreamResponse) Reset() { *x = TaskStreamResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_common_pb_controller_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_pkg_common_pb_controller_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *TaskStreamResponse) String() string { @@ -254,7 +246,7 @@ func (*TaskStreamResponse) ProtoMessage() {} func (x *TaskStreamResponse) ProtoReflect() protoreflect.Message { mi := &file_pkg_common_pb_controller_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -269,23 +261,27 @@ func (*TaskStreamResponse) Descriptor() ([]byte, []int) { return file_pkg_common_pb_controller_proto_rawDescGZIP(), []int{3} } -func (m *TaskStreamResponse) GetPayload() isTaskStreamResponse_Payload { - if m != nil { - return m.Payload +func (x *TaskStreamResponse) GetPayload() isTaskStreamResponse_Payload { + if x != nil { + return x.Payload } return nil } func (x *TaskStreamResponse) GetNewTask() *Task { - if x, ok := x.GetPayload().(*TaskStreamResponse_NewTask); ok { - return x.NewTask + if x != nil { + if x, ok := x.Payload.(*TaskStreamResponse_NewTask); ok { + return x.NewTask + } } return nil } func (x *TaskStreamResponse) GetAck() *Ack { - if x, ok := x.GetPayload().(*TaskStreamResponse_Ack); ok { - return x.Ack + if x != nil { + if x, ok := x.Payload.(*TaskStreamResponse_Ack); ok { + return x.Ack + } } return nil } @@ -307,22 +303,20 @@ func (*TaskStreamResponse_NewTask) isTaskStreamResponse_Payload() {} func (*TaskStreamResponse_Ack) isTaskStreamResponse_Payload() {} type Task struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Payload string `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"` + Input string `protobuf:"bytes,4,opt,name=input,proto3" json:"input,omitempty"` unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Payload string `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Task) Reset() { *x = Task{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_common_pb_controller_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_pkg_common_pb_controller_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Task) String() string { @@ -333,7 +327,7 @@ func (*Task) ProtoMessage() {} func (x *Task) ProtoReflect() protoreflect.Message { mi := &file_pkg_common_pb_controller_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -369,21 +363,25 @@ func (x *Task) GetPayload() string { return "" } +func (x *Task) GetInput() string { + if x != nil { + return x.Input + } + return "" +} + type Ack struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` unknownFields protoimpl.UnknownFields - - Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Ack) Reset() { *x = Ack{} - if protoimpl.UnsafeEnabled { - mi := &file_pkg_common_pb_controller_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_pkg_common_pb_controller_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Ack) String() string { @@ -394,7 +392,7 @@ func (*Ack) ProtoMessage() {} func (x *Ack) ProtoReflect() protoreflect.Message { mi := &file_pkg_common_pb_controller_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -447,20 +445,21 @@ var file_pkg_common_pb_controller_proto_rawDesc = []byte{ 0x62, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x07, 0x6e, 0x65, 0x77, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x1b, 0x0a, 0x03, 0x61, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x07, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x63, 0x6b, 0x48, 0x00, 0x52, 0x03, 0x61, 0x63, 0x6b, 0x42, 0x09, - 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x44, 0x0a, 0x04, 0x54, 0x61, 0x73, + 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x5a, 0x0a, 0x04, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, - 0x1f, 0x0a, 0x03, 0x41, 0x63, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x32, 0x4d, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x12, 0x3f, - 0x0a, 0x0a, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x15, 0x2e, 0x70, - 0x62, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, - 0x0f, 0x5a, 0x0d, 0x70, 0x6b, 0x67, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x62, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, + 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x22, 0x1f, 0x0a, 0x03, 0x41, 0x63, 0x6b, 0x12, 0x18, 0x0a, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x4d, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x0a, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x12, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x62, 0x2e, 0x54, + 0x61, 0x73, 0x6b, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0x0f, 0x5a, 0x0d, 0x70, 0x6b, 0x67, 0x2f, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -476,7 +475,7 @@ func file_pkg_common_pb_controller_proto_rawDescGZIP() []byte { } var file_pkg_common_pb_controller_proto_msgTypes = make([]protoimpl.MessageInfo, 6) -var file_pkg_common_pb_controller_proto_goTypes = []interface{}{ +var file_pkg_common_pb_controller_proto_goTypes = []any{ (*TaskStreamRequest)(nil), // 0: pb.TaskStreamRequest (*WorkerIdentification)(nil), // 1: pb.WorkerIdentification (*TaskResult)(nil), // 2: pb.TaskResult @@ -503,85 +502,11 @@ func file_pkg_common_pb_controller_proto_init() { if File_pkg_common_pb_controller_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_pkg_common_pb_controller_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TaskStreamRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pkg_common_pb_controller_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WorkerIdentification); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pkg_common_pb_controller_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TaskResult); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pkg_common_pb_controller_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TaskStreamResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pkg_common_pb_controller_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Task); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pkg_common_pb_controller_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Ack); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_pkg_common_pb_controller_proto_msgTypes[0].OneofWrappers = []interface{}{ + file_pkg_common_pb_controller_proto_msgTypes[0].OneofWrappers = []any{ (*TaskStreamRequest_WorkerInfo)(nil), (*TaskStreamRequest_TaskResult)(nil), } - file_pkg_common_pb_controller_proto_msgTypes[3].OneofWrappers = []interface{}{ + file_pkg_common_pb_controller_proto_msgTypes[3].OneofWrappers = []any{ (*TaskStreamResponse_NewTask)(nil), (*TaskStreamResponse_Ack)(nil), } diff --git a/pkg/common/pb/controller.proto b/pkg/common/pb/controller.proto index 54c1e5e..350d0b7 100644 --- a/pkg/common/pb/controller.proto +++ b/pkg/common/pb/controller.proto @@ -47,6 +47,7 @@ message Task { string id = 1; string name = 2; string payload = 3; + string input = 4; } message Ack { diff --git a/pkg/common/pb/controller_grpc.pb.go b/pkg/common/pb/controller_grpc.pb.go index 38c6b97..72bad0c 100644 --- a/pkg/common/pb/controller_grpc.pb.go +++ b/pkg/common/pb/controller_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.25.0 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.29.3 // source: pkg/common/pb/controller.proto package pb @@ -15,8 +15,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( Controller_TaskStream_FullMethodName = "/pb.Controller/TaskStream" @@ -26,7 +26,7 @@ const ( // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type ControllerClient interface { - TaskStream(ctx context.Context, opts ...grpc.CallOption) (Controller_TaskStreamClient, error) + TaskStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[TaskStreamRequest, TaskStreamResponse], error) } type controllerClient struct { @@ -37,53 +37,39 @@ func NewControllerClient(cc grpc.ClientConnInterface) ControllerClient { return &controllerClient{cc} } -func (c *controllerClient) TaskStream(ctx context.Context, opts ...grpc.CallOption) (Controller_TaskStreamClient, error) { - stream, err := c.cc.NewStream(ctx, &Controller_ServiceDesc.Streams[0], Controller_TaskStream_FullMethodName, opts...) +func (c *controllerClient) TaskStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[TaskStreamRequest, TaskStreamResponse], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &Controller_ServiceDesc.Streams[0], Controller_TaskStream_FullMethodName, cOpts...) if err != nil { return nil, err } - x := &controllerTaskStreamClient{stream} + x := &grpc.GenericClientStream[TaskStreamRequest, TaskStreamResponse]{ClientStream: stream} return x, nil } -type Controller_TaskStreamClient interface { - Send(*TaskStreamRequest) error - Recv() (*TaskStreamResponse, error) - grpc.ClientStream -} - -type controllerTaskStreamClient struct { - grpc.ClientStream -} - -func (x *controllerTaskStreamClient) Send(m *TaskStreamRequest) error { - return x.ClientStream.SendMsg(m) -} - -func (x *controllerTaskStreamClient) Recv() (*TaskStreamResponse, error) { - m := new(TaskStreamResponse) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type Controller_TaskStreamClient = grpc.BidiStreamingClient[TaskStreamRequest, TaskStreamResponse] // ControllerServer is the server API for Controller service. // All implementations must embed UnimplementedControllerServer -// for forward compatibility +// for forward compatibility. type ControllerServer interface { - TaskStream(Controller_TaskStreamServer) error + TaskStream(grpc.BidiStreamingServer[TaskStreamRequest, TaskStreamResponse]) error mustEmbedUnimplementedControllerServer() } -// UnimplementedControllerServer must be embedded to have forward compatible implementations. -type UnimplementedControllerServer struct { -} +// UnimplementedControllerServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedControllerServer struct{} -func (UnimplementedControllerServer) TaskStream(Controller_TaskStreamServer) error { +func (UnimplementedControllerServer) TaskStream(grpc.BidiStreamingServer[TaskStreamRequest, TaskStreamResponse]) error { return status.Errorf(codes.Unimplemented, "method TaskStream not implemented") } func (UnimplementedControllerServer) mustEmbedUnimplementedControllerServer() {} +func (UnimplementedControllerServer) testEmbeddedByValue() {} // UnsafeControllerServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to ControllerServer will @@ -93,34 +79,22 @@ type UnsafeControllerServer interface { } func RegisterControllerServer(s grpc.ServiceRegistrar, srv ControllerServer) { + // If the following call pancis, it indicates UnimplementedControllerServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Controller_ServiceDesc, srv) } func _Controller_TaskStream_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(ControllerServer).TaskStream(&controllerTaskStreamServer{stream}) -} - -type Controller_TaskStreamServer interface { - Send(*TaskStreamResponse) error - Recv() (*TaskStreamRequest, error) - grpc.ServerStream -} - -type controllerTaskStreamServer struct { - grpc.ServerStream + return srv.(ControllerServer).TaskStream(&grpc.GenericServerStream[TaskStreamRequest, TaskStreamResponse]{ServerStream: stream}) } -func (x *controllerTaskStreamServer) Send(m *TaskStreamResponse) error { - return x.ServerStream.SendMsg(m) -} - -func (x *controllerTaskStreamServer) Recv() (*TaskStreamRequest, error) { - m := new(TaskStreamRequest) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type Controller_TaskStreamServer = grpc.BidiStreamingServer[TaskStreamRequest, TaskStreamResponse] // Controller_ServiceDesc is the grpc.ServiceDesc for Controller service. // It's only intended for direct use with grpc.RegisterService, diff --git a/pkg/config/config.go b/pkg/config/config.go index 4dfde07..c8d7fdb 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -1,3 +1,4 @@ package config +var ServerPort = "8080" var PageLimit = int64(10) diff --git a/pkg/controller/main.go b/pkg/controller/main.go index e5bee9d..416b46b 100644 --- a/pkg/controller/main.go +++ b/pkg/controller/main.go @@ -1,7 +1,9 @@ package main import ( + "encoding/json" "fmt" + "github.com/krack8/lighthouse/pkg/k8s" "log" "net" "net/http" @@ -121,7 +123,7 @@ func (s *serverImpl) removeWorker(w *workerConnection) { // sendTaskToWorker sends a task down a particular worker’s stream. // Returns a channel on which the result will be delivered. -func (s *serverImpl) sendTaskToWorker(w *workerConnection, payload string, taskName string) (<-chan *pb.TaskResult, error) { +func (s *serverImpl) sendTaskToWorker(w *workerConnection, payload string, taskName string, input []byte) (<-chan *pb.TaskResult, error) { // Generate a task ID. taskID := uuid.NewString() @@ -139,6 +141,7 @@ func (s *serverImpl) sendTaskToWorker(w *workerConnection, payload string, taskN Id: taskID, Name: taskName, Payload: payload, + Input: string(input), }, }, }) @@ -180,7 +183,9 @@ func (s *serverImpl) httpExecuteHandler(w http.ResponseWriter, r *http.Request) return } taskName := "GetNamespaceList" - resultCh, err := s.sendTaskToWorker(worker, payload, taskName) + input, _ := json.Marshal(k8s.GetNamespaceListInputParams{Search: "hola", Limit: "10"}) + + resultCh, err := s.sendTaskToWorker(worker, payload, taskName, input) if err != nil { http.Error(w, "Failed to send task to worker: "+err.Error(), http.StatusInternalServerError) return diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go new file mode 100644 index 0000000..3ccea24 --- /dev/null +++ b/pkg/server/router/routes.go @@ -0,0 +1,20 @@ +package router + +import ( + "github.com/gin-gonic/gin" +) + +// @title Swagger API +// @version 1.0 + +// @host localhost:8080 +// @BasePath /api + +// @securityDefinitions.apikey ApiKeyAuth +// @in header +// @name Authorization + +func AddApiRoutes(httpRg *gin.RouterGroup) { + // Namespace + //httpRg.GET("api/v1/namespace", k8s.NamespaceController().GetNamespaceList) +} diff --git a/pkg/server/server.go b/pkg/server/server.go new file mode 100644 index 0000000..b85a66d --- /dev/null +++ b/pkg/server/server.go @@ -0,0 +1,33 @@ +package server + +import ( + "github.com/gin-contrib/cors" + "github.com/gin-gonic/gin" + cfg "github.com/krack8/lighthouse/pkg/config" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/server/router" + "net/http" +) + +func Start() { + //gin.DisableConsoleColor() + r := gin.Default() + corsConfig := cors.DefaultConfig() + corsConfig.AllowOrigins = []string{"*", "http://localhost:4200"} + corsConfig.AllowMethods = []string{http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete} + corsConfig.AllowCredentials = true + corsConfig.AllowHeaders = []string{"Origin", "*"} + corsConfig.AddAllowMethods("OPTIONS") + r.Use(cors.New(corsConfig), gin.LoggerWithWriter(gin.DefaultWriter, "/health", "/swagger/*any")) + // Setting API Base Path for HTTP APIs + httpRouter := r.Group("/") + //r.GET("/ws/v1/pod/logs/:name", v1.PodController().GetPodStreamLogs) + // Setting up all Http Routes + router.AddApiRoutes(httpRouter) + //r.GET("/health", api.Home().Health) + //r.GET("/", api.Home().Index) + err := r.Run(":" + cfg.ServerPort) // listen and serve on 0.0.0.0:8080 + if err != nil { + log.Logger.Errorw("Failed to start server", "err", err.Error()) + } +} From 6bfb84c33cfbd8c533da44a156d5a2310369eff8 Mon Sep 17 00:00:00 2001 From: Toha Date: Tue, 21 Jan 2025 18:42:40 +0600 Subject: [PATCH 04/64] controller gin --- pkg/context/context.go | 72 ++++++++++++ .../{main.go => agent_controller.go} | 88 ++++++++++++--- pkg/controller/namespace.go | 76 +++++++++++++ pkg/k8s/k8s.go | 104 ++++++++++++++++-- pkg/master/main.go | 19 ++++ pkg/server/router/routes.go | 3 +- pkg/server/server.go | 4 +- pkg/tasks/tasks.go | 15 +++ 8 files changed, 354 insertions(+), 27 deletions(-) create mode 100644 pkg/context/context.go rename pkg/controller/{main.go => agent_controller.go} (77%) create mode 100644 pkg/controller/namespace.go create mode 100644 pkg/master/main.go diff --git a/pkg/context/context.go b/pkg/context/context.go new file mode 100644 index 0000000..3a24935 --- /dev/null +++ b/pkg/context/context.go @@ -0,0 +1,72 @@ +package context + +import ( + "encoding/json" + "fmt" + "github.com/gin-gonic/gin" +) + +const ( + WsConnId = "WsConnId" + WsMsgId = "WsMsgId" + WsApiInput = "WsApiInput" + UserKey = "User" +) + +func IsRequestFromWS(c *gin.Context) bool { + if c.Keys == nil { + return false + } + _, exists := c.Get(WsConnId) + return exists +} + +func AddWsConnIdToContext(c *gin.Context, val interface{}) { + c.Set(WsConnId, val) +} + +func GetWsConnId(c *gin.Context) string { + if msgId, exists := c.Get(WsConnId); exists { + return fmt.Sprintf("%v", msgId) + } + return "" +} + +func AddRequestMsgIdToContext(c *gin.Context, val interface{}) { + c.Set(WsMsgId, val) +} + +func GetRequestMsgId(c *gin.Context) string { + if msgId, exists := c.Get(WsMsgId); exists { + return fmt.Sprintf("%v", msgId) + } + return "" +} + +func AddInputToContext(c *gin.Context, input interface{}) { + c.Set(WsApiInput, input) +} + +func GetInputFromContext(c *gin.Context, in interface{}) error { + // Binding input from context request if http + if !IsRequestFromWS(c) { + err := c.BindJSON(in) + return err + } + + input, exists := c.Get(WsApiInput) + if !exists { + return nil + } + + // Binding input from context keys if websocket + inputRaw, err := json.Marshal(input) + if err != nil { + return err + } + err = json.Unmarshal(inputRaw, in) + if err != nil { + return err + } + return nil +} diff --git a/pkg/controller/main.go b/pkg/controller/agent_controller.go similarity index 77% rename from pkg/controller/main.go rename to pkg/controller/agent_controller.go index 416b46b..5dd66f5 100644 --- a/pkg/controller/main.go +++ b/pkg/controller/agent_controller.go @@ -1,20 +1,34 @@ -package main +package controller import ( + "context" "encoding/json" + "errors" "fmt" + "github.com/google/uuid" + "github.com/krack8/lighthouse/pkg/common/pb" "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/tasks" + "google.golang.org/grpc" "log" "net" "net/http" "sync" "time" - - "github.com/google/uuid" - "github.com/krack8/lighthouse/pkg/common/pb" // Import the generated proto package - "google.golang.org/grpc" ) +type TaskToAgentInterface interface { + SendToWorker(c context.Context, groupName string, payload string, taskName string, input []byte) (*pb.TaskResult, error) +} + +type taskToAgent struct{} + +var tta taskToAgent + +func TaskToAgent() *taskToAgent { + return &tta +} + // workerConnection represents one worker's active streaming connection. type workerConnection struct { stream pb.Controller_TaskStreamServer @@ -25,7 +39,6 @@ type workerConnection struct { // serverImpl implements the pb.ControllerServer interface. type serverImpl struct { pb.UnimplementedControllerServer - mu sync.Mutex groups map[string][]*workerConnection // groupName -> slice of workers } @@ -168,6 +181,56 @@ func (s *serverImpl) pickWorker(groupName string) *workerConnection { return workers[0] } +func (s *serverImpl) Process(groupName string, payload string, taskName string, input []byte) (<-chan *pb.TaskResult, error) { + w := s.pickWorker(groupName) + if w == nil { + return nil, errors.New("worker unreachable") + } + // Generate a task ID. + taskID := uuid.NewString() + + // Prepare a channel to receive the worker’s response. + resultCh := make(chan *pb.TaskResult, 1) + + s.mu.Lock() + w.resultChMap[taskID] = resultCh + s.mu.Unlock() + + // Actually send the task to the worker. + err := w.stream.Send(&pb.TaskStreamResponse{ + Payload: &pb.TaskStreamResponse_NewTask{ + NewTask: &pb.Task{ + Id: taskID, + Name: taskName, + Payload: payload, + Input: string(input), + }, + }, + }) + if err != nil { + s.mu.Lock() + delete(w.resultChMap, taskID) + s.mu.Unlock() + return nil, err + } + + return resultCh, nil +} + +func (tta *taskToAgent) SendToWorker(c context.Context, groupName string, payload string, taskName string, input []byte) (*pb.TaskResult, error) { + resultCh, err := srv.Process(groupName, payload, taskName, input) + if err != nil { + return nil, err + } + select { + case res := <-resultCh: + // Send response to the user + return res, nil + case <-time.After(10 * time.Second): + return nil, errors.New("timed out waiting for worker result") + } +} + // HTTP handler: /execute?group=GroupA&payload=SomeData func (s *serverImpl) httpExecuteHandler(w http.ResponseWriter, r *http.Request) { group := r.URL.Query().Get("group") @@ -183,6 +246,7 @@ func (s *serverImpl) httpExecuteHandler(w http.ResponseWriter, r *http.Request) return } taskName := "GetNamespaceList" + tasks.GetCurrentTaskName() input, _ := json.Marshal(k8s.GetNamespaceListInputParams{Search: "hola", Limit: "10"}) resultCh, err := s.sendTaskToWorker(worker, payload, taskName, input) @@ -202,11 +266,11 @@ func (s *serverImpl) httpExecuteHandler(w http.ResponseWriter, r *http.Request) } } -func main() { - srv := &serverImpl{ - groups: make(map[string][]*workerConnection), - } +var srv = &serverImpl{ + groups: make(map[string][]*workerConnection), +} +func StartGrpcServer() { // Start gRPC server go func() { grpcServer := grpc.NewServer() @@ -221,9 +285,5 @@ func main() { log.Fatalf("Failed to serve gRPC: %v", err) } }() - - // Start HTTP server http.HandleFunc("/execute", srv.httpExecuteHandler) - log.Println("HTTP server listening on :8080") - log.Fatal(http.ListenAndServe(":8080", nil)) } diff --git a/pkg/controller/namespace.go b/pkg/controller/namespace.go new file mode 100644 index 0000000..ee66166 --- /dev/null +++ b/pkg/controller/namespace.go @@ -0,0 +1,76 @@ +package controller + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" +) + +type NamespaceControllerInterface interface { + GetNamespaceList(ctx *gin.Context) + //GetNamespaceNameList(ctx *gin.Context) + //GetNamespaceDetails(ctx *gin.Context) + //DeployNamespace(ctx *gin.Context) + //DeleteNamespace(ctx *gin.Context) +} + +type namespaceController struct { +} + +var nsc namespaceController + +func NamespaceController() *namespaceController { + return &nsc +} + +func (ctrl *namespaceController) GetNamespaceList(ctx *gin.Context) { + var result k8s.ResponseDTO + + input := new(k8s.GetNamespaceListInputParams) + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Errorw("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Infow("Filter by param for Namespace List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + taskName := tasks.GetCurrentTaskName() + inputTask, err := json.Marshal(input) + if err != nil { + log.Logger.Errorw("unable to marshal GetNamespaceList Task input ", "err", err.Error()) + } + log.Logger.Debugw("GetNamespaceList task started...", "Task", "GetNamespaceList") + group := ctx.Query("group") + payload := ctx.Query("payload") + if group == "" || payload == "" { + k8s.SendErrorResponse(ctx, "Missing group or payload param") + return + } + result.Data, err = TaskToAgent().SendToWorker(ctx, group, payload, taskName, inputTask) + if err != nil { + k8s.SendErrorResponse(ctx, err.Error()) + } + k8s.SendResponse(ctx, result) + + //err = we.Get(ctx, &result) + //if err != nil { + // log.Logger.Errorw("Unable to get result for GetNamespaceList", "err", err, "wid", we.GetID(), "rid", we.GetRunID()) + //} + // + //k8s.SendResponse(ctx, result) +} diff --git a/pkg/k8s/k8s.go b/pkg/k8s/k8s.go index 2175d3f..9c4518f 100644 --- a/pkg/k8s/k8s.go +++ b/pkg/k8s/k8s.go @@ -1,11 +1,12 @@ package k8s import ( - "context" "errors" "fmt" + "github.com/gin-gonic/gin" + "net/http" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/krack8/lighthouse/pkg/context" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" ) @@ -48,15 +49,98 @@ func GetClientset() *kubernetes.Clientset { return clientset } -func ListNamespaces(clientset kubernetes.Interface) ([]string, error) { - namespaces, err := clientset.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{}) - if err != nil { - return nil, fmt.Errorf("failed to list namespaces: %w", err) +//func ListNamespaces(clientset kubernetes.Interface) ([]string, error) { +// namespaces, err := clientset.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{}) +// if err != nil { +// return nil, fmt.Errorf("failed to list namespaces: %w", err) +// } +// +// var namespaceNames []string +// for _, ns := range namespaces.Items { +// namespaceNames = append(namespaceNames, ns.Name) +// } +// return namespaceNames, nil +//} + +var nilResponse ResponseDTO = ResponseDTO{} + +var ( + UserAuthenticatedMsg = "User authenticated" + UserLoggedOutMsg = "Logged out from lighthouse" + ErrNamespaceEmpty = "namespace field empty" + ClearRedis = "role cleared" +) + +var httpStatusMap = map[string]int{ + "success": http.StatusOK, + "error": http.StatusBadRequest, +} + +func NilResponse() ResponseDTO { + return nilResponse +} + +func ErrorResponse(err error) (ResponseDTO, error) { + return ResponseDTO{ + Status: "error", + Msg: err.Error(), + }, nil +} + +func SuccessResponse(data interface{}) (ResponseDTO, error) { + return ResponseDTO{ + Status: "success", + Data: data, + }, nil +} + +func executeSendResponse(c *gin.Context, data interface{}, httpStatus int) { + sendHttpResponse(c, data, httpStatus) +} + +func SendResponse(c *gin.Context, response ResponseDTO) { + executeSendResponse(c, response, httpStatusMap[response.Status]) +} + +func SendErrorResponse(c *gin.Context, msg string) { + data := gin.H{ + "status": http.StatusBadRequest, + "msg": msg, + } + if context.IsRequestFromWS(c) { + data["msgId"] = context.GetRequestMsgId(c) } + executeSendResponse(c, data, http.StatusBadRequest) +} - var namespaceNames []string - for _, ns := range namespaces.Items { - namespaceNames = append(namespaceNames, ns.Name) +func sendHttpResponse(c *gin.Context, data interface{}, httpStatus int) { + c.JSON(httpStatus, data) +} + +func SendForbiddenResponse(c *gin.Context, msg string) { + data := gin.H{ + "status": http.StatusForbidden, + "msg": msg, + } + if context.IsRequestFromWS(c) { + data["msgId"] = context.GetRequestMsgId(c) } - return namespaceNames, nil + executeSendResponse(c, data, http.StatusForbidden) +} + +//func SendSuccessResponse(c *gin.Context, response ResponseDTO) { +// response.Status = "success" +// data := gin.H{ +// "status": http.StatusOK, +// "data": response, +// } +// if context.IsRequestFromWS(c) { +// data["msgId"] = context.GetRequestMsgId(c) +// } +// executeSendResponse(c, data, http.StatusOK) +//} + +func SendSuccessResponse(c *gin.Context, response ResponseDTO) { + response.Status = "success" + executeSendResponse(c, response, httpStatusMap[response.Status]) } diff --git a/pkg/master/main.go b/pkg/master/main.go new file mode 100644 index 0000000..3990377 --- /dev/null +++ b/pkg/master/main.go @@ -0,0 +1,19 @@ +package main + +import ( + "github.com/krack8/lighthouse/pkg/controller" + _log "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/server" + "log" + "net/http" +) + +func main() { + _log.InitializeLogger() + controller.StartGrpcServer() + + // Start HTTP server + server.Start() + log.Println("HTTP server listening on :8080") + log.Fatal(http.ListenAndServe(":8080", nil)) +} diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index 3ccea24..9a8c0ea 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -2,6 +2,7 @@ package router import ( "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller" ) // @title Swagger API @@ -16,5 +17,5 @@ import ( func AddApiRoutes(httpRg *gin.RouterGroup) { // Namespace - //httpRg.GET("api/v1/namespace", k8s.NamespaceController().GetNamespaceList) + httpRg.GET("api/v1/namespace", controller.NamespaceController().GetNamespaceList) } diff --git a/pkg/server/server.go b/pkg/server/server.go index b85a66d..33dcab7 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -4,7 +4,7 @@ import ( "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" cfg "github.com/krack8/lighthouse/pkg/config" - "github.com/krack8/lighthouse/pkg/log" + _log "github.com/krack8/lighthouse/pkg/log" "github.com/krack8/lighthouse/pkg/server/router" "net/http" ) @@ -28,6 +28,6 @@ func Start() { //r.GET("/", api.Home().Index) err := r.Run(":" + cfg.ServerPort) // listen and serve on 0.0.0.0:8080 if err != nil { - log.Logger.Errorw("Failed to start server", "err", err.Error()) + _log.Logger.Errorw("Failed to start server", "err", err.Error()) } } diff --git a/pkg/tasks/tasks.go b/pkg/tasks/tasks.go index 7a96ef0..e59d8d7 100644 --- a/pkg/tasks/tasks.go +++ b/pkg/tasks/tasks.go @@ -74,6 +74,21 @@ func GetFuncName(funcTask interface{}) string { return functionName } +func GetCurrentTaskName() string { + pc, _, _, _ := runtime.Caller(1) + functionName := runtime.FuncForPC(pc).Name() + lastDotIndex := strings.LastIndex(functionName, ".") + if lastDotIndex != -1 { + functionName = functionName[lastDotIndex+1:] + } + lastSubsIndex := strings.Index(functionName, "-") + if lastSubsIndex != -1 { + functionName = functionName[:lastSubsIndex] + } + fmt.Println("Current function name:", functionName) + return functionName +} + func GeneratePayloadTask() { } From acceabbc1a0679148b4b04191fdc82d167836276 Mon Sep 17 00:00:00 2001 From: Toha Date: Sun, 26 Jan 2025 18:23:08 +0600 Subject: [PATCH 05/64] task selector --- pkg/agent/main.go | 49 +++++++------------ pkg/controller/{ => api}/namespace.go | 23 ++++----- pkg/{master => controller}/main.go | 4 +- .../controller.go} | 5 +- pkg/k8s/k8s.go | 26 +++++----- pkg/k8s/namespace.go | 4 +- pkg/k8s_test/k8s_test.go | 2 +- pkg/k8s_test/namespace_test.go | 1 + pkg/server/router/routes.go | 4 +- pkg/tasks/agent_task_selector.go | 43 ++++++++++++++++ pkg/tasks/tasks.go | 4 ++ 11 files changed, 104 insertions(+), 61 deletions(-) rename pkg/controller/{ => api}/namespace.go (79%) rename pkg/{master => controller}/main.go (79%) rename pkg/controller/{agent_controller.go => worker/controller.go} (99%) create mode 100644 pkg/k8s_test/namespace_test.go create mode 100644 pkg/tasks/agent_task_selector.go diff --git a/pkg/agent/main.go b/pkg/agent/main.go index 727db92..2d3bc44 100644 --- a/pkg/agent/main.go +++ b/pkg/agent/main.go @@ -3,18 +3,17 @@ package main import ( "context" "encoding/json" - "fmt" - "github.com/krack8/lighthouse/pkg/k8s" "github.com/krack8/lighthouse/pkg/tasks" + "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "log" - "time" - - "google.golang.org/grpc" + "sync" "github.com/krack8/lighthouse/pkg/common/pb" // Import the generated proto package ) +var taskMutex sync.Mutex + func main() { // For demonstration, we'll just run a single worker that belongs to "GroupA". groupName := "GroupA" @@ -64,37 +63,27 @@ func main() { task := payload.NewTask log.Printf("Worker received a new task: ID=%s, payload=%s", task.Id, task.Payload) - - // Here is where you do the actual business logic. - // We'll just pretend to do some work and return a result. go func(taskID, taskPayload string, task *pb.Task) { - // Simulate some processing time. - var res interface{} - newTask := tasks.TaskRegistry[task.Name] - switch v := newTask.TaskInput.(type) { - case k8s.GetNamespaceInputParams: - fmt.Println("Bhua:", v) - case k8s.GetNamespaceListInputParams: - input := k8s.GetNamespaceListInputParams{} - _ = json.Unmarshal([]byte(task.Input), &input) - fmt.Println("Get Namespace List Input Params:", v) - fmt.Println(input.Limit, input.Search) - execute, _ := newTask.TaskFunc.(func(context.Context, k8s.GetNamespaceListInputParams) (interface{}, error)) - res, err = execute(context.Background(), k8s.GetNamespaceListInputParams{}) + taskMutex.Lock() + defer taskMutex.Unlock() + TaskResult := &pb.TaskResult{} + res, err := tasks.TaskSelector(task) + if err != nil { + TaskResult.Success = false + TaskResult.Output = err.Error() + } else { + output, err := json.Marshal(res) if err != nil { - log.Printf(err.Error()) + TaskResult.Success = false + TaskResult.Output = err.Error() } + TaskResult.Success = true + TaskResult.Output = string(output) } - time.Sleep(2 * time.Second) - - // Build the result. + TaskResult.TaskId = taskID resultMsg := &pb.TaskStreamRequest{ Payload: &pb.TaskStreamRequest_TaskResult{ - TaskResult: &pb.TaskResult{ - TaskId: taskID, - Success: true, - Output: fmt.Sprintf("Processed payload: %s", res), - }, + TaskResult: TaskResult, }, } diff --git a/pkg/controller/namespace.go b/pkg/controller/api/namespace.go similarity index 79% rename from pkg/controller/namespace.go rename to pkg/controller/api/namespace.go index ee66166..62eef39 100644 --- a/pkg/controller/namespace.go +++ b/pkg/controller/api/namespace.go @@ -1,8 +1,9 @@ -package controller +package api import ( "encoding/json" "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" "github.com/krack8/lighthouse/pkg/k8s" "github.com/krack8/lighthouse/pkg/log" "github.com/krack8/lighthouse/pkg/tasks" @@ -49,7 +50,6 @@ func (ctrl *namespaceController) GetNamespaceList(ctx *gin.Context) { input.Search = ctx.Query("q") input.Continue = ctx.Query("continue") input.Limit = ctx.Query("limit") - taskName := tasks.GetCurrentTaskName() inputTask, err := json.Marshal(input) if err != nil { log.Logger.Errorw("unable to marshal GetNamespaceList Task input ", "err", err.Error()) @@ -61,16 +61,17 @@ func (ctrl *namespaceController) GetNamespaceList(ctx *gin.Context) { k8s.SendErrorResponse(ctx, "Missing group or payload param") return } - result.Data, err = TaskToAgent().SendToWorker(ctx, group, payload, taskName, inputTask) + taskName := tasks.GetTaskName(k8s.NamespaceService().GetNamespaceList) + log.Logger.Info("Printing task name from namespace controller: " + taskName) + res, err := worker.TaskToAgent().SendToWorker(ctx, group, payload, taskName, inputTask) if err != nil { k8s.SendErrorResponse(ctx, err.Error()) } - k8s.SendResponse(ctx, result) - - //err = we.Get(ctx, &result) - //if err != nil { - // log.Logger.Errorw("Unable to get result for GetNamespaceList", "err", err, "wid", we.GetID(), "rid", we.GetRunID()) - //} - // - //k8s.SendResponse(ctx, result) + output := k8s.OutputNamespaceList{} + err = json.Unmarshal([]byte(res.Output), &output) + if err != nil { + k8s.SendErrorResponse(ctx, err.Error()) + } + result.Data = output + k8s.SendSuccessResponse(ctx, result) } diff --git a/pkg/master/main.go b/pkg/controller/main.go similarity index 79% rename from pkg/master/main.go rename to pkg/controller/main.go index 3990377..abdfe54 100644 --- a/pkg/master/main.go +++ b/pkg/controller/main.go @@ -1,7 +1,7 @@ package main import ( - "github.com/krack8/lighthouse/pkg/controller" + "github.com/krack8/lighthouse/pkg/controller/worker" _log "github.com/krack8/lighthouse/pkg/log" "github.com/krack8/lighthouse/pkg/server" "log" @@ -10,7 +10,7 @@ import ( func main() { _log.InitializeLogger() - controller.StartGrpcServer() + worker.StartGrpcServer() // Start HTTP server server.Start() diff --git a/pkg/controller/agent_controller.go b/pkg/controller/worker/controller.go similarity index 99% rename from pkg/controller/agent_controller.go rename to pkg/controller/worker/controller.go index 5dd66f5..c845055 100644 --- a/pkg/controller/agent_controller.go +++ b/pkg/controller/worker/controller.go @@ -1,4 +1,4 @@ -package controller +package worker import ( "context" @@ -225,6 +225,9 @@ func (tta *taskToAgent) SendToWorker(c context.Context, groupName string, payloa select { case res := <-resultCh: // Send response to the user + if !res.Success { + return nil, errors.New(res.Output) + } return res, nil case <-time.After(10 * time.Second): return nil, errors.New("timed out waiting for worker result") diff --git a/pkg/k8s/k8s.go b/pkg/k8s/k8s.go index 9c4518f..f947b54 100644 --- a/pkg/k8s/k8s.go +++ b/pkg/k8s/k8s.go @@ -4,8 +4,10 @@ import ( "errors" "fmt" "github.com/gin-gonic/gin" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "net/http" + _context "context" "github.com/krack8/lighthouse/pkg/context" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" @@ -49,18 +51,18 @@ func GetClientset() *kubernetes.Clientset { return clientset } -//func ListNamespaces(clientset kubernetes.Interface) ([]string, error) { -// namespaces, err := clientset.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{}) -// if err != nil { -// return nil, fmt.Errorf("failed to list namespaces: %w", err) -// } -// -// var namespaceNames []string -// for _, ns := range namespaces.Items { -// namespaceNames = append(namespaceNames, ns.Name) -// } -// return namespaceNames, nil -//} +func ListNamespaces(clientset kubernetes.Interface) ([]string, error) { + namespaces, err := clientset.CoreV1().Namespaces().List(_context.TODO(), metav1.ListOptions{}) + if err != nil { + return nil, fmt.Errorf("failed to list namespaces: %w", err) + } + + var namespaceNames []string + for _, ns := range namespaces.Items { + namespaceNames = append(namespaceNames, ns.Name) + } + return namespaceNames, nil +} var nilResponse ResponseDTO = ResponseDTO{} diff --git a/pkg/k8s/namespace.go b/pkg/k8s/namespace.go index 25d6062..a8a4c35 100644 --- a/pkg/k8s/namespace.go +++ b/pkg/k8s/namespace.go @@ -167,8 +167,8 @@ func (namespace *namespaceService) GetNamespaceList(c context.Context, p GetName //} //p.output.Result = p.removeNamespaceListFields() return ResponseDTO{ - Status: "successfully done", - Data: nil, + Status: "success", + Data: GetNamespaceListInputParams{}, }, nil } diff --git a/pkg/k8s_test/k8s_test.go b/pkg/k8s_test/k8s_test.go index 01a8fe4..ad75b22 100644 --- a/pkg/k8s_test/k8s_test.go +++ b/pkg/k8s_test/k8s_test.go @@ -1,4 +1,4 @@ -package k8s_test_test +package k8s_test import ( "context" diff --git a/pkg/k8s_test/namespace_test.go b/pkg/k8s_test/namespace_test.go new file mode 100644 index 0000000..6de729e --- /dev/null +++ b/pkg/k8s_test/namespace_test.go @@ -0,0 +1 @@ +package k8s_test diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index 9a8c0ea..30b6a79 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -2,7 +2,7 @@ package router import ( "github.com/gin-gonic/gin" - "github.com/krack8/lighthouse/pkg/controller" + "github.com/krack8/lighthouse/pkg/controller/api" ) // @title Swagger API @@ -17,5 +17,5 @@ import ( func AddApiRoutes(httpRg *gin.RouterGroup) { // Namespace - httpRg.GET("api/v1/namespace", controller.NamespaceController().GetNamespaceList) + httpRg.GET("api/v1/namespace", api.NamespaceController().GetNamespaceList) } diff --git a/pkg/tasks/agent_task_selector.go b/pkg/tasks/agent_task_selector.go new file mode 100644 index 0000000..c087440 --- /dev/null +++ b/pkg/tasks/agent_task_selector.go @@ -0,0 +1,43 @@ +package tasks + +import ( + "context" + "encoding/json" + "errors" + "github.com/krack8/lighthouse/pkg/common/pb" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" +) + +var ErrTaskNotExistsRegistryMsg = "task does not exists" +var ErrTaskNotFoundMsg = "task not found" + +func TaskSelector(task *pb.Task) (interface{}, error) { + var res interface{} + var err error + newTask := GetTask(task.Name) + if newTask == nil { + return nil, errors.New(ErrTaskNotExistsRegistryMsg) + } + switch v := newTask.TaskInput.(type) { + case k8s.GetNamespaceInputParams: + log.Logger.Infow("Bhua:", v) + case k8s.GetNamespaceListInputParams: + log.Logger.Infow("task: "+task.Name+" started.", " task ID#:", task.Id) + input := k8s.GetNamespaceListInputParams{} + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetNamespaceListInputParams) (interface{}, error)) + if !exists { + return nil, errors.New(ErrTaskNotFoundMsg) + } + res, err = execute(context.Background(), k8s.GetNamespaceListInputParams{}) + if err != nil { + return nil, err + } + } + return res, nil +} diff --git a/pkg/tasks/tasks.go b/pkg/tasks/tasks.go index e59d8d7..0890c3c 100644 --- a/pkg/tasks/tasks.go +++ b/pkg/tasks/tasks.go @@ -89,6 +89,10 @@ func GetCurrentTaskName() string { return functionName } +func GetTaskName(funcTask interface{}) string { + return GetFuncName(funcTask) +} + func GeneratePayloadTask() { } From 06b4845af09772c245929ed8f23da7f6cd5df9eb Mon Sep 17 00:00:00 2001 From: Toha Date: Mon, 27 Jan 2025 03:43:25 +0600 Subject: [PATCH 06/64] namespace controller --- pkg/agent/main.go | 2 + pkg/controller/api/namespace.go | 129 ++++++++++++++++++++++---- pkg/controller/api/response_sender.go | 104 +++++++++++++++++++++ pkg/controller/worker/controller.go | 4 +- pkg/k8s/namespace.go | 2 +- pkg/server/router/routes.go | 5 + pkg/tasks/agent_task_selector.go | 85 ++++++++++++++--- pkg/tasks/tasks.go | 4 + 8 files changed, 303 insertions(+), 32 deletions(-) create mode 100644 pkg/controller/api/response_sender.go diff --git a/pkg/agent/main.go b/pkg/agent/main.go index 2d3bc44..69985e5 100644 --- a/pkg/agent/main.go +++ b/pkg/agent/main.go @@ -3,6 +3,7 @@ package main import ( "context" "encoding/json" + _log "github.com/krack8/lighthouse/pkg/log" "github.com/krack8/lighthouse/pkg/tasks" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -15,6 +16,7 @@ import ( var taskMutex sync.Mutex func main() { + _log.InitializeLogger() // For demonstration, we'll just run a single worker that belongs to "GroupA". groupName := "GroupA" authToken := "my-secret" diff --git a/pkg/controller/api/namespace.go b/pkg/controller/api/namespace.go index 62eef39..e973823 100644 --- a/pkg/controller/api/namespace.go +++ b/pkg/controller/api/namespace.go @@ -7,14 +7,15 @@ import ( "github.com/krack8/lighthouse/pkg/k8s" "github.com/krack8/lighthouse/pkg/log" "github.com/krack8/lighthouse/pkg/tasks" + corev1 "k8s.io/api/core/v1" ) type NamespaceControllerInterface interface { GetNamespaceList(ctx *gin.Context) - //GetNamespaceNameList(ctx *gin.Context) - //GetNamespaceDetails(ctx *gin.Context) - //DeployNamespace(ctx *gin.Context) - //DeleteNamespace(ctx *gin.Context) + GetNamespaceNameList(ctx *gin.Context) + GetNamespaceDetails(ctx *gin.Context) + DeployNamespace(ctx *gin.Context) + DeleteNamespace(ctx *gin.Context) } type namespaceController struct { @@ -27,7 +28,7 @@ func NamespaceController() *namespaceController { } func (ctrl *namespaceController) GetNamespaceList(ctx *gin.Context) { - var result k8s.ResponseDTO + var result ResponseDTO input := new(k8s.GetNamespaceListInputParams) input.Search = ctx.Query("q") @@ -38,7 +39,7 @@ func (ctrl *namespaceController) GetNamespaceList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Errorw("query labels unmarshal error ", "err", err.Error()) } @@ -55,23 +56,113 @@ func (ctrl *namespaceController) GetNamespaceList(ctx *gin.Context) { log.Logger.Errorw("unable to marshal GetNamespaceList Task input ", "err", err.Error()) } log.Logger.Debugw("GetNamespaceList task started...", "Task", "GetNamespaceList") - group := ctx.Query("group") - payload := ctx.Query("payload") - if group == "" || payload == "" { - k8s.SendErrorResponse(ctx, "Missing group or payload param") - return - } + //group := ctx.Query("group") + //payload := ctx.Query("payload") + ////if group == "" || payload == "" { + //// k8s.SendErrorResponse(ctx, "Missing group or payload param") + //// return + ////} taskName := tasks.GetTaskName(k8s.NamespaceService().GetNamespaceList) - log.Logger.Info("Printing task name from namespace controller: " + taskName) - res, err := worker.TaskToAgent().SendToWorker(ctx, group, payload, taskName, inputTask) + logRequestedTaskController("namespace", taskName) + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { k8s.SendErrorResponse(ctx, err.Error()) } - output := k8s.OutputNamespaceList{} - err = json.Unmarshal([]byte(res.Output), &output) + err = json.Unmarshal([]byte(res.Output), &result) if err != nil { - k8s.SendErrorResponse(ctx, err.Error()) + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *namespaceController) GetNamespaceNameList(ctx *gin.Context) { + var result ResponseDTO + var input = new(k8s.GetNamespaceNamesInputParams) + inputTask, err := json.Marshal(input) + if err != nil { + log.Logger.Errorw("unable to marshal GetNamespaceNameList Task input ", "err", err.Error()) + } + taskName := tasks.GetTaskName(k8s.NamespaceService().GetNamespaceNameList) + logRequestedTaskController("namespace", taskName) + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *namespaceController) DeployNamespace(ctx *gin.Context) { + var result ResponseDTO + payload := new(corev1.Namespace) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy Namespace payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + log.Logger.Debugw("deploy namespace payload ", payload) + + input := new(k8s.DeployNamespaceInputParams) + input.Namespace = payload + inputTask, err := json.Marshal(input) + if err != nil { + log.Logger.Errorw("unable to marshal deploy namespace Task input ", "err", err.Error()) + } + taskName := tasks.GetTaskName(k8s.NamespaceService().DeployNamespace) + logRequestedTaskController("namespace", taskName) + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *namespaceController) GetNamespaceDetails(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetNamespaceInputParams) + taskName := tasks.GetTaskName(k8s.NamespaceService().GetNamespaceDetails) + logRequestedTaskController("namespace", taskName) + input.NamespaceName = ctx.Param("name") + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *namespaceController) DeleteNamespace(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteNamespaceInputParams) + input.NamespaceName = ctx.Param("name") + taskName := tasks.GetTaskName(k8s.NamespaceService().DeleteNamespace) + logRequestedTaskController("namespace", taskName) + input.NamespaceName = ctx.Param("name") + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) } - result.Data = output - k8s.SendSuccessResponse(ctx, result) + SendResponse(ctx, result) } diff --git a/pkg/controller/api/response_sender.go b/pkg/controller/api/response_sender.go new file mode 100644 index 0000000..ec39414 --- /dev/null +++ b/pkg/controller/api/response_sender.go @@ -0,0 +1,104 @@ +package api + +import ( + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/context" + "github.com/krack8/lighthouse/pkg/log" + "net/http" +) + +type ResponseDTO struct { + Status string `json:"status"` + Msg string `json:"msg,omitempty"` + Data interface{} `json:"data,omitempty"` +} + +var nilResponse ResponseDTO = ResponseDTO{} + +var ( + UserAuthenticatedMsg = "User authenticated" + UserLoggedOutMsg = "Logged out from lighthouse" + ErrNamespaceEmpty = "namespace field empty" + ClearRedis = "role cleared" +) + +var httpStatusMap = map[string]int{ + "success": http.StatusOK, + "error": http.StatusBadRequest, +} + +func NilResponse() ResponseDTO { + return nilResponse +} + +func ErrorResponse(err error) (ResponseDTO, error) { + return ResponseDTO{ + Status: "error", + Msg: err.Error(), + }, nil +} + +func SuccessResponse(data interface{}) (ResponseDTO, error) { + return ResponseDTO{ + Status: "success", + Data: data, + }, nil +} + +func executeSendResponse(c *gin.Context, data interface{}, httpStatus int) { + sendHttpResponse(c, data, httpStatus) +} + +func SendResponse(c *gin.Context, response ResponseDTO) { + executeSendResponse(c, response, httpStatusMap[response.Status]) +} + +func SendErrorResponse(c *gin.Context, msg string) { + data := gin.H{ + "status": http.StatusBadRequest, + "msg": msg, + } + if context.IsRequestFromWS(c) { + data["msgId"] = context.GetRequestMsgId(c) + } + executeSendResponse(c, data, http.StatusBadRequest) +} + +func sendHttpResponse(c *gin.Context, data interface{}, httpStatus int) { + c.JSON(httpStatus, data) +} + +func SendForbiddenResponse(c *gin.Context, msg string) { + data := gin.H{ + "status": http.StatusForbidden, + "msg": msg, + } + if context.IsRequestFromWS(c) { + data["msgId"] = context.GetRequestMsgId(c) + } + executeSendResponse(c, data, http.StatusForbidden) +} + +//func SendSuccessResponse(c *gin.Context, response ResponseDTO) { +// response.Status = "success" +// data := gin.H{ +// "status": http.StatusOK, +// "data": response, +// } +// if context.IsRequestFromWS(c) { +// data["msgId"] = context.GetRequestMsgId(c) +// } +// executeSendResponse(c, data, http.StatusOK) +//} + +func SendSuccessResponse(c *gin.Context, response ResponseDTO) { + response.Status = "success" + executeSendResponse(c, response, httpStatusMap[response.Status]) +} + +func logRequestedTaskController(resource string, taskName string) { + log.Logger.Infow("from "+resource, "task", taskName) +} +func logErrMarshalTaskController(taskName string, err error) { + log.Logger.Errorw("unable to marshal "+taskName+" Task input", "err", err.Error()) +} diff --git a/pkg/controller/worker/controller.go b/pkg/controller/worker/controller.go index c845055..3e89764 100644 --- a/pkg/controller/worker/controller.go +++ b/pkg/controller/worker/controller.go @@ -217,7 +217,9 @@ func (s *serverImpl) Process(groupName string, payload string, taskName string, return resultCh, nil } -func (tta *taskToAgent) SendToWorker(c context.Context, groupName string, payload string, taskName string, input []byte) (*pb.TaskResult, error) { +func (tta *taskToAgent) SendToWorker(c context.Context, taskName string, input []byte) (*pb.TaskResult, error) { + groupName := "GroupA" + payload := taskName resultCh, err := srv.Process(groupName, payload, taskName, input) if err != nil { return nil, err diff --git a/pkg/k8s/namespace.go b/pkg/k8s/namespace.go index a8a4c35..5e2a821 100644 --- a/pkg/k8s/namespace.go +++ b/pkg/k8s/namespace.go @@ -168,7 +168,7 @@ func (namespace *namespaceService) GetNamespaceList(c context.Context, p GetName //p.output.Result = p.removeNamespaceListFields() return ResponseDTO{ Status: "success", - Data: GetNamespaceListInputParams{}, + Data: OutputNamespaceList{}, }, nil } diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index 30b6a79..a9cd606 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -18,4 +18,9 @@ import ( func AddApiRoutes(httpRg *gin.RouterGroup) { // Namespace httpRg.GET("api/v1/namespace", api.NamespaceController().GetNamespaceList) + httpRg.GET("api/v1/namespace/names", api.NamespaceController().GetNamespaceNameList) + httpRg.GET("api/v1/namespace/:name", api.NamespaceController().GetNamespaceDetails) + httpRg.POST("api/v1/namespace", api.NamespaceController().DeployNamespace) + httpRg.DELETE("api/v1/namespace/:name", api.NamespaceController().DeleteNamespace) + } diff --git a/pkg/tasks/agent_task_selector.go b/pkg/tasks/agent_task_selector.go index c087440..4cd49b0 100644 --- a/pkg/tasks/agent_task_selector.go +++ b/pkg/tasks/agent_task_selector.go @@ -9,35 +9,98 @@ import ( "github.com/krack8/lighthouse/pkg/log" ) -var ErrTaskNotExistsRegistryMsg = "task does not exists" -var ErrTaskNotFoundMsg = "task not found" +var ErrTaskNotExistsRegistry = errors.New("task does not exists") +var ErrTaskNotFound = errors.New("task not found") +var ErrUnexpectedTask = errors.New("unexpected task") +func logTaskStarted(task *pb.Task) { + log.Logger.Infow("Task: "+task.Name+" started.", "task ID#", task.Id) +} func TaskSelector(task *pb.Task) (interface{}, error) { var res interface{} var err error newTask := GetTask(task.Name) if newTask == nil { - return nil, errors.New(ErrTaskNotExistsRegistryMsg) + return nil, ErrTaskNotExistsRegistry } - switch v := newTask.TaskInput.(type) { + switch input := newTask.TaskInput.(type) { + //namespace case k8s.GetNamespaceInputParams: - log.Logger.Infow("Bhua:", v) + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetNamespaceInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil case k8s.GetNamespaceListInputParams: - log.Logger.Infow("task: "+task.Name+" started.", " task ID#:", task.Id) - input := k8s.GetNamespaceListInputParams{} + logTaskStarted(task) err = json.Unmarshal([]byte(task.Input), &input) if err != nil { return nil, err } - execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetNamespaceListInputParams) (interface{}, error)) if !exists { - return nil, errors.New(ErrTaskNotFoundMsg) + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetNamespaceNamesInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetNamespaceNamesInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployNamespaceInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployNamespaceInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteNamespaceInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteNamespaceInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound } - res, err = execute(context.Background(), k8s.GetNamespaceListInputParams{}) + res, err = execute(context.Background(), input) if err != nil { return nil, err } + return res, nil + default: + return nil, ErrUnexpectedTask } - return res, nil } diff --git a/pkg/tasks/tasks.go b/pkg/tasks/tasks.go index 0890c3c..f8d129c 100644 --- a/pkg/tasks/tasks.go +++ b/pkg/tasks/tasks.go @@ -58,6 +58,10 @@ func GetTask(taskName string) *Task { func InitTaskRegistry() { RegisterTask(k8s.NamespaceService().GetNamespaceList, k8s.GetNamespaceListInputParams{}) + RegisterTask(k8s.NamespaceService().GetNamespaceNameList, k8s.GetNamespaceNamesInputParams{}) + RegisterTask(k8s.NamespaceService().GetNamespaceDetails, k8s.GetNamespaceInputParams{}) + RegisterTask(k8s.NamespaceService().DeployNamespace, k8s.DeployNamespaceInputParams{}) + RegisterTask(k8s.NamespaceService().DeleteNamespace, k8s.DeleteNamespaceInputParams{}) } func GetFuncName(funcTask interface{}) string { From ada7a81cba835c27848bb6361c9a77199aff8e94 Mon Sep 17 00:00:00 2001 From: Toha Date: Mon, 27 Jan 2025 03:45:55 +0600 Subject: [PATCH 07/64] namespace controller remove fmt --- pkg/tasks/tasks.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/pkg/tasks/tasks.go b/pkg/tasks/tasks.go index f8d129c..8b9c9e0 100644 --- a/pkg/tasks/tasks.go +++ b/pkg/tasks/tasks.go @@ -1,7 +1,6 @@ package tasks import ( - "fmt" "github.com/krack8/lighthouse/pkg/k8s" "github.com/krack8/lighthouse/pkg/log" "reflect" @@ -39,12 +38,7 @@ func RegisterTask(funcTask interface{}, input interface{}) { task := &Task{TaskFunc: funcTask} task.TaskName = GetFuncName(funcTask) task.TaskInput = input - fmt.Println("Printing tasks info :" + task.TaskName) TaskRegistry[task.TaskName] = task - fmt.Println("Printing tasks ...") - fmt.Println(task) - fmt.Println("Printing tasks registry ...") - fmt.Println(TaskRegistry) } func GetTask(taskName string) *Task { @@ -74,7 +68,6 @@ func GetFuncName(funcTask interface{}) string { if lastSubsIndex != -1 { functionName = functionName[:lastSubsIndex] } - fmt.Println("Printing tasks Actual Name : " + functionName) return functionName } @@ -89,14 +82,9 @@ func GetCurrentTaskName() string { if lastSubsIndex != -1 { functionName = functionName[:lastSubsIndex] } - fmt.Println("Current function name:", functionName) return functionName } func GetTaskName(funcTask interface{}) string { return GetFuncName(funcTask) } - -func GeneratePayloadTask() { - -} From 2112e90d5d3067c850b1d2877ebe574ddb7d1cbc Mon Sep 17 00:00:00 2001 From: Toha Date: Mon, 27 Jan 2025 18:11:06 +0600 Subject: [PATCH 08/64] certificate, cluster role, cluster role binding, config map, controller revision controllers --- pkg/agent/main.go | 2 + pkg/config/config.go | 6 + pkg/config/kube_config.go | 17 +- pkg/controller/api/certificate.go | 164 ++++++++++ pkg/controller/api/cluster_role.go | 136 ++++++++ .../api/cluster_role_binding.controller.go | 135 ++++++++ pkg/controller/api/configmap.controller.go | 164 ++++++++++ .../api/controller_revision.controller.go | 164 ++++++++++ pkg/k8s/namespace.go | 12 +- pkg/server/router/routes.go | 26 +- pkg/tasks/agent_task_selector.go | 305 ++++++++++++++++++ pkg/tasks/tasks.go | 31 ++ 12 files changed, 1154 insertions(+), 8 deletions(-) create mode 100644 pkg/controller/api/certificate.go create mode 100644 pkg/controller/api/cluster_role.go create mode 100644 pkg/controller/api/cluster_role_binding.controller.go create mode 100644 pkg/controller/api/configmap.controller.go create mode 100644 pkg/controller/api/controller_revision.controller.go diff --git a/pkg/agent/main.go b/pkg/agent/main.go index 69985e5..1a46370 100644 --- a/pkg/agent/main.go +++ b/pkg/agent/main.go @@ -3,6 +3,7 @@ package main import ( "context" "encoding/json" + "github.com/krack8/lighthouse/pkg/config" _log "github.com/krack8/lighthouse/pkg/log" "github.com/krack8/lighthouse/pkg/tasks" "google.golang.org/grpc" @@ -17,6 +18,7 @@ var taskMutex sync.Mutex func main() { _log.InitializeLogger() + config.InitiateKubeClientSet() // For demonstration, we'll just run a single worker that belongs to "GroupA". groupName := "GroupA" authToken := "my-secret" diff --git a/pkg/config/config.go b/pkg/config/config.go index c8d7fdb..b0ff1ad 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -2,3 +2,9 @@ package config var ServerPort = "8080" var PageLimit = int64(10) +var isK8 = false +var KubeConfigFile = "dev-config.yaml" + +func IsK8() bool { + return isK8 +} diff --git a/pkg/config/kube_config.go b/pkg/config/kube_config.go index bceb24c..6104ae9 100644 --- a/pkg/config/kube_config.go +++ b/pkg/config/kube_config.go @@ -1,6 +1,7 @@ package config import ( + "flag" "github.com/krack8/lighthouse/pkg/log" snapshotV1 "github.com/kubernetes-csi/external-snapshotter/client/v6/clientset/versioned/typed/volumesnapshot/v1" networkingv1beta1 "istio.io/client-go/pkg/clientset/versioned/typed/networking/v1beta1" @@ -10,7 +11,9 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" + "k8s.io/client-go/util/homedir" metrics "k8s.io/metrics/pkg/client/clientset/versioned" + "path/filepath" ) var clientSet *kubernetes.Clientset @@ -21,10 +24,22 @@ var metricsClientSet *metrics.Clientset var networkingV1beta1ClientSet *networkingv1beta1.NetworkingV1beta1Client func InitiateKubeClientSet() { + var kubeConfig *string var restConfig *rest.Config var err error - restConfig, err = clientcmd.BuildConfigFromFlags("", "") + if IsK8() { + restConfig, err = clientcmd.BuildConfigFromFlags("", "") + } else { + if home := homedir.HomeDir(); home != "" { + kubeConfig = flag.String("kubeconfig", filepath.Join(home, ".kube", KubeConfigFile), "(optional) absolute path to the kubeconfig file") + restConfig, err = clientcmd.BuildConfigFromFlags("", *kubeConfig) + log.Logger.Info(filepath.Join(home, ".kube", KubeConfigFile)) + + } else { + restConfig, err = clientcmd.BuildConfigFromFlags("", "") + } + } if err != nil { log.Logger.Errorw(err.Error()) diff --git a/pkg/controller/api/certificate.go b/pkg/controller/api/certificate.go new file mode 100644 index 0000000..7f45e2b --- /dev/null +++ b/pkg/controller/api/certificate.go @@ -0,0 +1,164 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/dto" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" +) + +type CertificateControllerInterface interface { + GetCertificateList(ctx *gin.Context) + GetCertificateDetails(ctx *gin.Context) + DeployCertificate(ctx *gin.Context) + DeleteCertificate(ctx *gin.Context) +} + +type certificateController struct { +} + +var cc certificateController + +func CertificateController() *certificateController { + return &cc +} + +func (ctrl *certificateController) GetCertificateList(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetCertificateListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal(jsonLabel, &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for Certificate List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + inputTask, err := json.Marshal(input) + if err != nil { + log.Logger.Errorw("unable to marshal GetCertificateList Task input ", "err", err.Error()) + } + taskName := tasks.GetTaskName(k8s.CertificateService().GetCertificateList) + logRequestedTaskController("certificate", taskName) + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + k8s.SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *certificateController) GetCertificateDetails(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetCertificateDetailsInputParams) + input.CertificateName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + inputTask, err := json.Marshal(input) + if err != nil { + log.Logger.Errorw("unable to marshal GetCertificateList Task input ", "err", err.Error()) + } + taskName := tasks.GetTaskName(k8s.CertificateService().GetCertificateDetails) + logRequestedTaskController("certificate", taskName) + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + k8s.SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *certificateController) DeployCertificate(ctx *gin.Context) { + var result ResponseDTO + payload := new(dto.Certificate) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy Certificate payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployCertificateInputParams) + input.Certificate = payload + if input.Certificate.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "certificate deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + inputTask, err := json.Marshal(input) + if err != nil { + log.Logger.Errorw("unable to marshal DeployCertificate Task input ", "err", err.Error()) + } + taskName := tasks.GetTaskName(k8s.CertificateService().GetCertificateDetails) + logRequestedTaskController("certificate", taskName) + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + k8s.SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *certificateController) DeleteCertificate(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteCertificateInputParams) + input.CertificateName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + inputTask, err := json.Marshal(input) + if err != nil { + log.Logger.Errorw("unable to marshal GetCertificateList Task input ", "err", err.Error()) + } + taskName := tasks.GetTaskName(k8s.CertificateService().DeleteCertificate) + logRequestedTaskController("certificate", taskName) + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + k8s.SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/cluster_role.go b/pkg/controller/api/cluster_role.go new file mode 100644 index 0000000..fe04414 --- /dev/null +++ b/pkg/controller/api/cluster_role.go @@ -0,0 +1,136 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + rbacv1 "k8s.io/api/rbac/v1" +) + +type ClusterRoleControllerInterface interface { + GetClusterRoleList(ctx *gin.Context) + GetClusterRoleDetails(ctx *gin.Context) + DeployClusterRole(ctx *gin.Context) + DeleteClusterRole(ctx *gin.Context) +} + +type clusterRoleController struct { +} + +var crc clusterRoleController + +func ClusterRoleController() *clusterRoleController { + return &crc +} + +func (ctrl *clusterRoleController) GetClusterRoleList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetClusterRoleListInputParams) + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal(jsonLabel, &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for ClusterRole List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + inputTask, err := json.Marshal(input) + if err != nil { + log.Logger.Errorw("unable to marshal GetClusterRoleList Task input ", "err", err.Error()) + } + taskName := tasks.GetTaskName(k8s.ClusterRoleService().GetClusterRoleList) + logRequestedTaskController("cluster-role", taskName) + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *clusterRoleController) GetClusterRoleDetails(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetClusterRoleDetailsInputParams) + input.ClusterRoleName = ctx.Param("name") + inputTask, err := json.Marshal(input) + if err != nil { + log.Logger.Errorw("unable to marshal GetClusterRoleDetails Task input ", "err", err.Error()) + } + taskName := tasks.GetTaskName(k8s.ClusterRoleService().GetClusterRoleDetails) + logRequestedTaskController("cluster-role", taskName) + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *clusterRoleController) DeployClusterRole(ctx *gin.Context) { + var result ResponseDTO + payload := new(rbacv1.ClusterRole) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy clusterRole payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployClusterRoleInputParams) + input.ClusterRole = payload + inputTask, err := json.Marshal(input) + if err != nil { + log.Logger.Errorw("unable to marshal DeployClusterRole Task input ", "err", err.Error()) + } + taskName := tasks.GetTaskName(k8s.ClusterRoleService().DeployClusterRole) + logRequestedTaskController("cluster-role", taskName) + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *clusterRoleController) DeleteClusterRole(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteClusterRoleInputParams) + input.ClusterRoleName = ctx.Param("name") + inputTask, err := json.Marshal(input) + if err != nil { + log.Logger.Errorw("unable to marshal DeleteClusterRole Task input ", "err", err.Error()) + } + taskName := tasks.GetTaskName(k8s.ClusterRoleService().DeleteClusterRole) + logRequestedTaskController("cluster-role", taskName) + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/cluster_role_binding.controller.go b/pkg/controller/api/cluster_role_binding.controller.go new file mode 100644 index 0000000..df3f575 --- /dev/null +++ b/pkg/controller/api/cluster_role_binding.controller.go @@ -0,0 +1,135 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + rbacv1 "k8s.io/api/rbac/v1" +) + +type ClusterRoleBindingControllerInterface interface { + GetClusterRoleBindingList(ctx *gin.Context) + GetClusterRoleBindingDetails(ctx *gin.Context) + DeployClusterRoleBinding(ctx *gin.Context) + DeleteClusterRoleBinding(ctx *gin.Context) +} + +type clusterRoleBindingController struct { +} + +var crbc clusterRoleBindingController + +func ClusterRoleBindingController() *clusterRoleBindingController { + return &crbc +} + +func (ctrl *clusterRoleBindingController) GetClusterRoleBindingList(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetClusterRoleBindingListInputParams) + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal(jsonLabel, &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for ClusterRoleBinding List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + inputTask, err := json.Marshal(input) + if err != nil { + log.Logger.Errorw("unable to marshal GetClusterRoleBindingList Task input ", "err", err.Error()) + } + taskName := tasks.GetTaskName(k8s.ClusterRoleBindingService().GetClusterRoleBindingList) + logRequestedTaskController("cluster-role-binding", taskName) + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *clusterRoleBindingController) GetClusterRoleBindingDetails(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetClusterRoleBindingDetailsInputParams) + input.ClusterRoleBindingName = ctx.Param("name") + inputTask, err := json.Marshal(input) + if err != nil { + log.Logger.Errorw("unable to marshal GetClusterRoleBindingDetails Task input ", "err", err.Error()) + } + taskName := tasks.GetTaskName(k8s.ClusterRoleBindingService().GetClusterRoleBindingDetails) + logRequestedTaskController("cluster-role-binding", taskName) + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *clusterRoleBindingController) DeployClusterRoleBinding(ctx *gin.Context) { + var result ResponseDTO + payload := new(rbacv1.ClusterRoleBinding) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy clusterRoleBinding payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployClusterRoleBindingInputParams) + input.ClusterRoleBinding = payload + inputTask, err := json.Marshal(input) + if err != nil { + log.Logger.Errorw("unable to marshal DeployClusterRoleBinding Task input ", "err", err.Error()) + } + taskName := tasks.GetTaskName(k8s.ClusterRoleBindingService().DeployClusterRoleBinding) + logRequestedTaskController("cluster-role-binding", taskName) + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *clusterRoleBindingController) DeleteClusterRoleBinding(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteClusterRoleBindingInputParams) + input.ClusterRoleBindingName = ctx.Param("name") + taskName := tasks.GetTaskName(k8s.ClusterRoleBindingService().DeleteClusterRoleBinding) + logRequestedTaskController("cluster-role-binding", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/configmap.controller.go b/pkg/controller/api/configmap.controller.go new file mode 100644 index 0000000..2b610fc --- /dev/null +++ b/pkg/controller/api/configmap.controller.go @@ -0,0 +1,164 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + corev1 "k8s.io/api/core/v1" +) + +type ConfigMapControllerInterface interface { + GetConfigMapList(ctx *gin.Context) + GetConfigMapDetails(ctx *gin.Context) + DeployConfigMap(ctx *gin.Context) + DeleteConfigMap(ctx *gin.Context) +} + +type configMapController struct { +} + +var cmc configMapController + +func ConfigMapController() *configMapController { + return &cmc +} + +func (ctrl *configMapController) GetConfigMapList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetConfigMapListInputParams) + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal(jsonLabel, &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for ConfigMap List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.ConfigMapService().GetConfigMapList) + logRequestedTaskController("config-map", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *configMapController) GetConfigMapDetails(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetConfigMapDetailsInputParams) + input.ConfigMapName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.ConfigMapService().GetConfigMapDetails) + logRequestedTaskController("config-map", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *configMapController) DeployConfigMap(ctx *gin.Context) { + var result ResponseDTO + payload := new(corev1.ConfigMap) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy configmap payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployConfigMapInputParams) + input.ConfigMap = payload + if input.ConfigMap.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "config-map deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.ConfigMapService().DeployConfigMap) + logRequestedTaskController("config-map", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *configMapController) DeleteConfigMap(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteConfigMapInputParams) + input.ConfigMapName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.ConfigMapService().DeleteConfigMap) + logRequestedTaskController("config-map", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/controller_revision.controller.go b/pkg/controller/api/controller_revision.controller.go new file mode 100644 index 0000000..46efecd --- /dev/null +++ b/pkg/controller/api/controller_revision.controller.go @@ -0,0 +1,164 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + appsv1 "k8s.io/api/apps/v1" +) + +type ControllerRevisionControllerInterface interface { + GetControllerRevisionList(ctx *gin.Context) + GetControllerRevisionDetails(ctx *gin.Context) + DeployControllerRevision(ctx *gin.Context) + DeleteControllerRevision(ctx *gin.Context) +} + +type controllerRevisionController struct { +} + +var ctrlrc controllerRevisionController + +func ControllerRevisionController() *controllerRevisionController { + return &ctrlrc +} + +func (ctrl *controllerRevisionController) GetControllerRevisionList(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetControllerRevisionListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal(jsonLabel, &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for ControllerRevision List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.ControllerRevisionService().GetControllerRevisionList) + logRequestedTaskController("controller-revision", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *controllerRevisionController) GetControllerRevisionDetails(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetControllerRevisionDetailsInputParams) + input.ControllerRevisionName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.ControllerRevisionService().GetControllerRevisionDetails) + logRequestedTaskController("controller-revision", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *controllerRevisionController) DeployControllerRevision(ctx *gin.Context) { + var result ResponseDTO + payload := new(appsv1.ControllerRevision) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy configmap payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployControllerRevisionInputParams) + input.ControllerRevision = payload + if input.ControllerRevision.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "config-map deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.ControllerRevisionService().DeployControllerRevision) + logRequestedTaskController("controller-revision", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *controllerRevisionController) DeleteControllerRevision(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteControllerRevisionInputParams) + input.ControllerRevisionName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.ControllerRevisionService().DeleteControllerRevision) + logRequestedTaskController("controller-revision", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/k8s/namespace.go b/pkg/k8s/namespace.go index 5e2a821..c592e4b 100644 --- a/pkg/k8s/namespace.go +++ b/pkg/k8s/namespace.go @@ -161,14 +161,14 @@ func (p *GetNamespaceListInputParams) Process(c context.Context) error { } func (namespace *namespaceService) GetNamespaceList(c context.Context, p GetNamespaceListInputParams) (interface{}, error) { - //err := p.Process(c) - //if err != nil { - // return nil, err - //} - //p.output.Result = p.removeNamespaceListFields() + err := p.Process(c) + if err != nil { + return nil, err + } + p.output.Result = p.removeNamespaceListFields() return ResponseDTO{ Status: "success", - Data: OutputNamespaceList{}, + Data: p.output, }, nil } diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index a9cd606..f3a4383 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -22,5 +22,29 @@ func AddApiRoutes(httpRg *gin.RouterGroup) { httpRg.GET("api/v1/namespace/:name", api.NamespaceController().GetNamespaceDetails) httpRg.POST("api/v1/namespace", api.NamespaceController().DeployNamespace) httpRg.DELETE("api/v1/namespace/:name", api.NamespaceController().DeleteNamespace) - + // Certificate + httpRg.GET("api/v1/certificate", api.CertificateController().GetCertificateList) + httpRg.GET("api/v1/certificate/:name", api.CertificateController().GetCertificateDetails) + httpRg.POST("api/v1/certificate", api.CertificateController().DeployCertificate) + httpRg.DELETE("api/v1/certificate/:name", api.CertificateController().DeleteCertificate) + // Config Map + httpRg.GET("api/v1/config-map", api.ConfigMapController().GetConfigMapList) + httpRg.GET("api/v1/config-map/:name", api.ConfigMapController().GetConfigMapDetails) + httpRg.POST("api/v1/config-map", api.ConfigMapController().DeployConfigMap) + httpRg.DELETE("api/v1/config-map/:name", api.ConfigMapController().DeleteConfigMap) + // ClusterRole + httpRg.GET("api/v1/cluster-role", api.ClusterRoleController().GetClusterRoleList) + httpRg.GET("api/v1/cluster-role/:name", api.ClusterRoleController().GetClusterRoleDetails) + httpRg.POST("api/v1/cluster-role", api.ClusterRoleController().DeployClusterRole) + httpRg.DELETE("api/v1/cluster-role/:name", api.ClusterRoleController().DeleteClusterRole) + // ClusterRoleBinding + httpRg.GET("api/v1/cluster-role-binding", api.ClusterRoleBindingController().GetClusterRoleBindingList) + httpRg.GET("api/v1/cluster-role-binding/:name", api.ClusterRoleBindingController().GetClusterRoleBindingDetails) + httpRg.POST("api/v1/cluster-role-binding", api.ClusterRoleBindingController().DeployClusterRoleBinding) + httpRg.DELETE("api/v1/cluster-role-binding/:name", api.ClusterRoleBindingController().DeleteClusterRoleBinding) + // ControllerRevision + httpRg.GET("api/v1/controller-revision", api.ControllerRevisionController().GetControllerRevisionList) + httpRg.GET("api/v1/controller-revision/:name", api.ControllerRevisionController().GetControllerRevisionDetails) + httpRg.POST("api/v1/controller-revision", api.ControllerRevisionController().DeployControllerRevision) + httpRg.DELETE("api/v1/controller-revision/:name", api.ControllerRevisionController().DeleteControllerRevision) } diff --git a/pkg/tasks/agent_task_selector.go b/pkg/tasks/agent_task_selector.go index 4cd49b0..1eec052 100644 --- a/pkg/tasks/agent_task_selector.go +++ b/pkg/tasks/agent_task_selector.go @@ -100,6 +100,311 @@ func TaskSelector(task *pb.Task) (interface{}, error) { return nil, err } return res, nil + //Certificate + case k8s.GetCertificateListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetCertificateListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetCertificateDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetCertificateDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployCertificateInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployCertificateInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteCertificateInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteCertificateInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //ClusterRole + case k8s.GetClusterRoleListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetClusterRoleListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetClusterRoleDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetClusterRoleDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployClusterRoleInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployClusterRoleInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteClusterRoleInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteClusterRoleInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //ClusterRoleBinding + case k8s.GetClusterRoleBindingListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetClusterRoleBindingListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetClusterRoleBindingDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetClusterRoleBindingDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployClusterRoleBindingInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployClusterRoleBindingInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteClusterRoleBindingInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteClusterRoleBindingInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //ConfigMap + case k8s.GetConfigMapListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetConfigMapListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetConfigMapDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetConfigMapDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployConfigMapInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployConfigMapInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteConfigMapInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteConfigMapInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //ControllerRevision + case k8s.GetControllerRevisionListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetControllerRevisionListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetControllerRevisionDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetControllerRevisionDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployControllerRevisionInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployControllerRevisionInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteControllerRevisionInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteControllerRevisionInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil default: return nil, ErrUnexpectedTask } diff --git a/pkg/tasks/tasks.go b/pkg/tasks/tasks.go index 8b9c9e0..ae56a27 100644 --- a/pkg/tasks/tasks.go +++ b/pkg/tasks/tasks.go @@ -51,11 +51,42 @@ func GetTask(taskName string) *Task { } func InitTaskRegistry() { + //namespace RegisterTask(k8s.NamespaceService().GetNamespaceList, k8s.GetNamespaceListInputParams{}) RegisterTask(k8s.NamespaceService().GetNamespaceNameList, k8s.GetNamespaceNamesInputParams{}) RegisterTask(k8s.NamespaceService().GetNamespaceDetails, k8s.GetNamespaceInputParams{}) RegisterTask(k8s.NamespaceService().DeployNamespace, k8s.DeployNamespaceInputParams{}) RegisterTask(k8s.NamespaceService().DeleteNamespace, k8s.DeleteNamespaceInputParams{}) + + //certficate + RegisterTask(k8s.CertificateService().GetCertificateList, k8s.GetCertificateListInputParams{}) + RegisterTask(k8s.CertificateService().GetCertificateDetails, k8s.GetCertificateDetailsInputParams{}) + RegisterTask(k8s.CertificateService().DeployCertificate, k8s.DeployCertificateInputParams{}) + RegisterTask(k8s.CertificateService().DeleteCertificate, k8s.DeleteCertificateInputParams{}) + + //clusterRole + RegisterTask(k8s.ClusterRoleService().GetClusterRoleList, k8s.GetClusterRoleListInputParams{}) + RegisterTask(k8s.ClusterRoleService().GetClusterRoleDetails, k8s.GetClusterRoleDetailsInputParams{}) + RegisterTask(k8s.ClusterRoleService().DeployClusterRole, k8s.DeployClusterRoleInputParams{}) + RegisterTask(k8s.ClusterRoleService().DeleteClusterRole, k8s.DeleteClusterRoleInputParams{}) + + //clusterRoleBinding + RegisterTask(k8s.ClusterRoleBindingService().GetClusterRoleBindingList, k8s.GetClusterRoleBindingListInputParams{}) + RegisterTask(k8s.ClusterRoleBindingService().GetClusterRoleBindingDetails, k8s.GetClusterRoleBindingDetailsInputParams{}) + RegisterTask(k8s.ClusterRoleBindingService().DeployClusterRoleBinding, k8s.DeployClusterRoleBindingInputParams{}) + RegisterTask(k8s.ClusterRoleBindingService().DeleteClusterRoleBinding, k8s.DeleteClusterRoleBindingInputParams{}) + + //configMap + RegisterTask(k8s.ConfigMapService().GetConfigMapList, k8s.GetConfigMapListInputParams{}) + RegisterTask(k8s.ConfigMapService().GetConfigMapDetails, k8s.GetConfigMapDetailsInputParams{}) + RegisterTask(k8s.ConfigMapService().DeployConfigMap, k8s.DeployConfigMapInputParams{}) + RegisterTask(k8s.ConfigMapService().DeleteConfigMap, k8s.DeleteConfigMapInputParams{}) + + //controllerRevision + RegisterTask(k8s.ControllerRevisionService().GetControllerRevisionList, k8s.GetControllerRevisionListInputParams{}) + RegisterTask(k8s.ControllerRevisionService().GetControllerRevisionDetails, k8s.GetControllerRevisionDetailsInputParams{}) + RegisterTask(k8s.ControllerRevisionService().DeployControllerRevision, k8s.DeployControllerRevisionInputParams{}) + RegisterTask(k8s.ControllerRevisionService().DeleteControllerRevision, k8s.DeleteControllerRevisionInputParams{}) } func GetFuncName(funcTask interface{}) string { From 18b94bf6278139d8a36e4925c79100fcb9210e69 Mon Sep 17 00:00:00 2001 From: Toha Date: Mon, 27 Jan 2025 23:14:21 +0600 Subject: [PATCH 09/64] crd, cronjob, custom resource controller --- ....controller.go => cluster_role_binding.go} | 0 .../{configmap.controller.go => configmap.go} | 0 ...n.controller.go => controller_revision.go} | 0 pkg/controller/api/crd.go | 133 +++++++++++++ pkg/controller/api/cronjob.go | 163 ++++++++++++++++ pkg/controller/api/custom_resource.go | 157 +++++++++++++++ pkg/server/router/routes.go | 15 ++ pkg/tasks/agent_task_selector.go | 183 ++++++++++++++++++ pkg/tasks/register_tasks.go | 61 ++++++ pkg/tasks/tasks.go | 40 ---- 10 files changed, 712 insertions(+), 40 deletions(-) rename pkg/controller/api/{cluster_role_binding.controller.go => cluster_role_binding.go} (100%) rename pkg/controller/api/{configmap.controller.go => configmap.go} (100%) rename pkg/controller/api/{controller_revision.controller.go => controller_revision.go} (100%) create mode 100644 pkg/controller/api/crd.go create mode 100644 pkg/controller/api/cronjob.go create mode 100644 pkg/controller/api/custom_resource.go create mode 100644 pkg/tasks/register_tasks.go diff --git a/pkg/controller/api/cluster_role_binding.controller.go b/pkg/controller/api/cluster_role_binding.go similarity index 100% rename from pkg/controller/api/cluster_role_binding.controller.go rename to pkg/controller/api/cluster_role_binding.go diff --git a/pkg/controller/api/configmap.controller.go b/pkg/controller/api/configmap.go similarity index 100% rename from pkg/controller/api/configmap.controller.go rename to pkg/controller/api/configmap.go diff --git a/pkg/controller/api/controller_revision.controller.go b/pkg/controller/api/controller_revision.go similarity index 100% rename from pkg/controller/api/controller_revision.controller.go rename to pkg/controller/api/controller_revision.go diff --git a/pkg/controller/api/crd.go b/pkg/controller/api/crd.go new file mode 100644 index 0000000..3001f6a --- /dev/null +++ b/pkg/controller/api/crd.go @@ -0,0 +1,133 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" +) + +type CrdControllerInterface interface { + GetCrdList(ctx *gin.Context) + GetCrdDetails(ctx *gin.Context) + DeployCrd(ctx *gin.Context) + DeleteCrd(ctx *gin.Context) +} + +type crdController struct { +} + +var crdc crdController + +func CrdController() *crdController { + return &crdc +} + +func (ctrl *crdController) GetCrdList(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetCrdListInputParams) + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal(jsonLabel, &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for Crd List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + input.Continue = ctx.Query("continue") + input.Search = ctx.Query("q") + input.Limit = ctx.Query("limit") + taskName := tasks.GetTaskName(k8s.CrdService().GetCrdList) + logRequestedTaskController("crd", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *crdController) GetCrdDetails(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetCrdDetailsInputParams) + input.CrdName = ctx.Param("name") + taskName := tasks.GetTaskName(k8s.CrdService().GetCrdList) + logRequestedTaskController("crd", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *crdController) DeployCrd(ctx *gin.Context) { + var result ResponseDTO + payload := new(v1.CustomResourceDefinition) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy Crd payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + input := new(k8s.DeployCrdInputParams) + input.Crd = payload + taskName := tasks.GetTaskName(k8s.CrdService().DeployCrd) + logRequestedTaskController("crd", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *crdController) DeleteCrd(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteCrdInputParams) + input.CrdName = ctx.Param("name") + taskName := tasks.GetTaskName(k8s.CrdService().DeleteCrd) + logRequestedTaskController("crd", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/cronjob.go b/pkg/controller/api/cronjob.go new file mode 100644 index 0000000..252528e --- /dev/null +++ b/pkg/controller/api/cronjob.go @@ -0,0 +1,163 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + batchv1 "k8s.io/api/batch/v1" +) + +type CronJobControllerInterface interface { + GetCronJobList(ctx *gin.Context) + GetCronJobDetails(ctx *gin.Context) + DeployCronJob(ctx *gin.Context) + DeleteCronJob(ctx *gin.Context) +} + +type cronJobController struct { +} + +var cjc cronJobController + +func CronJobController() *cronJobController { + return &cjc +} + +func (ctrl *cronJobController) GetCronJobList(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetCronJobListInputParams) + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal(jsonLabel, &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for cronjob List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + taskName := tasks.GetTaskName(k8s.CronJobService().GetCronJobList) + logRequestedTaskController("cron-job", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *cronJobController) GetCronJobDetails(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetCronJobInputParams) + input.CronJobName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.CronJobService().GetCronJobDetails) + logRequestedTaskController("cron-job", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *cronJobController) DeployCronJob(ctx *gin.Context) { + var result ResponseDTO + payload := new(batchv1.CronJob) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy cronjob payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployCronJobInputParams) + input.CronJob = payload + if input.CronJob.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "cronjob deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.CronJobService().DeployCronJob) + logRequestedTaskController("cron-job", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *cronJobController) DeleteCronJob(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteCronJobInputParams) + input.CronJobName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.CronJobService().DeleteCronJob) + logRequestedTaskController("cron-job", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/custom_resource.go b/pkg/controller/api/custom_resource.go new file mode 100644 index 0000000..218d97a --- /dev/null +++ b/pkg/controller/api/custom_resource.go @@ -0,0 +1,157 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/dto" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" +) + +type CustomResourceControllerInterface interface { + GetCustomResourceList(ctx *gin.Context) + GetCustomResourceDetails(ctx *gin.Context) + DeployCustomResource(ctx *gin.Context) + DeleteCustomResource(ctx *gin.Context) +} + +type customResourceController struct{} + +var crec customResourceController + +func CustomResourceController() *customResourceController { + return &crec +} + +func (ctrl *customResourceController) GetCustomResourceList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetCustomResourceListInputParams) + + input.NamespaceName = ctx.Query("namespace") + input.CustomResourceSGVR.Resource = ctx.Query("resource") + input.CustomResourceSGVR.Group = ctx.Query("group") + input.CustomResourceSGVR.Version = ctx.Query("version") + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal(jsonLabel, &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for CustomResource List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + input.Search = ctx.Query("q") + taskName := tasks.GetTaskName(k8s.CustomResourceService().GetCustomResourceList) + logRequestedTaskController("custom-resource", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *customResourceController) GetCustomResourceDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetCustomResourceDetailsInputParams) + + input.Name = ctx.Param("name") + input.NamespaceName = ctx.Query("namespace") + input.CustomResourceSGVR.Resource = ctx.Query("resource") + input.CustomResourceSGVR.Group = ctx.Query("group") + input.CustomResourceSGVR.Version = ctx.Query("version") + taskName := tasks.GetTaskName(k8s.CustomResourceService().GetCustomResourceDetails) + logRequestedTaskController("custom-resource", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *customResourceController) DeployCustomResource(ctx *gin.Context) { + var result ResponseDTO + payload := new(dto.CustomResource) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy CustomResource payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployCustomResourceInputParams) + input.CustomResource = payload + input.Kind = ctx.Query("kind") + input.NamespaceName = ctx.Query("namespace") + input.CustomResourceSGVR.Resource = ctx.Query("resource") + input.CustomResourceSGVR.Version = ctx.Query("version") + input.CustomResourceSGVR.Group = ctx.Query("group") + taskName := tasks.GetTaskName(k8s.CustomResourceService().DeployCustomResource) + logRequestedTaskController("custom-resource", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *customResourceController) DeleteCustomResource(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteCustomResourceInputParams) + + input.CustomResourceName = ctx.Param("name") + input.NamespaceName = ctx.Query("namespace") + input.CustomResourceSGVR.Resource = ctx.Query("resource") + input.CustomResourceSGVR.Version = ctx.Query("version") + input.CustomResourceSGVR.Group = ctx.Query("group") + taskName := tasks.GetTaskName(k8s.CustomResourceService().DeleteCustomResource) + logRequestedTaskController("custom-resource", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index f3a4383..c456bfb 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -47,4 +47,19 @@ func AddApiRoutes(httpRg *gin.RouterGroup) { httpRg.GET("api/v1/controller-revision/:name", api.ControllerRevisionController().GetControllerRevisionDetails) httpRg.POST("api/v1/controller-revision", api.ControllerRevisionController().DeployControllerRevision) httpRg.DELETE("api/v1/controller-revision/:name", api.ControllerRevisionController().DeleteControllerRevision) + // CRD + httpRg.GET("api/v1/crd", api.CrdController().GetCrdList) + httpRg.GET("api/v1/crd/:name", api.CrdController().GetCrdDetails) + httpRg.POST("api/v1/crd", api.CrdController().DeployCrd) + httpRg.DELETE("api/v1/crd/:name", api.CrdController().DeleteCrd) + // Custom Resource + httpRg.GET("api/v1/custom-resource", api.CustomResourceController().GetCustomResourceList) + httpRg.GET("api/v1/custom-resource/:name", api.CustomResourceController().GetCustomResourceDetails) + httpRg.POST("api/v1/custom-resource", api.CustomResourceController().DeployCustomResource) + httpRg.DELETE("api/v1/custom-resource/:name", api.CustomResourceController().DeleteCustomResource) + //Cronjob + httpRg.GET("api/v1/cronjob", api.CronJobController().GetCronJobList) + httpRg.GET("api/v1/cronjob/:name", api.CronJobController().GetCronJobDetails) + httpRg.POST("api/v1/cronjob", api.CronJobController().DeployCronJob) + httpRg.DELETE("api/v1/cronjob/:name", api.CronJobController().DeleteCronJob) } diff --git a/pkg/tasks/agent_task_selector.go b/pkg/tasks/agent_task_selector.go index 1eec052..366134b 100644 --- a/pkg/tasks/agent_task_selector.go +++ b/pkg/tasks/agent_task_selector.go @@ -405,6 +405,189 @@ func TaskSelector(task *pb.Task) (interface{}, error) { return nil, err } return res, nil + //CRD + case k8s.GetCrdListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetCrdListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetCrdDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetCrdDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployCrdInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployCrdInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteCrdInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteCrdInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //cronJob + case k8s.GetCronJobListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetCronJobListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetCronJobInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetCronJobInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployCronJobInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployCronJobInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteCronJobInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteCronJobInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //customResource + case k8s.GetCustomResourceListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetCustomResourceListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetCustomResourceDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetCustomResourceDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployCustomResourceInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployCustomResourceInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteCustomResourceInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteCustomResourceInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil default: return nil, ErrUnexpectedTask } diff --git a/pkg/tasks/register_tasks.go b/pkg/tasks/register_tasks.go new file mode 100644 index 0000000..3c32f41 --- /dev/null +++ b/pkg/tasks/register_tasks.go @@ -0,0 +1,61 @@ +package tasks + +import "github.com/krack8/lighthouse/pkg/k8s" + +func InitTaskRegistry() { + //namespace + RegisterTask(k8s.NamespaceService().GetNamespaceList, k8s.GetNamespaceListInputParams{}) + RegisterTask(k8s.NamespaceService().GetNamespaceNameList, k8s.GetNamespaceNamesInputParams{}) + RegisterTask(k8s.NamespaceService().GetNamespaceDetails, k8s.GetNamespaceInputParams{}) + RegisterTask(k8s.NamespaceService().DeployNamespace, k8s.DeployNamespaceInputParams{}) + RegisterTask(k8s.NamespaceService().DeleteNamespace, k8s.DeleteNamespaceInputParams{}) + + //certficate + RegisterTask(k8s.CertificateService().GetCertificateList, k8s.GetCertificateListInputParams{}) + RegisterTask(k8s.CertificateService().GetCertificateDetails, k8s.GetCertificateDetailsInputParams{}) + RegisterTask(k8s.CertificateService().DeployCertificate, k8s.DeployCertificateInputParams{}) + RegisterTask(k8s.CertificateService().DeleteCertificate, k8s.DeleteCertificateInputParams{}) + + //clusterRole + RegisterTask(k8s.ClusterRoleService().GetClusterRoleList, k8s.GetClusterRoleListInputParams{}) + RegisterTask(k8s.ClusterRoleService().GetClusterRoleDetails, k8s.GetClusterRoleDetailsInputParams{}) + RegisterTask(k8s.ClusterRoleService().DeployClusterRole, k8s.DeployClusterRoleInputParams{}) + RegisterTask(k8s.ClusterRoleService().DeleteClusterRole, k8s.DeleteClusterRoleInputParams{}) + + //clusterRoleBinding + RegisterTask(k8s.ClusterRoleBindingService().GetClusterRoleBindingList, k8s.GetClusterRoleBindingListInputParams{}) + RegisterTask(k8s.ClusterRoleBindingService().GetClusterRoleBindingDetails, k8s.GetClusterRoleBindingDetailsInputParams{}) + RegisterTask(k8s.ClusterRoleBindingService().DeployClusterRoleBinding, k8s.DeployClusterRoleBindingInputParams{}) + RegisterTask(k8s.ClusterRoleBindingService().DeleteClusterRoleBinding, k8s.DeleteClusterRoleBindingInputParams{}) + + //configMap + RegisterTask(k8s.ConfigMapService().GetConfigMapList, k8s.GetConfigMapListInputParams{}) + RegisterTask(k8s.ConfigMapService().GetConfigMapDetails, k8s.GetConfigMapDetailsInputParams{}) + RegisterTask(k8s.ConfigMapService().DeployConfigMap, k8s.DeployConfigMapInputParams{}) + RegisterTask(k8s.ConfigMapService().DeleteConfigMap, k8s.DeleteConfigMapInputParams{}) + + //controllerRevision + RegisterTask(k8s.ControllerRevisionService().GetControllerRevisionList, k8s.GetControllerRevisionListInputParams{}) + RegisterTask(k8s.ControllerRevisionService().GetControllerRevisionDetails, k8s.GetControllerRevisionDetailsInputParams{}) + RegisterTask(k8s.ControllerRevisionService().DeployControllerRevision, k8s.DeployControllerRevisionInputParams{}) + RegisterTask(k8s.ControllerRevisionService().DeleteControllerRevision, k8s.DeleteControllerRevisionInputParams{}) + + //CRD + RegisterTask(k8s.CrdService().GetCrdList, k8s.GetCrdListInputParams{}) + RegisterTask(k8s.CrdService().GetCrdDetails, k8s.GetCrdDetailsInputParams{}) + RegisterTask(k8s.CrdService().DeployCrd, k8s.DeployCrdInputParams{}) + RegisterTask(k8s.CrdService().DeleteCrd, k8s.DeleteCrdInputParams{}) + + //customResource + RegisterTask(k8s.CustomResourceService().GetCustomResourceList, k8s.GetCustomResourceListInputParams{}) + RegisterTask(k8s.CustomResourceService().GetCustomResourceDetails, k8s.GetCustomResourceDetailsInputParams{}) + RegisterTask(k8s.CustomResourceService().DeployCustomResource, k8s.DeployCustomResourceInputParams{}) + RegisterTask(k8s.CustomResourceService().DeleteCustomResource, k8s.DeleteCustomResourceInputParams{}) + + //cronJob + RegisterTask(k8s.CronJobService().GetCronJobList, k8s.GetCronJobListInputParams{}) + RegisterTask(k8s.CronJobService().GetCronJobDetails, k8s.GetCronJobInputParams{}) + RegisterTask(k8s.CronJobService().DeployCronJob, k8s.DeployCronJobInputParams{}) + RegisterTask(k8s.CronJobService().DeleteCronJob, k8s.DeleteCronJobInputParams{}) + +} diff --git a/pkg/tasks/tasks.go b/pkg/tasks/tasks.go index ae56a27..ca1bf75 100644 --- a/pkg/tasks/tasks.go +++ b/pkg/tasks/tasks.go @@ -1,7 +1,6 @@ package tasks import ( - "github.com/krack8/lighthouse/pkg/k8s" "github.com/krack8/lighthouse/pkg/log" "reflect" "runtime" @@ -50,45 +49,6 @@ func GetTask(taskName string) *Task { return task } -func InitTaskRegistry() { - //namespace - RegisterTask(k8s.NamespaceService().GetNamespaceList, k8s.GetNamespaceListInputParams{}) - RegisterTask(k8s.NamespaceService().GetNamespaceNameList, k8s.GetNamespaceNamesInputParams{}) - RegisterTask(k8s.NamespaceService().GetNamespaceDetails, k8s.GetNamespaceInputParams{}) - RegisterTask(k8s.NamespaceService().DeployNamespace, k8s.DeployNamespaceInputParams{}) - RegisterTask(k8s.NamespaceService().DeleteNamespace, k8s.DeleteNamespaceInputParams{}) - - //certficate - RegisterTask(k8s.CertificateService().GetCertificateList, k8s.GetCertificateListInputParams{}) - RegisterTask(k8s.CertificateService().GetCertificateDetails, k8s.GetCertificateDetailsInputParams{}) - RegisterTask(k8s.CertificateService().DeployCertificate, k8s.DeployCertificateInputParams{}) - RegisterTask(k8s.CertificateService().DeleteCertificate, k8s.DeleteCertificateInputParams{}) - - //clusterRole - RegisterTask(k8s.ClusterRoleService().GetClusterRoleList, k8s.GetClusterRoleListInputParams{}) - RegisterTask(k8s.ClusterRoleService().GetClusterRoleDetails, k8s.GetClusterRoleDetailsInputParams{}) - RegisterTask(k8s.ClusterRoleService().DeployClusterRole, k8s.DeployClusterRoleInputParams{}) - RegisterTask(k8s.ClusterRoleService().DeleteClusterRole, k8s.DeleteClusterRoleInputParams{}) - - //clusterRoleBinding - RegisterTask(k8s.ClusterRoleBindingService().GetClusterRoleBindingList, k8s.GetClusterRoleBindingListInputParams{}) - RegisterTask(k8s.ClusterRoleBindingService().GetClusterRoleBindingDetails, k8s.GetClusterRoleBindingDetailsInputParams{}) - RegisterTask(k8s.ClusterRoleBindingService().DeployClusterRoleBinding, k8s.DeployClusterRoleBindingInputParams{}) - RegisterTask(k8s.ClusterRoleBindingService().DeleteClusterRoleBinding, k8s.DeleteClusterRoleBindingInputParams{}) - - //configMap - RegisterTask(k8s.ConfigMapService().GetConfigMapList, k8s.GetConfigMapListInputParams{}) - RegisterTask(k8s.ConfigMapService().GetConfigMapDetails, k8s.GetConfigMapDetailsInputParams{}) - RegisterTask(k8s.ConfigMapService().DeployConfigMap, k8s.DeployConfigMapInputParams{}) - RegisterTask(k8s.ConfigMapService().DeleteConfigMap, k8s.DeleteConfigMapInputParams{}) - - //controllerRevision - RegisterTask(k8s.ControllerRevisionService().GetControllerRevisionList, k8s.GetControllerRevisionListInputParams{}) - RegisterTask(k8s.ControllerRevisionService().GetControllerRevisionDetails, k8s.GetControllerRevisionDetailsInputParams{}) - RegisterTask(k8s.ControllerRevisionService().DeployControllerRevision, k8s.DeployControllerRevisionInputParams{}) - RegisterTask(k8s.ControllerRevisionService().DeleteControllerRevision, k8s.DeleteControllerRevisionInputParams{}) -} - func GetFuncName(funcTask interface{}) string { functionName := runtime.FuncForPC(reflect.ValueOf(funcTask).Pointer()).Name() lastDotIndex := strings.LastIndex(functionName, ".") From d51c58452b392b156f140f043dcf1bc92d39060f Mon Sep 17 00:00:00 2001 From: Toha Date: Mon, 27 Jan 2025 23:26:42 +0600 Subject: [PATCH 10/64] agent task selector upto HPA --- pkg/tasks/agent_task_selector.go | 336 +++++++++++++++++++++++++++++++ 1 file changed, 336 insertions(+) diff --git a/pkg/tasks/agent_task_selector.go b/pkg/tasks/agent_task_selector.go index 366134b..f16876c 100644 --- a/pkg/tasks/agent_task_selector.go +++ b/pkg/tasks/agent_task_selector.go @@ -588,6 +588,342 @@ func TaskSelector(task *pb.Task) (interface{}, error) { return nil, err } return res, nil + //daemonSet + case k8s.GetDaemonSetListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetDaemonSetListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetDaemonSetDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetDaemonSetDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployDaemonSetInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployDaemonSetInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteDaemonSetInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteDaemonSetInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //deployment + case k8s.GetDeploymentListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetDeploymentListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetDeploymentDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetDeploymentDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployDeploymentInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployDeploymentInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteDeploymentInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteDeploymentInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetDeploymentStatsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetDeploymentStatsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetDeploymentPodListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetDeploymentPodListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //endpoints + case k8s.GetEndpointsListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetEndpointsListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetEndpointsDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetEndpointsDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployEndpointsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployEndpointsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteEndpointsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteEndpointsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //endpointSlice + case k8s.GetEndpointSliceListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetEndpointSliceListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetEndpointSliceDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetEndpointSliceDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployEndpointSliceInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployEndpointSliceInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteEndpointSliceInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteEndpointSliceInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //event + case k8s.GetEventListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetEventListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetEventDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetEventDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //hpa + case k8s.GetHpaListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetHpaListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetHpaDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetHpaDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil default: return nil, ErrUnexpectedTask } From e4141d723bfcff2018864b8ee00facdf849c9538 Mon Sep 17 00:00:00 2001 From: Toha Date: Mon, 27 Jan 2025 23:42:22 +0600 Subject: [PATCH 11/64] agent task selector upto Node --- pkg/tasks/agent_task_selector.go | 276 +++++++++++++++++++++++++++++++ 1 file changed, 276 insertions(+) diff --git a/pkg/tasks/agent_task_selector.go b/pkg/tasks/agent_task_selector.go index f16876c..58bed0e 100644 --- a/pkg/tasks/agent_task_selector.go +++ b/pkg/tasks/agent_task_selector.go @@ -924,6 +924,282 @@ func TaskSelector(task *pb.Task) (interface{}, error) { return nil, err } return res, nil + //ingress + case k8s.GetIngressListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetIngressListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetIngressDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetIngressDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployIngressInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployIngressInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteIngressInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteIngressInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //istioGateway + case k8s.GetIstioGatewayListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetIstioGatewayListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetIstioGatewayDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetIstioGatewayDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployIstioGatewayInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployIstioGatewayInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteIstioGatewayInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteIstioGatewayInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //loadBalancer + case k8s.GetLoadBalancerListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetLoadBalancerListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetLoadBalancerDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetLoadBalancerDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //manifest + case k8s.DeployManifestInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployManifestInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //network + case k8s.GetNetworkPolicyListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetNetworkPolicyListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetNetworkPolicyDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetNetworkPolicyDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //node + case k8s.GetNodeListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetNodeListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetNodeInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetNodeInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.NodeCordonInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.NodeCordonInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.NodeTaintInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.NodeTaintInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.NodeUnTaintInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.NodeUnTaintInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil default: return nil, ErrUnexpectedTask } From c2ffd1c35d0c105016b730a16df69051906a81b1 Mon Sep 17 00:00:00 2001 From: Toha Date: Tue, 28 Jan 2025 13:22:38 +0600 Subject: [PATCH 12/64] agent task selector upto role binding --- pkg/tasks/agent_task_selector.go | 610 +++++++++++++++++++++++++++++++ 1 file changed, 610 insertions(+) diff --git a/pkg/tasks/agent_task_selector.go b/pkg/tasks/agent_task_selector.go index 58bed0e..8535af8 100644 --- a/pkg/tasks/agent_task_selector.go +++ b/pkg/tasks/agent_task_selector.go @@ -1200,6 +1200,616 @@ func TaskSelector(task *pb.Task) (interface{}, error) { return nil, err } return res, nil + //pod + case k8s.GetPodListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetPodListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetPodDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetPodDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetPodStatsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetPodStatsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetPodLogsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetPodLogsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployPodInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployPodInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeletePodInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeletePodInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //podDisruptionBudget + case k8s.GetPodDisruptionBudgetsListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetPodDisruptionBudgetsListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetPodDisruptionBudgetsDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetPodDisruptionBudgetsDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployPodDisruptionBudgetsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployPodDisruptionBudgetsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeletePodDisruptionBudgetsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeletePodDisruptionBudgetsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //podMetrics + case k8s.GetPodMetricsListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetPodMetricsListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetPodMetricsDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetPodMetricsDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //pv + case k8s.GetPvListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetPvListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetPvDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetPvDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployPvInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployPvInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeletePvInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeletePvInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //pvc + case k8s.GetPvcListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetPvcListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetPvcDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetPvcDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployPvcInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployPvcInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeletePvcInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeletePvcInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //replicaset + case k8s.GetReplicaSetListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetReplicaSetListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetReplicaSetDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetReplicaSetDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployReplicaSetInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployReplicaSetInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteReplicaSetInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteReplicaSetInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //replicationController + case k8s.GetReplicationControllerListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetReplicationControllerListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetReplicationControllerDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetReplicationControllerDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployReplicationControllerInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployReplicationControllerInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteReplicationControllerInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteReplicationControllerInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //resourceQuota + case k8s.GetResourceQuotaListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetResourceQuotaListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetResourceQuotaDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetResourceQuotaDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployResourceQuotaInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployResourceQuotaInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteResourceQuotaInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteResourceQuotaInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //role + case k8s.GetRoleListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetRoleListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetRoleDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetRoleDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployRoleInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployRoleInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteRoleInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteRoleInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //roleBinding + case k8s.GetRoleBindingListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetRoleBindingListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetRoleBindingDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetRoleBindingDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployRoleBindingInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployRoleBindingInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteRoleBindingInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteRoleBindingInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil default: return nil, ErrUnexpectedTask } From 98a8c5f3509a9fa254f6488c7bc2347f7208644f Mon Sep 17 00:00:00 2001 From: Toha Date: Tue, 28 Jan 2025 13:33:40 +0600 Subject: [PATCH 13/64] agent task selector all resources added --- pkg/tasks/agent_task_selector.go | 519 +++++++++++++++++++++++++++++++ 1 file changed, 519 insertions(+) diff --git a/pkg/tasks/agent_task_selector.go b/pkg/tasks/agent_task_selector.go index 8535af8..ed91133 100644 --- a/pkg/tasks/agent_task_selector.go +++ b/pkg/tasks/agent_task_selector.go @@ -1810,6 +1810,525 @@ func TaskSelector(task *pb.Task) (interface{}, error) { return nil, err } return res, nil + //sa + case k8s.GetServiceAccountListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetServiceAccountListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetServiceAccountDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetServiceAccountDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployServiceAccountInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployServiceAccountInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteServiceAccountInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteServiceAccountInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //secret + case k8s.GetSecretListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetSecretListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetSecretDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetSecretDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeploySecretInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeploySecretInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteSecretInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteSecretInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //statefulSet + case k8s.GetStatefulSetListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetStatefulSetListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetStatefulSetDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetStatefulSetDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetStatefulSetPodListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetStatefulSetPodListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetStatefulSetStatsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetStatefulSetStatsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployStatefulSetInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployStatefulSetInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteStatefulSetInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteStatefulSetInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //storageClass + case k8s.GetStorageClassListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetStorageClassListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetStorageClassDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetStorageClassDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployStorageClassInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployStorageClassInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteStorageClassInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteStorageClassInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //svc + case k8s.GetSvcListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetSvcListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetSvcDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetSvcDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeploySvcInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeploySvcInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteSvcInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteSvcInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //virtualService + case k8s.GetVirtualServiceListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetVirtualServiceListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetVirtualServiceDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetVirtualServiceDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployVirtualServiceInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployVirtualServiceInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteVirtualServiceInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteVirtualServiceInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //volumeSnapshot + case k8s.GetVolumeSnapshotListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetVolumeSnapshotListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetVolumeSnapshotDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetVolumeSnapshotDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployVolumeSnapshotInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployVolumeSnapshotInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteVolumeSnapshotInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteVolumeSnapshotInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //volumeSnapshotClass + case k8s.GetVolumeSnapshotClassListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetVolumeSnapshotClassListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetVolumeSnapshotClassDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetVolumeSnapshotClassDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + //volumeSnapshotContent + case k8s.GetVolumeSnapshotContentListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetVolumeSnapshotContentListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetVolumeSnapshotContentDetailsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetVolumeSnapshotContentDetailsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil default: return nil, ErrUnexpectedTask } From 9078add48bade4c5f05d7223f66b491c97ba29f3 Mon Sep 17 00:00:00 2001 From: Toha Date: Tue, 28 Jan 2025 14:13:51 +0600 Subject: [PATCH 14/64] daemonset, deployment, endpoints, endpointslice, endpoints, endpointslice, event, hpa, ingress, istio gateway controller --- pkg/controller/api/daemonset.go | 210 ++++++++++++++++++++++ pkg/controller/api/deployment.go | 266 ++++++++++++++++++++++++++++ pkg/controller/api/endpoints.go | 164 +++++++++++++++++ pkg/controller/api/endpointslice.go | 162 +++++++++++++++++ pkg/controller/api/event.go | 102 +++++++++++ pkg/controller/api/hpa.go | 99 +++++++++++ pkg/controller/api/ingress.go | 166 +++++++++++++++++ pkg/controller/api/istio_gateway.go | 166 +++++++++++++++++ pkg/server/router/routes.go | 39 ++++ pkg/tasks/agent_task_selector.go | 15 ++ pkg/tasks/register_tasks.go | 46 +++++ 11 files changed, 1435 insertions(+) create mode 100644 pkg/controller/api/daemonset.go create mode 100644 pkg/controller/api/deployment.go create mode 100644 pkg/controller/api/endpoints.go create mode 100644 pkg/controller/api/endpointslice.go create mode 100644 pkg/controller/api/event.go create mode 100644 pkg/controller/api/hpa.go create mode 100644 pkg/controller/api/ingress.go create mode 100644 pkg/controller/api/istio_gateway.go diff --git a/pkg/controller/api/daemonset.go b/pkg/controller/api/daemonset.go new file mode 100644 index 0000000..c9b3aa7 --- /dev/null +++ b/pkg/controller/api/daemonset.go @@ -0,0 +1,210 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + appsv1 "k8s.io/api/apps/v1" +) + +type DaemonSetControllerInterface interface { + GetDaemonSetList(ctx *gin.Context) + GetDaemonSetDetails(ctx *gin.Context) + DeployDaemonSet(ctx *gin.Context) + DeleteDaemonSet(ctx *gin.Context) + GetDaemonSetStats(ctx *gin.Context) +} + +type daemonSetController struct { +} + +var dsc daemonSetController + +func DaemonSetController() *daemonSetController { + return &dsc +} + +func (ctrl *daemonSetController) GetDaemonSetList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetDaemonSetListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for DaemonSet List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.DaemonSetService().GetDaemonSetList) + logRequestedTaskController("daemonSet", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *daemonSetController) GetDaemonSetDetails(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetDaemonSetDetailsInputParams) + input.DaemonSetName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.DaemonSetService().GetDaemonSetDetails) + logRequestedTaskController("daemonSet", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *daemonSetController) DeployDaemonSet(ctx *gin.Context) { + var result ResponseDTO + payload := new(appsv1.DaemonSet) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy daemonSet payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployDaemonSetInputParams) + input.DaemonSet = payload + if input.DaemonSet.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "daemonSet deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.DaemonSetService().DeployDaemonSet) + logRequestedTaskController("daemonSet", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *daemonSetController) DeleteDaemonSet(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteDaemonSetInputParams) + input.DaemonSetName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.DaemonSetService().DeleteDaemonSet) + logRequestedTaskController("daemonSet", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *daemonSetController) GetDaemonSetStats(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetDaemonSetStatsInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for DaemonSet List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.DaemonSetService().GetDaemonSetStats) + logRequestedTaskController("daemonSet", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/deployment.go b/pkg/controller/api/deployment.go new file mode 100644 index 0000000..9a50ff0 --- /dev/null +++ b/pkg/controller/api/deployment.go @@ -0,0 +1,266 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + appsv1 "k8s.io/api/apps/v1" +) + +type DeploymentControllerInterface interface { + GetDeploymentList(ctx *gin.Context) + GetDeploymentDetails(ctx *gin.Context) + DeployDeployment(ctx *gin.Context) + DeleteDeployment(ctx *gin.Context) + GetDeploymentStats(ctx *gin.Context) + GetDeploymentPodList(ctx *gin.Context) +} + +type deploymentController struct { +} + +var dc deploymentController + +func DeploymentController() *deploymentController { + return &dc +} + +func (ctrl *deploymentController) GetDeploymentList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetDeploymentListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for Deployment List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.DeploymentService().GetDeploymentList) + logRequestedTaskController("deployment", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *deploymentController) GetDeploymentDetails(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetDeploymentDetailsInputParams) + input.DeploymentName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.DeploymentService().GetDeploymentDetails) + logRequestedTaskController("deployment", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *deploymentController) DeployDeployment(ctx *gin.Context) { + var result ResponseDTO + payload := new(appsv1.Deployment) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy deployment payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployDeploymentInputParams) + input.Deployment = payload + if input.Deployment.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "deployment deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.DeploymentService().DeployDeployment) + logRequestedTaskController("deployment", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *deploymentController) DeleteDeployment(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteDeploymentInputParams) + input.DeploymentName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.DeploymentService().DeleteDeployment) + logRequestedTaskController("deployment", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *deploymentController) GetDeploymentStats(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetDeploymentStatsInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for Deployment List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.DeploymentService().GetDeploymentStats) + logRequestedTaskController("deployment", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *deploymentController) GetDeploymentPodList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetDeploymentPodListInputParams) + input.DeploymentName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + queryReplicaSet := ctx.Query("rs") + if queryReplicaSet == "" { + log.Logger.Errorw("rs required in query params", "rs", queryReplicaSet) + SendErrorResponse(ctx, "rs required in query params") + return + } + input.Replicaset = queryReplicaSet + input.Continue = ctx.Query("continue") + input.Search = ctx.Query("q") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for Pod List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.DeploymentService().GetDeploymentPodList) + logRequestedTaskController("deployment", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/endpoints.go b/pkg/controller/api/endpoints.go new file mode 100644 index 0000000..4d5a340 --- /dev/null +++ b/pkg/controller/api/endpoints.go @@ -0,0 +1,164 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + "k8s.io/api/core/v1" +) + +type EndpointsControllerInterface interface { + GetEndpointsList(ctx *gin.Context) + GetEndpointsDetails(ctx *gin.Context) + DeployEndpoints(ctx *gin.Context) + DeleteEndpoints(ctx *gin.Context) +} + +type endpointsController struct { +} + +var epc endpointsController + +func EndpointsController() *endpointsController { + return &epc +} + +func (ctrl *endpointsController) GetEndpointsList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetEndpointsListInputParams) + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for Endpoints List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + input.Namespace = ctx.Query("namespace") + input.Continue = ctx.Query("continue") + input.Search = ctx.Query("q") + input.Limit = ctx.Query("limit") + taskName := tasks.GetTaskName(k8s.EndpointsService().GetEndpointsList) + logRequestedTaskController("endpoint", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *endpointsController) GetEndpointsDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetEndpointsDetailsInputParams) + input.EndpointsName = ctx.Param("name") + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.Namespace = ctx.Query("namespace") + taskName := tasks.GetTaskName(k8s.EndpointsService().GetEndpointsDetails) + logRequestedTaskController("endpoint", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *endpointsController) DeployEndpoints(ctx *gin.Context) { + var result ResponseDTO + payload := new(v1.Endpoints) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy Endpoints payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployEndpointsInputParams) + input.Endpoints = payload + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + taskName := tasks.GetTaskName(k8s.EndpointsService().DeployEndpoints) + logRequestedTaskController("endpoint", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *endpointsController) DeleteEndpoints(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteEndpointsInputParams) + input.EndpointsName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + taskName := tasks.GetTaskName(k8s.EndpointsService().DeleteEndpoints) + logRequestedTaskController("endpoint", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/endpointslice.go b/pkg/controller/api/endpointslice.go new file mode 100644 index 0000000..319e8a2 --- /dev/null +++ b/pkg/controller/api/endpointslice.go @@ -0,0 +1,162 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + "k8s.io/api/discovery/v1" +) + +type EndpointSliceControllerInterface interface { + GetEndpointSliceList(ctx *gin.Context) + GetEndpointSliceDetails(ctx *gin.Context) + DeployEndpointSlice(ctx *gin.Context) + DeleteEndpointSlice(ctx *gin.Context) +} + +type endpointSliceController struct { +} + +var epsc endpointSliceController + +func EndpointSliceController() *endpointSliceController { + return &epsc +} + +func (ctrl *endpointSliceController) GetEndpointSliceList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetEndpointSliceListInputParams) + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for EndpointSlice List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + input.Namespace = ctx.Query("namespace") + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + taskName := tasks.GetTaskName(k8s.EndpointSliceService().GetEndpointSliceList) + logRequestedTaskController("endpoint-slice", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *endpointSliceController) GetEndpointSliceDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetEndpointSliceDetailsInputParams) + input.EndpointSliceName = ctx.Param("name") + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.Namespace = ctx.Query("namespace") + taskName := tasks.GetTaskName(k8s.EndpointSliceService().GetEndpointSliceDetails) + logRequestedTaskController("endpoint-slice", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *endpointSliceController) DeployEndpointSlice(ctx *gin.Context) { + var result ResponseDTO + payload := new(v1.EndpointSlice) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy endpointSlice payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployEndpointSliceInputParams) + input.EndpointSlice = payload + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + taskName := tasks.GetTaskName(k8s.EndpointSliceService().DeployEndpointSlice) + logRequestedTaskController("endpoint-slice", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *endpointSliceController) DeleteEndpointSlice(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteEndpointSliceInputParams) + input.EndpointSliceName = ctx.Param("name") + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + taskName := tasks.GetTaskName(k8s.EndpointSliceService().DeleteEndpointSlice) + logRequestedTaskController("endpoint-slice", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/event.go b/pkg/controller/api/event.go new file mode 100644 index 0000000..0c345a7 --- /dev/null +++ b/pkg/controller/api/event.go @@ -0,0 +1,102 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" +) + +type EventControllerInterface interface { + GetEventList(ctx *gin.Context) + GetEventDetails(ctx *gin.Context) +} + +type eventController struct { +} + +var ec eventController + +func EventController() *eventController { + return &ec +} + +func (ctrl *eventController) GetEventList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetEventListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + + queryInvolvedObjectName := ctx.Query("involved_object_name") + input.InvolvedObjectName = queryInvolvedObjectName + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for Event List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.EventService().GetEventList) + logRequestedTaskController("event", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *eventController) GetEventDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetEventDetailsInputParams) + input.EventName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.EventService().GetEventDetails) + logRequestedTaskController("event", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/hpa.go b/pkg/controller/api/hpa.go new file mode 100644 index 0000000..dbacca6 --- /dev/null +++ b/pkg/controller/api/hpa.go @@ -0,0 +1,99 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" +) + +type HpaControllerInterface interface { + GetHpaList(ctx *gin.Context) + GetHpaDetails(ctx *gin.Context) +} + +type hpaController struct { +} + +var hpac hpaController + +func HpaController() *hpaController { + return &hpac +} + +func (ctrl *hpaController) GetHpaList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetHpaListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for Hpa List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.HpaService().GetHpaList) + logRequestedTaskController("hpa", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *hpaController) GetHpaDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetHpaDetailsInputParams) + input.HpaName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.HpaService().GetHpaDetails) + logRequestedTaskController("hpa", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/ingress.go b/pkg/controller/api/ingress.go new file mode 100644 index 0000000..4dbddce --- /dev/null +++ b/pkg/controller/api/ingress.go @@ -0,0 +1,166 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + networkingv1 "k8s.io/api/networking/v1" +) + +type IngressControllerInterface interface { + GetIngressList(ctx *gin.Context) + GetIngressDetails(ctx *gin.Context) + DeployIngress(ctx *gin.Context) + DeleteIngress(ctx *gin.Context) +} + +type ingressController struct { +} + +var ic ingressController + +func IngressController() *ingressController { + return &ic +} + +func (ctrl *ingressController) GetIngressList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetIngressListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for Ingress List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.IngressService().GetIngressList) + logRequestedTaskController("ingress", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *ingressController) GetIngressDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetIngressDetailsInputParams) + input.IngressName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.IngressService().GetIngressDetails) + logRequestedTaskController("ingress", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *ingressController) DeployIngress(ctx *gin.Context) { + var result ResponseDTO + payload := new(networkingv1.Ingress) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy Ingress payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployIngressInputParams) + input.Ingress = payload + if input.Ingress.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "ingress deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.IngressService().DeployIngress) + logRequestedTaskController("ingress", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *ingressController) DeleteIngress(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteIngressInputParams) + input.IngressName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.IngressService().DeleteIngress) + logRequestedTaskController("ingress", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/istio_gateway.go b/pkg/controller/api/istio_gateway.go new file mode 100644 index 0000000..2b3a948 --- /dev/null +++ b/pkg/controller/api/istio_gateway.go @@ -0,0 +1,166 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + "istio.io/client-go/pkg/apis/networking/v1beta1" +) + +type IstioGatewayControllerInterface interface { + GetIstioGatewayList(ctx *gin.Context) + GetIstioGatewayDetails(ctx *gin.Context) + DeployIstioGateway(ctx *gin.Context) + DeleteIstioGateway(ctx *gin.Context) +} + +type istioGatewayController struct { +} + +var igc istioGatewayController + +func IstioGatewayController() *istioGatewayController { + return &igc +} + +func (ctrl *istioGatewayController) GetIstioGatewayList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetIstioGatewayListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for IstioGateway List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.IstioGatewayService().GetIstioGatewayList) + logRequestedTaskController("istio-gateway", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *istioGatewayController) GetIstioGatewayDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetIstioGatewayDetailsInputParams) + input.IstioGatewayName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.IstioGatewayService().GetIstioGatewayDetails) + logRequestedTaskController("istio-gateway", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *istioGatewayController) DeployIstioGateway(ctx *gin.Context) { + var result ResponseDTO + payload := new(v1beta1.Gateway) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy IstioGateway payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployIstioGatewayInputParams) + input.IstioGateway = payload + if input.IstioGateway.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "istioGateway deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.IstioGatewayService().DeployIstioGateway) + logRequestedTaskController("istio-gateway", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *istioGatewayController) DeleteIstioGateway(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteIstioGatewayInputParams) + input.IstioGatewayName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.IstioGatewayService().DeleteIstioGateway) + logRequestedTaskController("istio-gateway", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index c456bfb..e3dca42 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -62,4 +62,43 @@ func AddApiRoutes(httpRg *gin.RouterGroup) { httpRg.GET("api/v1/cronjob/:name", api.CronJobController().GetCronJobDetails) httpRg.POST("api/v1/cronjob", api.CronJobController().DeployCronJob) httpRg.DELETE("api/v1/cronjob/:name", api.CronJobController().DeleteCronJob) + // Daemonset + httpRg.GET("api/v1/daemonset", api.DaemonSetController().GetDaemonSetList) + httpRg.GET("api/v1/daemonset/:name", api.DaemonSetController().GetDaemonSetDetails) + httpRg.POST("api/v1/daemonset", api.DaemonSetController().DeployDaemonSet) + httpRg.DELETE("api/v1/daemonset/:name", api.DaemonSetController().DeleteDaemonSet) + httpRg.GET("api/v1/daemonset/stats", api.DaemonSetController().GetDaemonSetStats) + // Deployment + httpRg.GET("api/v1/deployment", api.DeploymentController().GetDeploymentList) + httpRg.GET("api/v1/deployment/:name", api.DeploymentController().GetDeploymentDetails) + httpRg.POST("api/v1/deployment", api.DeploymentController().DeployDeployment) + httpRg.DELETE("api/v1/deployment/:name", api.DeploymentController().DeleteDeployment) + httpRg.GET("api/v1/deployment/stats", api.DeploymentController().GetDeploymentStats) + httpRg.GET("api/v1/deployment/:name/pods", api.DeploymentController().GetDeploymentPodList) + // Endpoints + httpRg.GET("api/v1/endpoints", api.EndpointsController().GetEndpointsList) + httpRg.GET("api/v1/endpoints/:name", api.EndpointsController().GetEndpointsDetails) + httpRg.POST("api/v1/endpoints", api.EndpointsController().DeployEndpoints) + httpRg.DELETE("api/v1/endpoints/:name", api.EndpointsController().DeleteEndpoints) + // EndpointSlice + httpRg.GET("api/v1/endpoint-slice", api.EndpointSliceController().GetEndpointSliceList) + httpRg.GET("api/v1/endpoint-slice/:name", api.EndpointSliceController().GetEndpointSliceDetails) + httpRg.POST("api/v1/endpoint-slice", api.EndpointSliceController().DeployEndpointSlice) + httpRg.DELETE("api/v1/endpoint-slice/:name", api.EndpointSliceController().DeleteEndpointSlice) + // event + httpRg.GET("api/v1/event", api.EventController().GetEventList) + httpRg.GET("api/v1/event/:name", api.EventController().GetEventDetails) + // HPA + httpRg.GET("api/v1/hpa", api.HpaController().GetHpaList) + httpRg.GET("api/v1/hpa/:name", api.HpaController().GetHpaDetails) + // Ingress + httpRg.GET("api/v1/ingress", api.IngressController().GetIngressList) + httpRg.GET("api/v1/ingress/:name", api.IngressController().GetIngressDetails) + httpRg.POST("api/v1/ingress", api.IngressController().DeployIngress) + httpRg.DELETE("api/v1/ingress/:name", api.IngressController().DeleteIngress) + // Istio Gateway + httpRg.GET("api/v1/gateway", api.IstioGatewayController().GetIstioGatewayList) + httpRg.GET("api/v1/gateway/:name", api.IstioGatewayController().GetIstioGatewayDetails) + httpRg.POST("api/v1/gateway", api.IstioGatewayController().DeployIstioGateway) + httpRg.DELETE("api/v1/gateway/:name", api.IstioGatewayController().DeleteIstioGateway) } diff --git a/pkg/tasks/agent_task_selector.go b/pkg/tasks/agent_task_selector.go index ed91133..dd290a9 100644 --- a/pkg/tasks/agent_task_selector.go +++ b/pkg/tasks/agent_task_selector.go @@ -619,6 +619,21 @@ func TaskSelector(task *pb.Task) (interface{}, error) { return nil, err } return res, nil + case k8s.GetDaemonSetStatsInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetDaemonSetStatsInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil case k8s.DeployDaemonSetInputParams: logTaskStarted(task) err = json.Unmarshal([]byte(task.Input), &input) diff --git a/pkg/tasks/register_tasks.go b/pkg/tasks/register_tasks.go index 3c32f41..3cde468 100644 --- a/pkg/tasks/register_tasks.go +++ b/pkg/tasks/register_tasks.go @@ -58,4 +58,50 @@ func InitTaskRegistry() { RegisterTask(k8s.CronJobService().DeployCronJob, k8s.DeployCronJobInputParams{}) RegisterTask(k8s.CronJobService().DeleteCronJob, k8s.DeleteCronJobInputParams{}) + //daemonSet + RegisterTask(k8s.DaemonSetService().GetDaemonSetList, k8s.GetDaemonSetListInputParams{}) + RegisterTask(k8s.DaemonSetService().GetDaemonSetDetails, k8s.GetDaemonSetDetailsInputParams{}) + RegisterTask(k8s.DaemonSetService().GetDaemonSetStats, k8s.GetDaemonSetStatsInputParams{}) + RegisterTask(k8s.DaemonSetService().DeployDaemonSet, k8s.DeployDaemonSetInputParams{}) + RegisterTask(k8s.DaemonSetService().DeleteDaemonSet, k8s.DeleteDaemonSetInputParams{}) + + //deployment + RegisterTask(k8s.DeploymentService().GetDeploymentList, k8s.GetDeploymentListInputParams{}) + RegisterTask(k8s.DeploymentService().GetDeploymentDetails, k8s.GetDeploymentDetailsInputParams{}) + RegisterTask(k8s.DeploymentService().GetDeploymentStats, k8s.GetDeploymentStatsInputParams{}) + RegisterTask(k8s.DeploymentService().GetDeploymentPodList, k8s.GetDeploymentPodListInputParams{}) + RegisterTask(k8s.DeploymentService().DeployDeployment, k8s.DeployDeploymentInputParams{}) + RegisterTask(k8s.DeploymentService().DeleteDeployment, k8s.DeleteDeploymentInputParams{}) + + //endpoints + RegisterTask(k8s.EndpointsService().GetEndpointsList, k8s.GetEndpointsListInputParams{}) + RegisterTask(k8s.EndpointsService().GetEndpointsDetails, k8s.GetEndpointsDetailsInputParams{}) + RegisterTask(k8s.EndpointsService().DeployEndpoints, k8s.DeployEndpointsInputParams{}) + RegisterTask(k8s.EndpointsService().DeleteEndpoints, k8s.DeleteEndpointsInputParams{}) + + //endpointSlice + RegisterTask(k8s.EndpointSliceService().GetEndpointSliceList, k8s.GetEndpointSliceListInputParams{}) + RegisterTask(k8s.EndpointSliceService().GetEndpointSliceDetails, k8s.GetEndpointSliceDetailsInputParams{}) + RegisterTask(k8s.EndpointSliceService().DeployEndpointSlice, k8s.DeployEndpointSliceInputParams{}) + RegisterTask(k8s.EndpointSliceService().DeleteEndpointSlice, k8s.DeleteEndpointSliceInputParams{}) + + //event + RegisterTask(k8s.EventService().GetEventList, k8s.GetEventListInputParams{}) + RegisterTask(k8s.EventService().GetEventDetails, k8s.GetEventDetailsInputParams{}) + + //hpa + RegisterTask(k8s.HpaService().GetHpaList, k8s.GetHpaListInputParams{}) + RegisterTask(k8s.HpaService().GetHpaDetails, k8s.GetHpaDetailsInputParams{}) + + //ingress + RegisterTask(k8s.IngressService().GetIngressList, k8s.GetIngressListInputParams{}) + RegisterTask(k8s.IngressService().GetIngressDetails, k8s.GetIngressDetailsInputParams{}) + RegisterTask(k8s.IngressService().DeployIngress, k8s.DeployIngressInputParams{}) + RegisterTask(k8s.IngressService().DeleteIngress, k8s.DeleteIngressInputParams{}) + + //istioGateway + RegisterTask(k8s.IstioGatewayService().GetIstioGatewayList, k8s.GetIstioGatewayListInputParams{}) + RegisterTask(k8s.IstioGatewayService().GetIstioGatewayDetails, k8s.GetIstioGatewayDetailsInputParams{}) + RegisterTask(k8s.IstioGatewayService().DeployIstioGateway, k8s.DeployIstioGatewayInputParams{}) + RegisterTask(k8s.IstioGatewayService().DeleteIstioGateway, k8s.DeleteIstioGatewayInputParams{}) } From a85667ed16e432e81ecb7561ac5fedda75aadcb9 Mon Sep 17 00:00:00 2001 From: Toha Date: Tue, 28 Jan 2025 14:31:28 +0600 Subject: [PATCH 15/64] job, load balancer, manifest controller --- pkg/controller/api/job.go | 165 +++++++++++++++++ pkg/controller/api/load_balancer.go | 99 +++++++++++ pkg/controller/api/manifest.go | 68 +++++++ pkg/k8s/job.go | 267 ++++++++++++++++++++++++++++ pkg/server/router/routes.go | 10 ++ pkg/tasks/register_tasks.go | 13 ++ 6 files changed, 622 insertions(+) create mode 100644 pkg/controller/api/job.go create mode 100644 pkg/controller/api/load_balancer.go create mode 100644 pkg/controller/api/manifest.go create mode 100644 pkg/k8s/job.go diff --git a/pkg/controller/api/job.go b/pkg/controller/api/job.go new file mode 100644 index 0000000..77f6a61 --- /dev/null +++ b/pkg/controller/api/job.go @@ -0,0 +1,165 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + batchv1 "k8s.io/api/batch/v1" +) + +type JobControllerInterface interface { + GetJobList(ctx *gin.Context) + GetJobDetails(ctx *gin.Context) + DeployJob(ctx *gin.Context) + DeleteJob(ctx *gin.Context) +} + +type jobController struct { +} + +var jc jobController + +func JobController() *jobController { + return &jc +} + +func (ctrl *jobController) GetJobList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetJobListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for job List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.JobService().GetJobList) + logRequestedTaskController("job", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *jobController) GetJobDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetJobInputParams) + input.JobName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.JobService().GetJobDetails) + logRequestedTaskController("job", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *jobController) DeployJob(ctx *gin.Context) { + var result ResponseDTO + payload := new(batchv1.Job) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy job payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + input := new(k8s.DeployJobInputParams) + input.Job = payload + if input.Job.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "job deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.JobService().DeployJob) + logRequestedTaskController("job", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *jobController) DeleteJob(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteJobInputParams) + input.JobName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.JobService().DeleteJob) + logRequestedTaskController("job", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/load_balancer.go b/pkg/controller/api/load_balancer.go new file mode 100644 index 0000000..72344af --- /dev/null +++ b/pkg/controller/api/load_balancer.go @@ -0,0 +1,99 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" +) + +type LoadBalancerControllerInterface interface { + GetLoadBalancerList(ctx *gin.Context) + GetLoadBalancerDetails(ctx *gin.Context) +} + +type loadBalancerController struct { +} + +var lbc loadBalancerController + +func LoadBalancerController() *loadBalancerController { + return &lbc +} + +func (ctrl *loadBalancerController) GetLoadBalancerList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetLoadBalancerListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for LoadBalancer List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.LoadBalancerService().GetLoadBalancerList) + logRequestedTaskController("load-balancer", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *loadBalancerController) GetLoadBalancerDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetLoadBalancerDetailsInputParams) + input.LoadBalancerName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.LoadBalancerService().GetLoadBalancerDetails) + logRequestedTaskController("load-balancer", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/manifest.go b/pkg/controller/api/manifest.go new file mode 100644 index 0000000..6f35138 --- /dev/null +++ b/pkg/controller/api/manifest.go @@ -0,0 +1,68 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/dto" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" +) + +type ManifestControllerInterface interface { + DeployManifest(ctx *gin.Context) +} + +type manifestController struct { +} + +var manc manifestController + +func ManifestController() *manifestController { + return &manc +} + +func (ctrl *manifestController) DeployManifest(ctx *gin.Context) { + var result ResponseDTO + payload := new(dto.ManifestDto) + // plural resource + resource := ctx.Query("resource") + if resource == "" { + log.Logger.Errorw("resource required in query param", "value", "manifest") + SendErrorResponse(ctx, "resource required in query") + return + } + // camel case kind . ex VolumeSnapshot + kind := ctx.Query("kind") + if kind == "" { + log.Logger.Errorw("kind required in query param", "value", "manifest") + SendErrorResponse(ctx, "kind required in query") + return + } + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy Manifest payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployManifestInputParams) + input.Manifest = payload + input.Manifest.Kind = kind + input.Resource = resource + taskName := tasks.GetTaskName(k8s.ManifestService().DeployManifest) + logRequestedTaskController("load-balancer", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/k8s/job.go b/pkg/k8s/job.go new file mode 100644 index 0000000..37aa6a0 --- /dev/null +++ b/pkg/k8s/job.go @@ -0,0 +1,267 @@ +package k8s + +import ( + "context" + cfg "github.com/krack8/lighthouse/pkg/config" + "github.com/krack8/lighthouse/pkg/controller/api" + "github.com/krack8/lighthouse/pkg/log" + batchv1 "k8s.io/api/batch/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + v1 "k8s.io/client-go/kubernetes/typed/batch/v1" + "strconv" + "strings" +) + +type JobServiceInterface interface { + GetJobList(c context.Context, p GetJobListInputParams) (interface{}, error) + GetJobDetails(c context.Context, p GetJobInputParams) (interface{}, error) + DeployJob(c context.Context, p DeployJobInputParams) (interface{}, error) + DeleteJob(c context.Context, p DeleteJobInputParams) (interface{}, error) +} + +type jobService struct{} + +var js jobService + +func JobService() *jobService { + return &js +} + +type Output struct { + Result []batchv1.Job + Resource string + Remaining int64 + Total int +} + +type GetJobListInputParams struct { + NamespaceName string + Search string + Continue string + Limit string + Labels map[string]string + output Output +} + +type GetJobInputParams struct { + NamespaceName string + JobName string + output batchv1.Job +} + +func (p *GetJobListInputParams) Find(jobClient v1.JobInterface, pageSize int64) error { + log.Logger.Debugw("Entering Search mode....", "src", "job") + filteredJobs := []batchv1.Job{} + length := 0 + var nextPageToken string + nextPageToken = p.Continue + //limit := int(pageSize) + for length < int(pageSize) { + listOptions := metav1.ListOptions{Limit: pageSize, Continue: nextPageToken} + jobList, err := jobClient.List(context.Background(), listOptions) + if err != nil { + log.Logger.Errorw("Failed to get job list", "err", err.Error()) + return err + } + + for _, job := range jobList.Items { + if strings.Contains(job.Name, p.Search) { + filteredJobs = append(filteredJobs, job) + } + } + length = len(filteredJobs) + nextPageToken = jobList.Continue + if jobList.Continue == "" { + break + } + } + remaining := 0 + if nextPageToken != "" { + listOptions := metav1.ListOptions{Continue: nextPageToken} + jobList, err := jobClient.List(context.Background(), listOptions) + if err != nil { + log.Logger.Errorw("Failed to get job list", "err", err.Error()) + return err + } + for _, job := range jobList.Items { + if strings.Contains(job.Name, p.Search) { + remaining = remaining + 1 + } + } + } + p.output.Resource = nextPageToken + p.output.Result = filteredJobs + p.output.Total = len(filteredJobs) + p.output.Remaining = int64(remaining) + return nil +} + +func (p *GetJobListInputParams) Process() error { + log.Logger.Debugw("fetching job list of " + p.NamespaceName) + jobClient := cfg.GetKubeClientSet().BatchV1().Jobs(p.NamespaceName) + limit := cfg.PageLimit + if p.Limit != "" { + limit, _ = strconv.ParseInt(p.Limit, 10, 64) + } + listOptions := metav1.ListOptions{Limit: limit, Continue: p.Continue} + if p.Labels != nil { + labelSelector := metav1.LabelSelector{MatchLabels: p.Labels} + listOptions = metav1.ListOptions{ + LabelSelector: labels.Set(labelSelector.MatchLabels).String(), + } + } + var err error + var jobList *batchv1.JobList + if p.Search != "" { + //listOptions.FieldSelector = fields.OneTermEqualSelector("metadata.name", p.Search).String() + err = p.Find(jobClient, limit) + if err != nil { + log.Logger.Errorw("Failed to get job list", "err", err.Error()) + return err + } + return nil + } else { + jobList, err = jobClient.List(context.Background(), listOptions) + if err != nil { + log.Logger.Errorw("Failed to get job list", "err", err.Error()) + return err + } + + jobList, err = jobClient.List(context.Background(), listOptions) + if err != nil { + log.Logger.Errorw("Failed to get job list", "err", err.Error()) + return err + } + remaining := jobList.RemainingItemCount + if remaining != nil { + p.output.Remaining = *remaining + if p.output.Remaining == 1 { + listOptions = metav1.ListOptions{Continue: jobList.Continue} + res, err := jobClient.List(context.Background(), listOptions) + p.output.Remaining = int64(len(res.Items)) + if err != nil { + log.Logger.Errorw("Failed to get job list", "err", err.Error()) + return err + } + } + } else { + p.output.Remaining = 0 + } + p.output.Result = jobList.Items + p.output.Total = len(jobList.Items) + p.output.Resource = jobList.Continue + } + return nil +} + +func (svc *jobService) GetJobList(c context.Context, p GetJobListInputParams) (interface{}, error) { + err := p.Process() + if err != nil { + return api.ErrorResponse(err) + } + + return api.ResponseDTO{ + Status: "success", + Data: p.output, + }, nil +} + +func (p *GetJobInputParams) Process() error { + log.Logger.Debugw("fetching job details of ....", p.NamespaceName) + jobs := cfg.GetKubeClientSet().BatchV1().Jobs(p.NamespaceName) + output, err := jobs.Get(context.Background(), p.JobName, metav1.GetOptions{}) + if err != nil { + log.Logger.Errorw("Failed to get job ", p.JobName, "err", err.Error()) + return err + } + p.output = *output + return nil +} + +func (svc *jobService) GetJobDetails(c context.Context, p GetJobInputParams) (interface{}, error) { + err := p.Process() + if err != nil { + return api.ErrorResponse(err) + } + + return api.ResponseDTO{ + Status: "success", + Data: p.output, + }, nil +} + +type DeployJobInputParams struct { + Job *batchv1.Job + output *batchv1.Job +} + +func (p *DeployJobInputParams) Process(c context.Context) error { + jobClient := cfg.GetKubeClientSet().BatchV1().Jobs(p.Job.Namespace) + _, err := jobClient.Get(context.Background(), p.Job.Name, metav1.GetOptions{}) + if err != nil { + log.Logger.Infow("Creating job in namespace "+p.Job.Namespace, "value", p.Job.Name) + p.output, err = jobClient.Create(context.Background(), p.Job, metav1.CreateOptions{}) + if err != nil { + log.Logger.Errorw("failed to create job in namespace "+p.Job.Namespace, "err", err.Error()) + return err + } + log.Logger.Infow("job created") + } else { + log.Logger.Infow("job exist in namespace "+p.Job.Namespace, "value", p.Job.Name) + log.Logger.Infow("Updating job in namespace "+p.Job.Namespace, "value", p.Job.Name) + p.output, err = jobClient.Update(context.Background(), p.Job, metav1.UpdateOptions{}) + if err != nil { + log.Logger.Errorw("failed to update job ", p.Job.Name, "err", err.Error()) + return err + } + log.Logger.Infow("job updated") + } + return nil +} + +func (svc *jobService) DeployJob(c context.Context, p DeployJobInputParams) (interface{}, error) { + err := p.Process(c) + if err != nil { + return api.ErrorResponse(err) + } + + return api.ResponseDTO{ + Status: "success", + Data: p.output, + }, nil +} + +type DeleteJobInputParams struct { + NamespaceName string + JobName string +} + +func (p *DeleteJobInputParams) Process(c context.Context) error { + log.Logger.Debugw("deleting job of ....", p.NamespaceName) + jobClient := cfg.GetKubeClientSet().BatchV1().Jobs(p.NamespaceName) + _, err := jobClient.Get(context.Background(), p.JobName, metav1.GetOptions{}) + if err != nil { + log.Logger.Errorw("get job ", p.JobName, "err", err.Error()) + return err + } + var grace int64 = 1 + err = jobClient.Delete(context.Background(), p.JobName, metav1.DeleteOptions{GracePeriodSeconds: &grace}) + if err != nil { + log.Logger.Errorw("Failed to delete job ", p.JobName, "err", err.Error()) + return err + } + return nil +} + +func (svc *jobService) DeleteJob(c context.Context, p DeleteJobInputParams) (interface{}, error) { + err := p.Process(c) + if err != nil { + return api.ErrorResponse(err) + } + + return api.ResponseDTO{ + Status: "success", + Data: nil, + }, nil +} diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index e3dca42..65e1415 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -101,4 +101,14 @@ func AddApiRoutes(httpRg *gin.RouterGroup) { httpRg.GET("api/v1/gateway/:name", api.IstioGatewayController().GetIstioGatewayDetails) httpRg.POST("api/v1/gateway", api.IstioGatewayController().DeployIstioGateway) httpRg.DELETE("api/v1/gateway/:name", api.IstioGatewayController().DeleteIstioGateway) + //Job + httpRg.GET("api/v1/job", api.JobController().GetJobList) + httpRg.GET("api/v1/job/:name", api.JobController().GetJobDetails) + httpRg.POST("api/v1/job", api.JobController().DeployJob) + httpRg.DELETE("api/v1/job/:name", api.JobController().DeleteJob) + //Load Balancer + httpRg.GET("api/v1/load-balancer", api.LoadBalancerController().GetLoadBalancerList) + httpRg.GET("api/v1/load-balancer/:name", api.LoadBalancerController().GetLoadBalancerDetails) + // Manifest + httpRg.POST("api/v1/manifest", api.ManifestController().DeployManifest) } diff --git a/pkg/tasks/register_tasks.go b/pkg/tasks/register_tasks.go index 3cde468..4e820e9 100644 --- a/pkg/tasks/register_tasks.go +++ b/pkg/tasks/register_tasks.go @@ -104,4 +104,17 @@ func InitTaskRegistry() { RegisterTask(k8s.IstioGatewayService().GetIstioGatewayDetails, k8s.GetIstioGatewayDetailsInputParams{}) RegisterTask(k8s.IstioGatewayService().DeployIstioGateway, k8s.DeployIstioGatewayInputParams{}) RegisterTask(k8s.IstioGatewayService().DeleteIstioGateway, k8s.DeleteIstioGatewayInputParams{}) + + //job + RegisterTask(k8s.JobService().GetJobList, k8s.GetJobListInputParams{}) + RegisterTask(k8s.JobService().GetJobDetails, k8s.GetJobInputParams{}) + RegisterTask(k8s.JobService().DeployJob, k8s.DeployJobInputParams{}) + RegisterTask(k8s.JobService().DeleteJob, k8s.DeleteJobInputParams{}) + + //loadBalancer + RegisterTask(k8s.LoadBalancerService().GetLoadBalancerList, k8s.GetLoadBalancerListInputParams{}) + RegisterTask(k8s.LoadBalancerService().GetLoadBalancerDetails, k8s.GetLoadBalancerDetailsInputParams{}) + + //Manifest + RegisterTask(k8s.ManifestService().DeployManifest, k8s.DeployManifestInputParams{}) } From aa14e9309b8d3228bbddb1718ecbeebfc0a23a9e Mon Sep 17 00:00:00 2001 From: Toha Date: Tue, 28 Jan 2025 15:57:29 +0600 Subject: [PATCH 16/64] import fix --- pkg/controller/worker/controller.go | 1 - pkg/k8s/job.go | 17 ++++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/pkg/controller/worker/controller.go b/pkg/controller/worker/controller.go index 3e89764..65f888f 100644 --- a/pkg/controller/worker/controller.go +++ b/pkg/controller/worker/controller.go @@ -290,5 +290,4 @@ func StartGrpcServer() { log.Fatalf("Failed to serve gRPC: %v", err) } }() - http.HandleFunc("/execute", srv.httpExecuteHandler) } diff --git a/pkg/k8s/job.go b/pkg/k8s/job.go index 37aa6a0..fc3e759 100644 --- a/pkg/k8s/job.go +++ b/pkg/k8s/job.go @@ -3,7 +3,6 @@ package k8s import ( "context" cfg "github.com/krack8/lighthouse/pkg/config" - "github.com/krack8/lighthouse/pkg/controller/api" "github.com/krack8/lighthouse/pkg/log" batchv1 "k8s.io/api/batch/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -158,10 +157,10 @@ func (p *GetJobListInputParams) Process() error { func (svc *jobService) GetJobList(c context.Context, p GetJobListInputParams) (interface{}, error) { err := p.Process() if err != nil { - return api.ErrorResponse(err) + return ErrorResponse(err) } - return api.ResponseDTO{ + return ResponseDTO{ Status: "success", Data: p.output, }, nil @@ -182,10 +181,10 @@ func (p *GetJobInputParams) Process() error { func (svc *jobService) GetJobDetails(c context.Context, p GetJobInputParams) (interface{}, error) { err := p.Process() if err != nil { - return api.ErrorResponse(err) + return ErrorResponse(err) } - return api.ResponseDTO{ + return ResponseDTO{ Status: "success", Data: p.output, }, nil @@ -223,10 +222,10 @@ func (p *DeployJobInputParams) Process(c context.Context) error { func (svc *jobService) DeployJob(c context.Context, p DeployJobInputParams) (interface{}, error) { err := p.Process(c) if err != nil { - return api.ErrorResponse(err) + return ErrorResponse(err) } - return api.ResponseDTO{ + return ResponseDTO{ Status: "success", Data: p.output, }, nil @@ -257,10 +256,10 @@ func (p *DeleteJobInputParams) Process(c context.Context) error { func (svc *jobService) DeleteJob(c context.Context, p DeleteJobInputParams) (interface{}, error) { err := p.Process(c) if err != nil { - return api.ErrorResponse(err) + return ErrorResponse(err) } - return api.ResponseDTO{ + return ResponseDTO{ Status: "success", Data: nil, }, nil From 150a0a416e9e9dc642c681ba6c5f11a353d265e8 Mon Sep 17 00:00:00 2001 From: Nahid Date: Tue, 28 Jan 2025 17:55:02 +0600 Subject: [PATCH 17/64] refactor: gin implementation in user routes --- go.mod | 15 +++--- go.sum | 28 +++++----- pkg/auth/controllers/auth_controller.go | 51 +++++++++--------- .../controllers/role_permission_controller.go | 39 ++++++-------- pkg/auth/controllers/user_controller.go | 54 +++++++++---------- pkg/auth/middlewares/auth.go | 40 ++++++++------ pkg/auth/routes/auth_routes.go | 17 ------ pkg/auth/routes/rbac_routes.go | 31 ----------- pkg/auth/routes/user_routes.go | 32 ----------- pkg/auth/utils/response.go | 17 +++--- pkg/controller/main.go | 24 +++++++++ pkg/server/router/routes.go | 33 ++++++++++++ pkg/server/server.go | 24 ++++++++- 13 files changed, 198 insertions(+), 207 deletions(-) delete mode 100644 pkg/auth/routes/auth_routes.go delete mode 100644 pkg/auth/routes/rbac_routes.go delete mode 100644 pkg/auth/routes/user_routes.go diff --git a/go.mod b/go.mod index 5fcc22c..abacaf9 100644 --- a/go.mod +++ b/go.mod @@ -5,13 +5,15 @@ go 1.23.0 require ( github.com/gin-contrib/cors v1.7.3 github.com/gin-gonic/gin v1.10.0 - github.com/google/uuid v1.6.0 github.com/go-playground/validator/v10 v10.24.0 - github.com/golang-jwt/jwt/v4 v4.5.0 - github.com/joho/godotenv v1.5.1 + github.com/golang-jwt/jwt/v4 v4.5.0 + github.com/google/uuid v1.6.0 + github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 + github.com/joho/godotenv v1.5.1 github.com/kubernetes-csi/external-snapshotter/client/v6 v6.3.0 github.com/stretchr/testify v1.9.0 + go.mongodb.org/mongo-driver v1.17.2 go.uber.org/zap v1.27.0 golang.org/x/crypto v0.32.0 google.golang.org/grpc v1.69.2 @@ -63,7 +65,7 @@ require ( github.com/fatih/color v1.13.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.7 // indirect + github.com/gabriel-vasile/mimetype v1.4.8 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect @@ -74,7 +76,6 @@ require ( github.com/go-openapi/swag v0.23.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.23.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/goccy/go-json v0.10.4 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -134,6 +135,7 @@ require ( github.com/spf13/cast v1.7.0 // indirect github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect github.com/x448/float16 v0.8.4 // indirect @@ -152,8 +154,7 @@ require ( go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.12.0 // indirect - golang.org/x/crypto v0.31.0 // indirect - golang.org/x/net v0.33.0 // indirect + golang.org/x/net v0.34.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.29.0 // indirect diff --git a/go.sum b/go.sum index e56cfb7..30c9e75 100644 --- a/go.sum +++ b/go.sum @@ -126,8 +126,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA= -github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU= +github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= +github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= github.com/gin-contrib/cors v1.7.3 h1:hV+a5xp8hwJoTw7OY+a70FsL8JkVVFTXw9EcfrYUdns= github.com/gin-contrib/cors v1.7.3/go.mod h1:M3bcKZhxzsvI+rlRSkkxHyljJt1ESd93COUvemZ79j4= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= @@ -160,8 +160,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o= -github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-playground/validator/v10 v10.24.0 h1:KHQckvo8G6hlWnrPX4NJJ+aBfWNAE/HH+qdL2cBpCmg= +github.com/go-playground/validator/v10 v10.24.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -219,10 +219,10 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= -github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= -github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= -github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= @@ -485,8 +485,10 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= @@ -517,8 +519,10 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= diff --git a/pkg/auth/controllers/auth_controller.go b/pkg/auth/controllers/auth_controller.go index 7aaf783..27c2e2c 100644 --- a/pkg/auth/controllers/auth_controller.go +++ b/pkg/auth/controllers/auth_controller.go @@ -1,8 +1,8 @@ package controllers import ( - "encoding/json" "errors" + "github.com/gin-gonic/gin" "github.com/krack8/lighthouse/pkg/auth/services" "github.com/krack8/lighthouse/pkg/auth/utils" "net/http" @@ -10,84 +10,81 @@ import ( "time" ) -func LoginHandler(w http.ResponseWriter, r *http.Request) { +// LoginHandler handles user login requests +func LoginHandler(c *gin.Context) { var requestBody map[string]string - err := json.NewDecoder(r.Body).Decode(&requestBody) - if err != nil { - http.Error(w, "Invalid request body", http.StatusBadRequest) + + // Bind the request body to the map + if err := c.ShouldBindJSON(&requestBody); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) return } username := requestBody["username"] password := requestBody["password"] + // Ensure both username and password are provided if username == "" || password == "" { - http.Error(w, "Username and password are required", http.StatusBadRequest) + c.JSON(http.StatusBadRequest, gin.H{"error": "Username and password are required"}) return } + // Call the login service to get the tokens accessToken, refreshToken, err := services.Login(username, password) if err != nil { // Return structured error in JSON format - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusUnauthorized) - json.NewEncoder(w).Encode(map[string]string{ - "error": err.Error(), - }) + c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()}) return } // Return the access and refresh tokens as JSON - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - json.NewEncoder(w).Encode(map[string]string{ + c.JSON(http.StatusOK, gin.H{ "access_token": accessToken, "refresh_token": refreshToken, }) } // RefreshTokenHandler handles token refresh requests -func RefreshTokenHandler(w http.ResponseWriter, r *http.Request) { +func RefreshTokenHandler(c *gin.Context) { var request map[string]string - err := json.NewDecoder(r.Body).Decode(&request) - if err != nil { - http.Error(w, "Invalid request body", http.StatusBadRequest) + + // Bind the request body to the map + if err := c.ShouldBindJSON(&request); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) return } refreshToken := request["refresh_token"] if refreshToken == "" { - http.Error(w, "Missing refresh token", http.StatusBadRequest) + c.JSON(http.StatusBadRequest, gin.H{"error": "Missing refresh token"}) return } // Validate the refresh token claims, err := utils.ValidateToken(refreshToken, os.Getenv("JWT_REFRESH_SECRET")) if err != nil { - http.Error(w, "Invalid or expired refresh token", http.StatusUnauthorized) + c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid or expired refresh token"}) return } // Load expiry durations from environment variables accessTokenExpiry, err := parseDurationFromEnv("ACCESS_TOKEN_EXPIRY") if err != nil { - http.Error(w, "Failed to load access token expiry", http.StatusInternalServerError) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load access token expiry"}) return } // Generate a new access token accessToken, err := utils.GenerateToken(claims.Username, os.Getenv("JWT_SECRET"), accessTokenExpiry) if err != nil { - http.Error(w, "Failed to generate access token", http.StatusInternalServerError) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate access token"}) return } - // Send response - response := map[string]string{ + // Send response with the new access token + c.JSON(http.StatusOK, gin.H{ "access_token": accessToken, - } - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + }) } // Helper function to parse durations from environment variables diff --git a/pkg/auth/controllers/role_permission_controller.go b/pkg/auth/controllers/role_permission_controller.go index 8b0731b..2b65555 100644 --- a/pkg/auth/controllers/role_permission_controller.go +++ b/pkg/auth/controllers/role_permission_controller.go @@ -1,13 +1,11 @@ package controllers import ( - "encoding/json" "fmt" + "github.com/gin-gonic/gin" "github.com/krack8/lighthouse/pkg/auth/models" "github.com/krack8/lighthouse/pkg/auth/services" "net/http" - - "go.mongodb.org/mongo-driver/bson/primitive" ) type RbacController struct { @@ -15,67 +13,62 @@ type RbacController struct { } // CreatePermissionHandler handles the creation of a new permission -func (rbac *RbacController) CreatePermissionHandler(w http.ResponseWriter, r *http.Request) { +func (rbac *RbacController) CreatePermissionHandler(c *gin.Context) { var permission models.Permission - decoder := json.NewDecoder(r.Body) - if err := decoder.Decode(&permission); err != nil { - http.Error(w, "Invalid input", http.StatusBadRequest) + if err := c.ShouldBindJSON(&permission); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"}) return } // Create Permission permissionID, err := rbac.RbacService.CreatePermission(permission) if err != nil { - http.Error(w, "Error creating permission", http.StatusInternalServerError) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Error creating permission"}) return } // Respond with the ID of the created permission - w.WriteHeader(http.StatusCreated) - json.NewEncoder(w).Encode(map[string]primitive.ObjectID{"permission_id": permissionID}) + c.JSON(http.StatusCreated, gin.H{"permission_id": permissionID}) } // CreateRoleHandler handles the creation of a new role -func (rbac *RbacController) CreateRoleHandler(w http.ResponseWriter, r *http.Request) { +func (rbac *RbacController) CreateRoleHandler(c *gin.Context) { var role models.Role - decoder := json.NewDecoder(r.Body) - if err := decoder.Decode(&role); err != nil { - http.Error(w, "Invalid input", http.StatusBadRequest) + if err := c.ShouldBindJSON(&role); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"}) return } // Create Role roleID, err := rbac.RbacService.CreateRole(role) if err != nil { - http.Error(w, "Error creating role", http.StatusInternalServerError) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Error creating role"}) return } // Respond with the ID of the created role - w.WriteHeader(http.StatusCreated) - json.NewEncoder(w).Encode(map[string]primitive.ObjectID{"role_id": roleID}) + c.JSON(http.StatusCreated, gin.H{"role_id": roleID}) } // AssignRolesHandler assigns multiple roles to a user. -func (rbac *RbacController) AssignRolesHandler(w http.ResponseWriter, r *http.Request) { +func (rbac *RbacController) AssignRolesHandler(c *gin.Context) { var request struct { Username string `json:"username"` Roles []string `json:"roles"` } // Parse the JSON request body - if err := json.NewDecoder(r.Body).Decode(&request); err != nil { - http.Error(w, "Invalid request body", http.StatusBadRequest) + if err := c.ShouldBindJSON(&request); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) return } // Call the service to assign the roles err := rbac.RbacService.AssignRole(request.Username, request.Roles) if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } - w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, "Roles %v assigned to user '%s'\n", request.Roles, request.Username) + c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("Roles %v assigned to user '%s'", request.Roles, request.Username)}) } diff --git a/pkg/auth/controllers/user_controller.go b/pkg/auth/controllers/user_controller.go index c3840fd..0cc76a6 100644 --- a/pkg/auth/controllers/user_controller.go +++ b/pkg/auth/controllers/user_controller.go @@ -1,8 +1,7 @@ package controllers import ( - "encoding/json" - "github.com/gorilla/mux" + "github.com/gin-gonic/gin" "github.com/krack8/lighthouse/pkg/auth/models" "github.com/krack8/lighthouse/pkg/auth/services" "github.com/krack8/lighthouse/pkg/auth/utils" @@ -14,79 +13,74 @@ type UserController struct { } // CreateUserHandler handles the creation of a new user. -func (uc *UserController) CreateUserHandler(w http.ResponseWriter, r *http.Request) { +func (uc *UserController) CreateUserHandler(c *gin.Context) { var user models.User - if err := json.NewDecoder(r.Body).Decode(&user); err != nil { - utils.RespondWithError(w, http.StatusBadRequest, err.Error()) + if err := c.ShouldBindJSON(&user); err != nil { + utils.RespondWithError(c, http.StatusBadRequest, err.Error()) return } createdUser, err := uc.UserService.CreateUser(&user) if err != nil { - utils.RespondWithError(w, http.StatusInternalServerError, err.Error()) + utils.RespondWithError(c, http.StatusInternalServerError, err.Error()) return } - utils.RespondWithJSON(w, http.StatusCreated, createdUser) + utils.RespondWithJSON(c, http.StatusCreated, createdUser) } // GetUserHandler handles fetching a user by ID. -func (uc *UserController) GetUserHandler(w http.ResponseWriter, r *http.Request) { - params := mux.Vars(r) - id := params["id"] +func (uc *UserController) GetUserHandler(c *gin.Context) { + id := c.Param("id") user, err := uc.UserService.GetUser(id) if err != nil { - utils.RespondWithError(w, http.StatusInternalServerError, err.Error()) + utils.RespondWithError(c, http.StatusInternalServerError, err.Error()) return } - utils.RespondWithJSON(w, http.StatusOK, user) + utils.RespondWithJSON(c, http.StatusOK, user) } -// GetUserHandler handles fetching a user by ID. -func (uc *UserController) GetAllUsersHandler(w http.ResponseWriter, r *http.Request) { +// GetAllUsersHandler handles fetching all users. +func (uc *UserController) GetAllUsersHandler(c *gin.Context) { userList, err := uc.UserService.GetAllUsers() if err != nil { - utils.RespondWithError(w, http.StatusInternalServerError, err.Error()) + utils.RespondWithError(c, http.StatusInternalServerError, err.Error()) return } - utils.RespondWithJSON(w, http.StatusOK, userList) + utils.RespondWithJSON(c, http.StatusOK, userList) } // UpdateUserHandler handles updating a user's information. -func (uc *UserController) UpdateUserHandler(w http.ResponseWriter, r *http.Request) { - params := mux.Vars(r) - id := params["id"] +func (uc *UserController) UpdateUserHandler(c *gin.Context) { + id := c.Param("id") var updatedData models.User - if err := json.NewDecoder(r.Body).Decode(&updatedData); err != nil { - utils.RespondWithError(w, http.StatusBadRequest, err.Error()) + if err := c.ShouldBindJSON(&updatedData); err != nil { + utils.RespondWithError(c, http.StatusBadRequest, err.Error()) return } err := uc.UserService.UpdateUser(id, &updatedData) if err != nil { - utils.RespondWithError(w, http.StatusInternalServerError, err.Error()) + utils.RespondWithError(c, http.StatusInternalServerError, err.Error()) return } - w.Write([]byte("User updated successfully")) - utils.RespondWithJSON(w, http.StatusOK, nil) + utils.RespondWithJSON(c, http.StatusOK, gin.H{"message": "User updated successfully"}) } // DeleteUserHandler handles deleting a user by ID. -func (uc *UserController) DeleteUserHandler(w http.ResponseWriter, r *http.Request) { - params := mux.Vars(r) - id := params["id"] +func (uc *UserController) DeleteUserHandler(c *gin.Context) { + id := c.Param("id") err := uc.UserService.DeleteUser(id) if err != nil { - utils.RespondWithError(w, http.StatusInternalServerError, err.Error()) + utils.RespondWithError(c, http.StatusInternalServerError, err.Error()) return } - w.Write([]byte("User deleted successfully")) - utils.RespondWithJSON(w, http.StatusOK, nil) + utils.RespondWithJSON(c, http.StatusOK, gin.H{"message": "User deleted successfully"}) } diff --git a/pkg/auth/middlewares/auth.go b/pkg/auth/middlewares/auth.go index 321076f..228c673 100644 --- a/pkg/auth/middlewares/auth.go +++ b/pkg/auth/middlewares/auth.go @@ -3,7 +3,8 @@ package middleware import ( "context" "errors" - db "github.com/krack8/lighthouse/pkg/auth/config" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/auth/config" "github.com/krack8/lighthouse/pkg/auth/models" "github.com/krack8/lighthouse/pkg/auth/services" "github.com/krack8/lighthouse/pkg/auth/utils" @@ -15,26 +16,29 @@ import ( ) // AuthMiddleware is used to verify if a user is authenticated and authorized to access a route -func AuthMiddleware(route string, method string, next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +func AuthMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { // Extract the Authorization header - authHeader := r.Header.Get("Authorization") + authHeader := c.GetHeader("Authorization") if authHeader == "" { - http.Error(w, "Authorization token required", http.StatusUnauthorized) + c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization token required"}) + c.Abort() return } // Remove "Bearer " prefix from the token if present token := strings.TrimPrefix(authHeader, "Bearer ") if token == "" { - http.Error(w, "Authorization token is missing", http.StatusUnauthorized) + c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization token is missing"}) + c.Abort() return } // Validate token and extract claims claims, err := utils.ValidateToken(token, os.Getenv("JWT_SECRET")) if err != nil { - http.Error(w, "Invalid token", http.StatusUnauthorized) + c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + c.Abort() return } @@ -42,20 +46,23 @@ func AuthMiddleware(route string, method string, next http.Handler) http.Handler // Check if filter is not nil if filter == nil { // Handle the error - http.Error(w, "User not Found", http.StatusUnauthorized) + c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + c.Abort() return } // FindOne with error handling - result := db.UserCollection.FindOne(context.Background(), filter) + result := config.UserCollection.FindOne(context.Background(), filter) var user models.User if err := result.Decode(&user); err != nil { if errors.Is(err, mongo.ErrNoDocuments) { - http.Error(w, "User not Found", http.StatusUnauthorized) + c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + c.Abort() return } - http.Error(w, "User not Found", http.StatusUnauthorized) + c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"}) + c.Abort() return } @@ -69,13 +76,14 @@ func AuthMiddleware(route string, method string, next http.Handler) http.Handler } // Check if user has permission for the requested route and method - if !services.CheckPermission(permissions, route, method) { - http.Error(w, "Permission denied", http.StatusForbidden) + if !services.CheckPermission(permissions, c.FullPath(), c.Request.Method) { + c.JSON(http.StatusForbidden, gin.H{"error": "Permission denied"}) + c.Abort() return } } - // Forward to the next handler if authentication and authorization pass - next.ServeHTTP(w, r) - }) + // Proceed to the next handler if authentication and authorization pass + c.Next() + } } diff --git a/pkg/auth/routes/auth_routes.go b/pkg/auth/routes/auth_routes.go deleted file mode 100644 index 76a7b07..0000000 --- a/pkg/auth/routes/auth_routes.go +++ /dev/null @@ -1,17 +0,0 @@ -package routes - -import ( - "github.com/gorilla/mux" - "github.com/krack8/lighthouse/pkg/auth/controllers" -) - -// InitAuthRoutes initializes authentication-related routes -func InitAuthRoutes(router *mux.Router) { - - // Create a sub-router for auth-related endpoints - authRouter := router.PathPrefix("/auth").Subrouter() - - // Define routes - authRouter.HandleFunc("/login", controllers.LoginHandler).Methods("POST") // Login route - authRouter.HandleFunc("/refresh-token", controllers.RefreshTokenHandler).Methods("POST") // Refresh token route -} diff --git a/pkg/auth/routes/rbac_routes.go b/pkg/auth/routes/rbac_routes.go deleted file mode 100644 index de95303..0000000 --- a/pkg/auth/routes/rbac_routes.go +++ /dev/null @@ -1,31 +0,0 @@ -package routes - -import ( - "github.com/gorilla/mux" - "github.com/krack8/lighthouse/pkg/auth/controllers" - middleware "github.com/krack8/lighthouse/pkg/auth/middlewares" - "net/http" -) - -// InitPermissionRoutes initializes permission-related routes -func InitPermissionRoutes(rbacController *controllers.RbacController, router *mux.Router) { - - // Create a sub-router for permission-related endpoints - permissionRouter := router.PathPrefix("/permissions").Subrouter() - - // Create a new Permission - Protected - permissionRouter.Handle("", middleware.AuthMiddleware("/permissions", "POST", http.HandlerFunc(rbacController.CreatePermissionHandler))).Methods("POST") // Create new permission -} - -// InitRoleRoutes initializes role-related routes. -func InitRoleRoutes(rbacController *controllers.RbacController, router *mux.Router) { - - // Create a sub-router for role-related endpoints - roleRouter := router.PathPrefix("/roles").Subrouter() - - // Create a new Role - Protected - roleRouter.Handle("", middleware.AuthMiddleware("/roles", "POST", http.HandlerFunc(rbacController.CreatePermissionHandler))).Methods("POST") // Create new role - - // Assign multiple roles to a user - Protected - roleRouter.Handle("/assign/multiple", middleware.AuthMiddleware("/roles/assign/multiple", "POST", http.HandlerFunc(rbacController.AssignRolesHandler))).Methods("POST") // Create new role // Assign role to user -} diff --git a/pkg/auth/routes/user_routes.go b/pkg/auth/routes/user_routes.go deleted file mode 100644 index 31a5fbb..0000000 --- a/pkg/auth/routes/user_routes.go +++ /dev/null @@ -1,32 +0,0 @@ -package routes - -import ( - "github.com/gorilla/mux" - "github.com/krack8/lighthouse/pkg/auth/controllers" - middleware "github.com/krack8/lighthouse/pkg/auth/middlewares" - "net/http" -) - -// InitUserRoutes initializes user-related routes -func InitUserRoutes(userController *controllers.UserController, router *mux.Router) { - - // Create a sub-router for user-related endpoints - userRouter := router.PathPrefix("/users").Subrouter() - - // Define routes with authentication middleware - - // Get all users - Protected - userRouter.Handle("", middleware.AuthMiddleware("/users", "GET", http.HandlerFunc(userController.GetAllUsersHandler))).Methods("GET") - - // Get user by ID - Protected - userRouter.Handle("/{id}", middleware.AuthMiddleware("/users/{id}", "GET", http.HandlerFunc(userController.GetUserHandler))).Methods("GET") - - // Create a new user - Protected - userRouter.Handle("", middleware.AuthMiddleware("/users", "POST", http.HandlerFunc(userController.CreateUserHandler))).Methods("POST") - - // Update user by ID - Protected - userRouter.Handle("/{id}", middleware.AuthMiddleware("/users/{id}", "PUT", http.HandlerFunc(userController.UpdateUserHandler))).Methods("PUT") - - // Delete user by ID - Protected - userRouter.Handle("/{id}", middleware.AuthMiddleware("/users/{id}", "DELETE", http.HandlerFunc(userController.DeleteUserHandler))).Methods("DELETE") -} diff --git a/pkg/auth/utils/response.go b/pkg/auth/utils/response.go index f95fcb7..9c1d86d 100644 --- a/pkg/auth/utils/response.go +++ b/pkg/auth/utils/response.go @@ -1,18 +1,15 @@ package utils import ( - "encoding/json" - "net/http" + "github.com/gin-gonic/gin" ) -// RespondWithError sends an error response. -func RespondWithError(w http.ResponseWriter, code int, message string) { - RespondWithJSON(w, code, map[string]string{"error": message}) +// RespondWithJSON is a helper function to send JSON responses +func RespondWithJSON(c *gin.Context, statusCode int, payload interface{}) { + c.JSON(statusCode, payload) } -// RespondWithJSON sends a JSON response. -func RespondWithJSON(w http.ResponseWriter, code int, payload interface{}) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(code) - json.NewEncoder(w).Encode(payload) +// RespondWithError is a helper function to send error responses +func RespondWithError(c *gin.Context, statusCode int, message string) { + c.JSON(statusCode, gin.H{"error": message}) } diff --git a/pkg/controller/main.go b/pkg/controller/main.go index abdfe54..c70435e 100644 --- a/pkg/controller/main.go +++ b/pkg/controller/main.go @@ -1,6 +1,8 @@ package main import ( + "github.com/joho/godotenv" + "github.com/krack8/lighthouse/pkg/auth/config" "github.com/krack8/lighthouse/pkg/controller/worker" _log "github.com/krack8/lighthouse/pkg/log" "github.com/krack8/lighthouse/pkg/server" @@ -12,6 +14,28 @@ func main() { _log.InitializeLogger() worker.StartGrpcServer() + // Load environment variables from .env file + if err := godotenv.Load("../.env"); err != nil { + log.Fatal("Error loading .env file") + } + // Connect to the database + client, ctx, err := config.ConnectDB() + if err != nil { + log.Fatalf("Error connecting to DB: %v", err) + return + } + defer func() { + if err := client.Disconnect(ctx); err != nil { + log.Fatalf("Error disconnecting from DB: %v", err) + } + }() + + // Initialize the default RBAC if needed + config.InitRBAC() + + // Initialize the default user if needed + config.InitializeDefaultUser() + // Start HTTP server server.Start() log.Println("HTTP server listening on :8080") diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index 65e1415..076adfd 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -2,6 +2,8 @@ package router import ( "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/auth/controllers" + middleware "github.com/krack8/lighthouse/pkg/auth/middlewares" "github.com/krack8/lighthouse/pkg/controller/api" ) @@ -15,7 +17,38 @@ import ( // @in header // @name Authorization +// Declare the userService as a global variable +var userController *controllers.UserController + +// Declare the userService as a global variable +var rbacController *controllers.RbacController + +// Declare the userService as a global variable + func AddApiRoutes(httpRg *gin.RouterGroup) { + + // Define the login route separately without middleware + // Login route + httpRg.POST("/auth/login", controllers.LoginHandler) + + // Refresh token route + httpRg.POST("/auth/refresh-token", controllers.RefreshTokenHandler) + + // Apply the AuthMiddleware to the /api/v1 routes + apiGroup := httpRg.Group("/api/v1", middleware.AuthMiddleware()) + + // User routes + apiGroup.POST("/users", userController.CreateUserHandler) + apiGroup.GET("/users", userController.GetAllUsersHandler) + apiGroup.GET("/users/:id", userController.GetUserHandler) + apiGroup.PUT("/users/:id", userController.UpdateUserHandler) + apiGroup.DELETE("/users/:id", userController.DeleteUserHandler) + + // RBAC routes + apiGroup.POST("/rbac/permissions", rbacController.CreatePermissionHandler) + apiGroup.POST("/rbac/roles", rbacController.CreateRoleHandler) + apiGroup.POST("/rbac/assign-roles", rbacController.AssignRolesHandler) + // Namespace httpRg.GET("api/v1/namespace", api.NamespaceController().GetNamespaceList) httpRg.GET("api/v1/namespace/names", api.NamespaceController().GetNamespaceNameList) diff --git a/pkg/server/server.go b/pkg/server/server.go index 33dcab7..cf7ff49 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -3,10 +3,10 @@ package server import ( "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" - cfg "github.com/krack8/lighthouse/pkg/config" _log "github.com/krack8/lighthouse/pkg/log" "github.com/krack8/lighthouse/pkg/server/router" "net/http" + "os" ) func Start() { @@ -23,10 +23,30 @@ func Start() { httpRouter := r.Group("/") //r.GET("/ws/v1/pod/logs/:name", v1.PodController().GetPodStreamLogs) // Setting up all Http Routes + + /*// Initialize services and controllers + userService := &services.UserService{} // Ensure it is properly initialized + userController := &controllers.UserController{UserService: userService} + + rbacService := &services.RbacService{} // Ensure it is properly initialized + rbacController := &controllers.RbacController{RbacService: rbacService} + + // Initialize routes from various route files + routes.InitPermissionRoutes(rbacController, router) // permission-related routes + routes.InitRoleRoutes(rbacController, router) // role-related routes + + routes.InitAuthRoutes(router) // Auth-related routes + routes.InitUserRoutes(userController, router) // user-related routes*/ + // Get the application port from the environment + port := os.Getenv("PORT") + if port == "" { + port = "8080" // Default port if not specified + } + router.AddApiRoutes(httpRouter) //r.GET("/health", api.Home().Health) //r.GET("/", api.Home().Index) - err := r.Run(":" + cfg.ServerPort) // listen and serve on 0.0.0.0:8080 + err := r.Run(":" + port) // listen and serve if err != nil { _log.Logger.Errorw("Failed to start server", "err", err.Error()) } From 5c99cc7a66eaed4172b7724a2d85c965cf2da7b7 Mon Sep 17 00:00:00 2001 From: Toha Date: Tue, 28 Jan 2025 17:55:15 +0600 Subject: [PATCH 18/64] network policy, node, pod, pod disruption budget, pod metrics, pv, pvc controller --- pkg/controller/api/network_policy.go | 101 ++++++++ pkg/controller/api/node.go | 168 ++++++++++++ pkg/controller/api/pod.go | 257 +++++++++++++++++++ pkg/controller/api/pod_disruption_budgets.go | 166 ++++++++++++ pkg/controller/api/pod_metrics.go | 83 ++++++ pkg/controller/api/pv.go | 138 ++++++++++ pkg/controller/api/pvc.go | 166 ++++++++++++ pkg/server/router/routes.go | 44 +++- pkg/tasks/register_tasks.go | 41 +++ 9 files changed, 1154 insertions(+), 10 deletions(-) create mode 100644 pkg/controller/api/network_policy.go create mode 100644 pkg/controller/api/node.go create mode 100644 pkg/controller/api/pod.go create mode 100644 pkg/controller/api/pod_disruption_budgets.go create mode 100644 pkg/controller/api/pod_metrics.go create mode 100644 pkg/controller/api/pv.go create mode 100644 pkg/controller/api/pvc.go diff --git a/pkg/controller/api/network_policy.go b/pkg/controller/api/network_policy.go new file mode 100644 index 0000000..bcaa351 --- /dev/null +++ b/pkg/controller/api/network_policy.go @@ -0,0 +1,101 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" +) + +type NetworkPolicyControllerInterface interface { + GetNetworkPolicyList(ctx *gin.Context) + GetNetworkPolicyDetails(ctx *gin.Context) +} + +type networkPolicyController struct { +} + +var npc networkPolicyController + +func NetworkPolicyController() *networkPolicyController { + return &npc +} + +func (ctrl *networkPolicyController) GetNetworkPolicyList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetNetworkPolicyListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for NetworkPolicy List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.NetworkPolicyService().GetNetworkPolicyList) + logRequestedTaskController("network-policy", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *networkPolicyController) GetNetworkPolicyDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetNetworkPolicyDetailsInputParams) + input.NetworkPolicyName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.NetworkPolicyService().GetNetworkPolicyDetails) + logRequestedTaskController("network-policy", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/node.go b/pkg/controller/api/node.go new file mode 100644 index 0000000..d4a8c0d --- /dev/null +++ b/pkg/controller/api/node.go @@ -0,0 +1,168 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/dto" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" +) + +type NodeControllerInterface interface { + GetNodeList(ctx *gin.Context) + GetNodeDetails(ctx *gin.Context) + NodeCordon(ctx *gin.Context) + NodeTaint(ctx *gin.Context) + NodeUnTaint(ctx *gin.Context) +} + +type nodeController struct { +} + +var nc nodeController + +func NodeController() *nodeController { + return &nc +} + +func (ctrl *nodeController) GetNodeList(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetNodeListInputParams) + input.Search = ctx.Query("q") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Errorw("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Infow("Filter by param for Namespace List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.NodeService().GetNodeList) + logRequestedTaskController("node", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *nodeController) GetNodeDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetNodeInputParams) + input.NodeName = ctx.Param("name") + taskName := tasks.GetTaskName(k8s.NodeService().GetNodeDetails) + logRequestedTaskController("node", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *nodeController) NodeCordon(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.NodeCordonInputParams) + input.NodeName = ctx.Param("name") + taskName := tasks.GetTaskName(k8s.NodeService().NodeCordon) + logRequestedTaskController("node", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *nodeController) NodeTaint(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.NodeTaintInputParams) + input.NodeName = ctx.Param("name") + + payload := new(dto.TaintList) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind node taint payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + log.Logger.Debugw("node taint payload ", payload) + + input.TaintList = payload + taskName := tasks.GetTaskName(k8s.NodeService().NodeTaint) + logRequestedTaskController("node", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *nodeController) NodeUnTaint(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.NodeUnTaintInputParams) + input.NodeName = ctx.Param("name") + payload := new(dto.UnTaintKeys) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind node untaint payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + log.Logger.Debugw("node untaint payload ", payload) + input.Keys = payload.Keys + taskName := tasks.GetTaskName(k8s.NodeService().NodeUnTaint) + logRequestedTaskController("node", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/pod.go b/pkg/controller/api/pod.go new file mode 100644 index 0000000..4354f5f --- /dev/null +++ b/pkg/controller/api/pod.go @@ -0,0 +1,257 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + corev1 "k8s.io/api/core/v1" + "strconv" +) + +type PodControllerInterface interface { + GetPodList(ctx *gin.Context) + GetPodDetails(ctx *gin.Context) + GetPodStats(ctx *gin.Context) + GetPodLogs(ctx *gin.Context) + DeployPod(ctx *gin.Context) + DeletePod(ctx *gin.Context) +} + +type podController struct { +} + +var pc podController + +func PodController() *podController { + return &pc +} + +func (ctrl *podController) GetPodList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetPodListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Continue = ctx.Query("continue") + input.Search = ctx.Query("q") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for Pod List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.PodService().GetPodList) + logRequestedTaskController("pod", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *podController) GetPodDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetPodDetailsInputParams) + input.PodName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.PodService().GetPodDetails) + logRequestedTaskController("pod", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *podController) DeployPod(ctx *gin.Context) { + var result ResponseDTO + payload := new(corev1.Pod) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy pod payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployPodInputParams) + input.Pod = payload + if input.Pod.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "pod deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.PodService().DeployPod) + logRequestedTaskController("pod", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *podController) DeletePod(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeletePodInputParams) + input.PodName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.PodService().DeletePod) + logRequestedTaskController("pod", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *podController) GetPodStats(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetPodStatsInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for Pod List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.PodService().GetPodStats) + logRequestedTaskController("pod", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *podController) GetPodLogs(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetPodLogsInputParams) + input.Pod = ctx.Param("name") + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Container = ctx.Query("container") + if ctx.Query("lines") != "" { + tailLines, err := strconv.ParseInt(ctx.Query("lines"), 10, 64) + if err == nil { + input.TailLines = &tailLines + } + } + if ctx.Query("since") != "" { + sinceSeconds, err := strconv.ParseInt(ctx.Query("since"), 10, 64) + if err == nil { + input.SinceSeconds = &sinceSeconds + } + } + input.Timestamps = ctx.Query("timestamps") + input.Previous = ctx.Query("previous") + taskName := tasks.GetTaskName(k8s.PodService().GetPodLogs) + logRequestedTaskController("pod", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/pod_disruption_budgets.go b/pkg/controller/api/pod_disruption_budgets.go new file mode 100644 index 0000000..f379f1d --- /dev/null +++ b/pkg/controller/api/pod_disruption_budgets.go @@ -0,0 +1,166 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + v1 "k8s.io/api/policy/v1" +) + +type PodDisruptionBudgetsControllerInterface interface { + GetPodDisruptionBudgetsList(ctx *gin.Context) + GetPodDisruptionBudgetsDetails(ctx *gin.Context) + DeployPodDisruptionBudgets(ctx *gin.Context) + DeletePodDisruptionBudgets(ctx *gin.Context) +} + +type podDisruptionBudgetsController struct { +} + +var pdbc podDisruptionBudgetsController + +func PodDisruptionBudgetsController() *podDisruptionBudgetsController { + return &pdbc +} + +func (ctrl *podDisruptionBudgetsController) GetPodDisruptionBudgetsList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetPodDisruptionBudgetsListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for PodDisruptionBudgets List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.PodDisruptionBudgetsService().GetPodDisruptionBudgetsList) + logRequestedTaskController("pod-disruption-budget", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *podDisruptionBudgetsController) GetPodDisruptionBudgetsDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetPodDisruptionBudgetsDetailsInputParams) + input.PodDisruptionBudgetsName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.PodDisruptionBudgetsService().GetPodDisruptionBudgetsDetails) + logRequestedTaskController("pod-disruption-budget", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *podDisruptionBudgetsController) DeployPodDisruptionBudgets(ctx *gin.Context) { + var result ResponseDTO + payload := new(v1.PodDisruptionBudget) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy PodDisruptionBudgets payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployPodDisruptionBudgetsInputParams) + input.PodDisruptionBudgets = payload + if input.PodDisruptionBudgets.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "podDisruptionBudgets deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.PodDisruptionBudgetsService().DeployPodDisruptionBudgets) + logRequestedTaskController("pod-disruption-budget", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *podDisruptionBudgetsController) DeletePodDisruptionBudgets(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeletePodDisruptionBudgetsInputParams) + input.PodDisruptionBudgetsName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.PodDisruptionBudgetsService().DeletePodDisruptionBudgets) + logRequestedTaskController("pod-disruption-budget", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/pod_metrics.go b/pkg/controller/api/pod_metrics.go new file mode 100644 index 0000000..2db8de3 --- /dev/null +++ b/pkg/controller/api/pod_metrics.go @@ -0,0 +1,83 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" +) + +type PodMetricsControllerInterface interface { + GetPodMetricsList(ctx *gin.Context) + GetPodMetricsDetails(ctx *gin.Context) +} + +type podMetricsController struct { +} + +var pmc podMetricsController + +func PodMetricsController() *podMetricsController { + return &pmc +} + +func (ctrl *podMetricsController) GetPodMetricsList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetPodMetricsListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.PodMetricsService().GetPodMetricsList) + logRequestedTaskController("pod-metrics", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *podMetricsController) GetPodMetricsDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetPodMetricsDetailsInputParams) + input.PodName = ctx.Param("pod") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.PodMetricsService().GetPodMetricsDetails) + logRequestedTaskController("pod-metrics", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/pv.go b/pkg/controller/api/pv.go new file mode 100644 index 0000000..f26428d --- /dev/null +++ b/pkg/controller/api/pv.go @@ -0,0 +1,138 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + corev1 "k8s.io/api/core/v1" +) + +type PvControllerInterface interface { + GetPvList(ctx *gin.Context) + GetPvDetails(ctx *gin.Context) + DeployPv(ctx *gin.Context) + DeletePv(ctx *gin.Context) +} + +type pvController struct { +} + +var pvc pvController + +func PvController() *pvController { + return &pvc +} + +func (ctrl *pvController) GetPvList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetPvListInputParams) + + queryLabel := ctx.Query("labels") + + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for Pv List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + taskName := tasks.GetTaskName(k8s.PvService().GetPvList) + logRequestedTaskController("pv", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *pvController) GetPvDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetPvDetailsInputParams) + input.PvName = ctx.Param("name") + taskName := tasks.GetTaskName(k8s.PvService().GetPvDetails) + logRequestedTaskController("pv", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *pvController) DeployPv(ctx *gin.Context) { + var result ResponseDTO + payload := new(corev1.PersistentVolume) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy pvc payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployPvInputParams) + input.Pv = payload + taskName := tasks.GetTaskName(k8s.PvService().DeployPv) + logRequestedTaskController("pv", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *pvController) DeletePv(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeletePvInputParams) + input.PvName = ctx.Param("name") + taskName := tasks.GetTaskName(k8s.PvService().DeletePv) + logRequestedTaskController("pv", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/pvc.go b/pkg/controller/api/pvc.go new file mode 100644 index 0000000..d92215b --- /dev/null +++ b/pkg/controller/api/pvc.go @@ -0,0 +1,166 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + corev1 "k8s.io/api/core/v1" +) + +type PvcControllerInterface interface { + GetPvcList(ctx *gin.Context) + GetPvcDetails(ctx *gin.Context) + DeployPvc(ctx *gin.Context) + DeletePvc(ctx *gin.Context) +} + +type pvcController struct { +} + +var pvcc pvcController + +func PvcController() *pvcController { + return &pvcc +} + +func (ctrl *pvcController) GetPvcList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetPvcListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for Pvc List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.PvcService().GetPvcList) + logRequestedTaskController("pvc", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *pvcController) GetPvcDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetPvcDetailsInputParams) + input.PvcName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.PvcService().GetPvcDetails) + logRequestedTaskController("pvc", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *pvcController) DeployPvc(ctx *gin.Context) { + var result ResponseDTO + payload := new(corev1.PersistentVolumeClaim) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy pvc payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployPvcInputParams) + input.Pvc = payload + if input.Pvc.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "pvc deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.PvcService().DeployPvc) + logRequestedTaskController("pvc", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *pvcController) DeletePvc(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeletePvcInputParams) + input.PvcName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.PvcService().DeletePvc) + logRequestedTaskController("pvc", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index 65e1415..f851a11 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -5,16 +5,6 @@ import ( "github.com/krack8/lighthouse/pkg/controller/api" ) -// @title Swagger API -// @version 1.0 - -// @host localhost:8080 -// @BasePath /api - -// @securityDefinitions.apikey ApiKeyAuth -// @in header -// @name Authorization - func AddApiRoutes(httpRg *gin.RouterGroup) { // Namespace httpRg.GET("api/v1/namespace", api.NamespaceController().GetNamespaceList) @@ -111,4 +101,38 @@ func AddApiRoutes(httpRg *gin.RouterGroup) { httpRg.GET("api/v1/load-balancer/:name", api.LoadBalancerController().GetLoadBalancerDetails) // Manifest httpRg.POST("api/v1/manifest", api.ManifestController().DeployManifest) + // Network Policy + httpRg.GET("api/v1/network-policy", api.NetworkPolicyController().GetNetworkPolicyList) + httpRg.GET("api/v1/network-policy/:name", api.NetworkPolicyController().GetNetworkPolicyDetails) + //Node + httpRg.GET("api/v1/node", api.NodeController().GetNodeList) + httpRg.GET("api/v1/node/:name", api.NodeController().GetNodeDetails) + httpRg.GET("api/v1/node/cordon/:name", api.NodeController().NodeCordon) + httpRg.POST("api/v1/node/taint/:name", api.NodeController().NodeTaint) + httpRg.POST("api/v1/node/untaint/:name", api.NodeController().NodeUnTaint) + // Pod + httpRg.GET("api/v1/pod", api.PodController().GetPodList) + httpRg.GET("api/v1/pod/:name", api.PodController().GetPodDetails) + httpRg.GET("api/v1/pod/logs/:name", api.PodController().GetPodLogs) + httpRg.POST("api/v1/pod", api.PodController().DeployPod) + httpRg.DELETE("api/v1/pod/:name", api.PodController().DeletePod) + httpRg.GET("api/v1/pod/stats", api.PodController().GetPodStats) + // PodDisruptionBudgets + httpRg.GET("api/v1/PDB", api.PodDisruptionBudgetsController().GetPodDisruptionBudgetsList) + httpRg.GET("api/v1/PDB/:name", api.PodDisruptionBudgetsController().GetPodDisruptionBudgetsDetails) + httpRg.POST("api/v1/PDB", api.PodDisruptionBudgetsController().DeployPodDisruptionBudgets) + httpRg.DELETE("api/v1/PDB/:name", api.PodDisruptionBudgetsController().DeletePodDisruptionBudgets) + // Pod Metrics + httpRg.GET("api/v1/pod-metrics", api.PodMetricsController().GetPodMetricsList) + httpRg.GET("api/v1/pod-metrics/:pod", api.PodMetricsController().GetPodMetricsDetails) + // PV + httpRg.GET("api/v1/pv", api.PvController().GetPvList) + httpRg.GET("api/v1/pv/:name", api.PvController().GetPvDetails) + httpRg.POST("api/v1/pv", api.PvController().DeployPv) + httpRg.DELETE("api/v1/pv/:name", api.PvController().DeletePv) + // Persistent Volume Claim + httpRg.GET("api/v1/pvc", api.PvcController().GetPvcList) + httpRg.GET("api/v1/pvc/:name", api.PvcController().GetPvcDetails) + httpRg.POST("api/v1/pvc", api.PvcController().DeployPvc) + httpRg.DELETE("api/v1/pvc/:name", api.PvcController().DeletePvc) } diff --git a/pkg/tasks/register_tasks.go b/pkg/tasks/register_tasks.go index 4e820e9..6afa0bf 100644 --- a/pkg/tasks/register_tasks.go +++ b/pkg/tasks/register_tasks.go @@ -117,4 +117,45 @@ func InitTaskRegistry() { //Manifest RegisterTask(k8s.ManifestService().DeployManifest, k8s.DeployManifestInputParams{}) + + //networkPolicy + RegisterTask(k8s.NetworkPolicyService().GetNetworkPolicyList, k8s.GetNetworkPolicyListInputParams{}) + RegisterTask(k8s.NetworkPolicyService().GetNetworkPolicyDetails, k8s.GetNetworkPolicyDetailsInputParams{}) + + //node + RegisterTask(k8s.NodeService().GetNodeList, k8s.GetNodeListInputParams{}) + RegisterTask(k8s.NodeService().GetNodeDetails, k8s.GetNodeInputParams{}) + RegisterTask(k8s.NodeService().NodeCordon, k8s.NodeCordonInputParams{}) + RegisterTask(k8s.NodeService().NodeTaint, k8s.NodeTaintInputParams{}) + RegisterTask(k8s.NodeService().NodeUnTaint, k8s.NodeUnTaintInputParams{}) + + //pod + RegisterTask(k8s.PodService().GetPodList, k8s.GetPodListInputParams{}) + RegisterTask(k8s.PodService().GetPodDetails, k8s.GetPodDetailsInputParams{}) + RegisterTask(k8s.PodService().GetPodLogs, k8s.GetPodLogsInputParams{}) + RegisterTask(k8s.PodService().GetPodStats, k8s.GetPodStatsInputParams{}) + RegisterTask(k8s.PodService().DeployPod, k8s.DeployPodInputParams{}) + RegisterTask(k8s.PodService().DeletePod, k8s.DeletePodInputParams{}) + + //podDisruptionBudget + RegisterTask(k8s.PodDisruptionBudgetsService().GetPodDisruptionBudgetsList, k8s.GetPodDisruptionBudgetsListInputParams{}) + RegisterTask(k8s.PodDisruptionBudgetsService().GetPodDisruptionBudgetsDetails, k8s.GetPodDisruptionBudgetsDetailsInputParams{}) + RegisterTask(k8s.PodDisruptionBudgetsService().DeployPodDisruptionBudgets, k8s.DeployPodDisruptionBudgetsInputParams{}) + RegisterTask(k8s.PodDisruptionBudgetsService().DeletePodDisruptionBudgets, k8s.DeletePodDisruptionBudgetsInputParams{}) + + //podMetrics + RegisterTask(k8s.PodMetricsService().GetPodMetricsList, k8s.GetPodMetricsListInputParams{}) + RegisterTask(k8s.PodMetricsService().GetPodMetricsDetails, k8s.GetPodMetricsDetailsInputParams{}) + + //pv + RegisterTask(k8s.PvService().GetPvList, k8s.GetPvListInputParams{}) + RegisterTask(k8s.PvService().GetPvDetails, k8s.GetPvDetailsInputParams{}) + RegisterTask(k8s.PvService().DeployPv, k8s.DeployPvInputParams{}) + RegisterTask(k8s.PvService().DeletePv, k8s.DeletePvInputParams{}) + + //pvc + RegisterTask(k8s.PvcService().GetPvcList, k8s.GetPvcListInputParams{}) + RegisterTask(k8s.PvcService().GetPvcDetails, k8s.GetPvcDetailsInputParams{}) + RegisterTask(k8s.PvcService().DeployPvc, k8s.DeployPvcInputParams{}) + RegisterTask(k8s.PvcService().DeletePvc, k8s.DeletePvcInputParams{}) } From 612799d41d32d785d6c1ba08b9327cd778c6f292 Mon Sep 17 00:00:00 2001 From: Toha Date: Tue, 28 Jan 2025 18:54:31 +0600 Subject: [PATCH 19/64] replicaset, replication controller, resource quota, role, rolebinding, sa, secret, sts, storage class, svc controller --- pkg/controller/api/replicaset.go | 211 +++++++++++++++ pkg/controller/api/replication_controller.go | 166 ++++++++++++ pkg/controller/api/resource_quota.go | 169 ++++++++++++ pkg/controller/api/role.go | 166 ++++++++++++ pkg/controller/api/role_binding.go | 166 ++++++++++++ pkg/controller/api/sa.go | 166 ++++++++++++ pkg/controller/api/secret.go | 153 +++++++++++ pkg/controller/api/statefulset.go | 257 +++++++++++++++++++ pkg/controller/api/storage_class.go | 137 ++++++++++ pkg/controller/api/svc.go | 167 ++++++++++++ pkg/server/router/routes.go | 54 ++++ pkg/tasks/register_tasks.go | 63 +++++ 12 files changed, 1875 insertions(+) create mode 100644 pkg/controller/api/replicaset.go create mode 100644 pkg/controller/api/replication_controller.go create mode 100644 pkg/controller/api/resource_quota.go create mode 100644 pkg/controller/api/role.go create mode 100644 pkg/controller/api/role_binding.go create mode 100644 pkg/controller/api/sa.go create mode 100644 pkg/controller/api/secret.go create mode 100644 pkg/controller/api/statefulset.go create mode 100644 pkg/controller/api/storage_class.go create mode 100644 pkg/controller/api/svc.go diff --git a/pkg/controller/api/replicaset.go b/pkg/controller/api/replicaset.go new file mode 100644 index 0000000..57e7267 --- /dev/null +++ b/pkg/controller/api/replicaset.go @@ -0,0 +1,211 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + appsv1 "k8s.io/api/apps/v1" +) + +type ReplicaSetControllerInterface interface { + GetReplicaSetList(ctx *gin.Context) + GetReplicaSetDetails(ctx *gin.Context) + DeployReplicaSet(ctx *gin.Context) + DeleteReplicaSet(ctx *gin.Context) + GetReplicaSetStats(ctx *gin.Context) +} + +type replicaSetController struct { +} + +var rsc replicaSetController + +func ReplicaSetController() *replicaSetController { + return &rsc +} + +func (ctrl *replicaSetController) GetReplicaSetList(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetReplicaSetListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for ReplicaSet List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.ReplicaSetService().GetReplicaSetList) + logRequestedTaskController("replicaset", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *replicaSetController) GetReplicaSetDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetReplicaSetDetailsInputParams) + input.ReplicaSetName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.ReplicaSetService().GetReplicaSetDetails) + logRequestedTaskController("replicaset", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *replicaSetController) DeployReplicaSet(ctx *gin.Context) { + var result ResponseDTO + payload := new(appsv1.ReplicaSet) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy ReplicaSet payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployReplicaSetInputParams) + input.ReplicaSet = payload + if input.ReplicaSet.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "replicaSet deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.ReplicaSetService().DeployReplicaSet) + logRequestedTaskController("replicaset", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *replicaSetController) DeleteReplicaSet(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteReplicaSetInputParams) + input.ReplicaSetName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.ReplicaSetService().DeleteReplicaSet) + logRequestedTaskController("replicaset", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *replicaSetController) GetReplicaSetStats(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetReplicaSetStatsInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for ReplicaSet List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.ReplicaSetService().GetReplicaSetStats) + logRequestedTaskController("replicaset", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/replication_controller.go b/pkg/controller/api/replication_controller.go new file mode 100644 index 0000000..28a9258 --- /dev/null +++ b/pkg/controller/api/replication_controller.go @@ -0,0 +1,166 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + corev1 "k8s.io/api/core/v1" +) + +type ReplicationControllerControllerInterface interface { + GetReplicationControllerList(ctx *gin.Context) + GetReplicationControllerDetails(ctx *gin.Context) + DeployReplicationController(ctx *gin.Context) + DeleteReplicationController(ctx *gin.Context) +} + +type replicationControllerController struct { +} + +var rcc replicationControllerController + +func ReplicationControllerController() *replicationControllerController { + return &rcc +} + +func (ctrl *replicationControllerController) GetReplicationControllerList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetReplicationControllerListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for ReplicationController List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.ReplicationControllerService().GetReplicationControllerList) + logRequestedTaskController("replication-controller", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *replicationControllerController) GetReplicationControllerDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetReplicationControllerDetailsInputParams) + input.ReplicationControllerName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.ReplicationControllerService().GetReplicationControllerDetails) + logRequestedTaskController("replication-controller", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *replicationControllerController) DeployReplicationController(ctx *gin.Context) { + var result ResponseDTO + payload := new(corev1.ReplicationController) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy configmap payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployReplicationControllerInputParams) + input.ReplicationController = payload + if input.ReplicationController.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "config-map deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.ReplicationControllerService().DeployReplicationController) + logRequestedTaskController("replication-controller", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *replicationControllerController) DeleteReplicationController(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteReplicationControllerInputParams) + input.ReplicationControllerName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.ReplicationControllerService().DeleteReplicationController) + logRequestedTaskController("replication-controller", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/resource_quota.go b/pkg/controller/api/resource_quota.go new file mode 100644 index 0000000..aee7e91 --- /dev/null +++ b/pkg/controller/api/resource_quota.go @@ -0,0 +1,169 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + corev1 "k8s.io/api/core/v1" +) + +type ResourceQuotaControllerInterface interface { + GetResourceQuotaList(ctx *gin.Context) + GetResourceQuotaDetails(ctx *gin.Context) + DeploySVC(ctx *gin.Context) + DeleteResourceQuota(ctx *gin.Context) +} + +type resourceQuotaController struct { +} + +var rqc resourceQuotaController + +func ResourceQuotaController() *resourceQuotaController { + return &rqc +} + +func (ctrl *resourceQuotaController) GetResourceQuotaList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetResourceQuotaListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for ResourceQuota List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.ResourceQuotaService().GetResourceQuotaList) + logRequestedTaskController("resource-quota", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *resourceQuotaController) GetResourceQuotaDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetResourceQuotaDetailsInputParams) + input.ResourceQuotaName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.ResourceQuotaService().GetResourceQuotaDetails) + logRequestedTaskController("resource-quota", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *resourceQuotaController) DeployResourceQuota(ctx *gin.Context) { + var result ResponseDTO + + payload := new(corev1.ResourceQuota) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy Service payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + log.Logger.Debugw("deploy service payload ", payload) + + input := new(k8s.DeployResourceQuotaInputParams) + input.ResourceQuota = payload + if input.ResourceQuota.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "resourceQuota deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.ResourceQuotaService().DeployResourceQuota) + logRequestedTaskController("resource-quota", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *resourceQuotaController) DeleteResourceQuota(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.DeleteResourceQuotaInputParams) + input.ResourceQuotaName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.ResourceQuotaService().DeleteResourceQuota) + logRequestedTaskController("resource-quota", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/role.go b/pkg/controller/api/role.go new file mode 100644 index 0000000..870ca24 --- /dev/null +++ b/pkg/controller/api/role.go @@ -0,0 +1,166 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + rbacv1 "k8s.io/api/rbac/v1" +) + +type RoleControllerInterface interface { + GetRoleList(ctx *gin.Context) + GetRoleDetails(ctx *gin.Context) + DeployRole(ctx *gin.Context) + DeleteRole(ctx *gin.Context) +} + +type roleController struct { +} + +var rc roleController + +func RoleController() *roleController { + return &rc +} + +func (ctrl *roleController) GetRoleList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetRoleListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for Role List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.RoleService().GetRoleList) + logRequestedTaskController("role", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *roleController) GetRoleDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetRoleDetailsInputParams) + input.RoleName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.RoleService().GetRoleDetails) + logRequestedTaskController("role", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *roleController) DeployRole(ctx *gin.Context) { + var result ResponseDTO + payload := new(rbacv1.Role) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy Role payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployRoleInputParams) + input.Role = payload + if input.Role.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "Role deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.RoleService().DeployRole) + logRequestedTaskController("role", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *roleController) DeleteRole(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteRoleInputParams) + input.RoleName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.RoleService().DeleteRole) + logRequestedTaskController("role", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/role_binding.go b/pkg/controller/api/role_binding.go new file mode 100644 index 0000000..9df9fb6 --- /dev/null +++ b/pkg/controller/api/role_binding.go @@ -0,0 +1,166 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + rbacv1 "k8s.io/api/rbac/v1" +) + +type RoleBindingControllerInterface interface { + GetRoleBindingList(ctx *gin.Context) + GetRoleBindingDetails(ctx *gin.Context) + DeployRoleBinding(ctx *gin.Context) + DeleteRoleBinding(ctx *gin.Context) +} + +type roleBindingController struct { +} + +var rbc roleBindingController + +func RoleBindingController() *roleBindingController { + return &rbc +} + +func (ctrl *roleBindingController) GetRoleBindingList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetRoleBindingListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for RoleBinding List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.RoleBindingService().GetRoleBindingList) + logRequestedTaskController("role-binding", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *roleBindingController) GetRoleBindingDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetRoleBindingDetailsInputParams) + input.RoleBindingName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.RoleBindingService().GetRoleBindingDetails) + logRequestedTaskController("role-binding", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *roleBindingController) DeployRoleBinding(ctx *gin.Context) { + var result ResponseDTO + payload := new(rbacv1.RoleBinding) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy RoleBinding payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployRoleBindingInputParams) + input.RoleBinding = payload + if input.RoleBinding.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "roleBinding deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.RoleBindingService().DeployRoleBinding) + logRequestedTaskController("role-binding", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *roleBindingController) DeleteRoleBinding(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteRoleBindingInputParams) + input.RoleBindingName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.RoleBindingService().DeleteRoleBinding) + logRequestedTaskController("role-binding", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/sa.go b/pkg/controller/api/sa.go new file mode 100644 index 0000000..ddd8e06 --- /dev/null +++ b/pkg/controller/api/sa.go @@ -0,0 +1,166 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + corev1 "k8s.io/api/core/v1" +) + +type ServiceAccountControllerInterface interface { + GetServiceAccountList(ctx *gin.Context) + GetServiceAccountDetails(ctx *gin.Context) + DeployServiceAccount(ctx *gin.Context) + DeleteServiceAccount(ctx *gin.Context) +} + +type serviceAccountController struct { +} + +var sas serviceAccountController + +func ServiceAccountController() *serviceAccountController { + return &sas +} + +func (ctrl *serviceAccountController) GetServiceAccountList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetServiceAccountListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for ServiceAccount List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.ServiceAccountService().GetServiceAccountList) + logRequestedTaskController("service-account", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *serviceAccountController) GetServiceAccountDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetServiceAccountDetailsInputParams) + input.ServiceAccountName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.ServiceAccountService().GetServiceAccountDetails) + logRequestedTaskController("service-account", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *serviceAccountController) DeployServiceAccount(ctx *gin.Context) { + var result ResponseDTO + payload := new(corev1.ServiceAccount) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy ServiceAccount payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployServiceAccountInputParams) + input.ServiceAccount = payload + if input.ServiceAccount.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "serviceAccount deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.ServiceAccountService().DeployServiceAccount) + logRequestedTaskController("service-account", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *serviceAccountController) DeleteServiceAccount(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteServiceAccountInputParams) + input.ServiceAccountName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.ServiceAccountService().DeleteServiceAccount) + logRequestedTaskController("service-account", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/secret.go b/pkg/controller/api/secret.go new file mode 100644 index 0000000..425bef8 --- /dev/null +++ b/pkg/controller/api/secret.go @@ -0,0 +1,153 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + corev1 "k8s.io/api/core/v1" +) + +type SecretControllerInterface interface { + GetSecretList(ctx *gin.Context) + GetSecretDetails(ctx *gin.Context) + DeploySecret(ctx *gin.Context) + DeleteSecret(ctx *gin.Context) +} + +type secretController struct { +} + +var sc secretController + +func SecretController() *secretController { + return &sc +} + +func (ctrl *secretController) GetSecretList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetSecretListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for Secret List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.SecretService().GetSecretList) + logRequestedTaskController("secret", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *secretController) GetSecretDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetSecretDetailsInputParams) + input.SecretName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.SecretService().GetSecretDetails) + logRequestedTaskController("secret", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *secretController) DeploySecret(ctx *gin.Context) { + var result ResponseDTO + payload := new(corev1.Secret) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy secret payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeploySecretInputParams) + input.Secret = payload + taskName := tasks.GetTaskName(k8s.SecretService().DeploySecret) + logRequestedTaskController("secret", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *secretController) DeleteSecret(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteSecretInputParams) + input.SecretName = ctx.Param("name") + taskName := tasks.GetTaskName(k8s.SecretService().DeleteSecret) + logRequestedTaskController("secret", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/statefulset.go b/pkg/controller/api/statefulset.go new file mode 100644 index 0000000..51db975 --- /dev/null +++ b/pkg/controller/api/statefulset.go @@ -0,0 +1,257 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + appsv1 "k8s.io/api/apps/v1" +) + +type StatefulSetControllerInterface interface { + GetStatefulSetList(ctx *gin.Context) + GetStatefulSetDetails(ctx *gin.Context) + DeployStatefulSet(ctx *gin.Context) + DeleteStatefulSet(ctx *gin.Context) + GetStatefulSetStats(ctx *gin.Context) + GetStatefulSetPodList(ctx *gin.Context) +} + +type statefulSetController struct { +} + +var sfsc statefulSetController + +func StatefulSetController() *statefulSetController { + return &sfsc +} + +func (ctrl *statefulSetController) GetStatefulSetList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetStatefulSetListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for StatefulSet List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.StatefulSetService().GetStatefulSetList) + logRequestedTaskController("statefulset", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *statefulSetController) GetStatefulSetDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetStatefulSetDetailsInputParams) + input.StatefulSetName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.StatefulSetService().GetStatefulSetDetails) + logRequestedTaskController("statefulset", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *statefulSetController) DeployStatefulSet(ctx *gin.Context) { + var result ResponseDTO + payload := new(appsv1.StatefulSet) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy statefulSet payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployStatefulSetInputParams) + input.StatefulSet = payload + if input.StatefulSet.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "statefulSet deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.StatefulSetService().DeployStatefulSet) + logRequestedTaskController("statefulset", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *statefulSetController) DeleteStatefulSet(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteStatefulSetInputParams) + input.StatefulSetName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.StatefulSetService().DeleteStatefulSet) + logRequestedTaskController("statefulset", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *statefulSetController) GetStatefulSetStats(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetStatefulSetStatsInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for StatefulSet List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.StatefulSetService().GetStatefulSetStats) + logRequestedTaskController("statefulset", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *statefulSetController) GetStatefulSetPodList(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.GetStatefulSetPodListInputParams) + input.StatefulSetName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for Pod List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.StatefulSetService().GetStatefulSetPodList) + logRequestedTaskController("statefulset", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/storage_class.go b/pkg/controller/api/storage_class.go new file mode 100644 index 0000000..6380254 --- /dev/null +++ b/pkg/controller/api/storage_class.go @@ -0,0 +1,137 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + storagev1 "k8s.io/api/storage/v1" +) + +type StorageClassControllerInterface interface { + GetStorageClassList(ctx *gin.Context) + GetStorageClassDetails(ctx *gin.Context) + DeployStorageClass(ctx *gin.Context) + DeleteStorageClass(ctx *gin.Context) +} + +type storageClassController struct { +} + +var scc storageClassController + +func StorageClassController() *storageClassController { + return &scc +} + +func (ctrl *storageClassController) GetStorageClassList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetStorageClassListInputParams) + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for StorageClass List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + taskName := tasks.GetTaskName(k8s.StorageClassService().GetStorageClassList) + logRequestedTaskController("storage-class", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *storageClassController) GetStorageClassDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetStorageClassDetailsInputParams) + input.StorageClassName = ctx.Param("name") + taskName := tasks.GetTaskName(k8s.StorageClassService().GetStorageClassDetails) + logRequestedTaskController("storage-class", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *storageClassController) DeployStorageClass(ctx *gin.Context) { + var result ResponseDTO + payload := new(storagev1.StorageClass) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy StorageClass payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployStorageClassInputParams) + input.StorageClass = payload + taskName := tasks.GetTaskName(k8s.StorageClassService().DeployStorageClass) + logRequestedTaskController("storage-class", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *storageClassController) DeleteStorageClass(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteStorageClassInputParams) + input.StorageClassName = ctx.Param("name") + taskName := tasks.GetTaskName(k8s.StorageClassService().DeleteStorageClass) + logRequestedTaskController("storage-class", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/svc.go b/pkg/controller/api/svc.go new file mode 100644 index 0000000..7e32f6d --- /dev/null +++ b/pkg/controller/api/svc.go @@ -0,0 +1,167 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + corev1 "k8s.io/api/core/v1" +) + +type SvcControllerInterface interface { + GetSvcList(ctx *gin.Context) + GetSvcDetails(ctx *gin.Context) + DeploySVC(ctx *gin.Context) + DeleteSvc(ctx *gin.Context) +} + +type svcController struct { +} + +var svcc svcController + +func SvcController() *svcController { + return &svcc +} + +func (ctrl *svcController) GetSvcList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetSvcListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + input.Continue = ctx.Query("continue") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for Svc List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.SvcService().GetSvcList) + logRequestedTaskController("svc", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *svcController) GetSvcDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetSvcDetailsInputParams) + input.SvcName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.SvcService().GetSvcDetails) + logRequestedTaskController("svc", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *svcController) DeploySVC(ctx *gin.Context) { + var result ResponseDTO + payload := new(corev1.Service) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy Service payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + log.Logger.Debugw("deploy service payload ", payload) + + input := new(k8s.DeploySvcInputParams) + input.Svc = payload + if input.Svc.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "svc deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.SvcService().DeploySvc) + logRequestedTaskController("svc", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} + +func (ctrl *svcController) DeleteSvc(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteSvcInputParams) + input.SvcName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.SvcService().DeleteSvc) + logRequestedTaskController("svc", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + } + SendResponse(ctx, result) +} diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index 3038906..9172303 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -6,6 +6,7 @@ import ( middleware "github.com/krack8/lighthouse/pkg/auth/middlewares" "github.com/krack8/lighthouse/pkg/controller/api" ) + var userController *controllers.UserController // Declare the userService as a global variable @@ -164,4 +165,57 @@ func AddApiRoutes(httpRg *gin.RouterGroup) { httpRg.GET("api/v1/pvc/:name", api.PvcController().GetPvcDetails) httpRg.POST("api/v1/pvc", api.PvcController().DeployPvc) httpRg.DELETE("api/v1/pvc/:name", api.PvcController().DeletePvc) + // ReplicaSet + httpRg.GET("api/v1/replicaset", api.ReplicaSetController().GetReplicaSetList) + httpRg.GET("api/v1/replicaset/:name", api.ReplicaSetController().GetReplicaSetDetails) + httpRg.GET("api/v1/replicaset/stats", api.ReplicaSetController().GetReplicaSetStats) + httpRg.POST("api/v1/replicaset", api.ReplicaSetController().DeployReplicaSet) + httpRg.DELETE("api/v1/replicaset/:name", api.ReplicaSetController().DeleteReplicaSet) + // ReplicationController + httpRg.GET("api/v1/replication-controller", api.ReplicationControllerController().GetReplicationControllerList) + httpRg.GET("api/v1/replication-controller/:name", api.ReplicationControllerController().GetReplicationControllerDetails) + httpRg.POST("api/v1/replication-controller", api.ReplicationControllerController().DeployReplicationController) + httpRg.DELETE("api/v1/replication-controller/:name", api.ReplicationControllerController().DeleteReplicationController) + // Resource Quota + httpRg.GET("api/v1/resource-quota", api.ResourceQuotaController().GetResourceQuotaList) + httpRg.GET("api/v1/resource-quota/:name", api.ResourceQuotaController().GetResourceQuotaDetails) + httpRg.POST("api/v1/resource-quota", api.ResourceQuotaController().DeployResourceQuota) + httpRg.DELETE("api/v1/resource-quota/:name", api.ResourceQuotaController().DeleteResourceQuota) + // Role + httpRg.GET("api/v1/role", api.RoleController().GetRoleList) + httpRg.GET("api/v1/role/:name", api.RoleController().GetRoleDetails) + httpRg.POST("api/v1/role", api.RoleController().DeployRole) + httpRg.DELETE("api/v1/role/:name", api.RoleController().DeleteRole) + // RoleBinding + httpRg.GET("api/v1/role-binding", api.RoleBindingController().GetRoleBindingList) + httpRg.GET("api/v1/role-binding/:name", api.RoleBindingController().GetRoleBindingDetails) + httpRg.POST("api/v1/role-binding", api.RoleBindingController().DeployRoleBinding) + httpRg.DELETE("api/v1/role-binding/:name", api.RoleBindingController().DeleteRoleBinding) + // Service Account + httpRg.GET("api/v1/service-account", api.ServiceAccountController().GetServiceAccountList) + httpRg.GET("api/v1/service-account/:name", api.ServiceAccountController().GetServiceAccountDetails) + httpRg.POST("api/v1/service-account", api.ServiceAccountController().DeployServiceAccount) + httpRg.DELETE("api/v1/service-account/:name", api.ServiceAccountController().DeleteServiceAccount) + // Secret + httpRg.GET("api/v1/secret", api.SecretController().GetSecretList) + httpRg.GET("api/v1/secret/:name", api.SecretController().GetSecretDetails) + httpRg.POST("api/v1/secret", api.SecretController().DeploySecret) + httpRg.DELETE("api/v1/secret/:name", api.SecretController().DeleteSecret) + // StatefulSet + httpRg.GET("api/v1/statefulset", api.StatefulSetController().GetStatefulSetList) + httpRg.GET("api/v1/statefulset/:name", api.StatefulSetController().GetStatefulSetDetails) + httpRg.POST("api/v1/statefulset", api.StatefulSetController().DeployStatefulSet) + httpRg.DELETE("api/v1/statefulset/:name", api.StatefulSetController().DeleteStatefulSet) + httpRg.GET("api/v1/statefulset/stats", api.StatefulSetController().GetStatefulSetStats) + httpRg.GET("api/v1/statefulset/:name/pods", api.StatefulSetController().GetStatefulSetPodList) + // Storage class + httpRg.GET("api/v1/storage-class", api.StorageClassController().GetStorageClassList) + httpRg.GET("api/v1/storage-class/:name", api.StorageClassController().GetStorageClassDetails) + httpRg.POST("api/v1/storage-class", api.StorageClassController().DeployStorageClass) + httpRg.DELETE("api/v1/storage-class/:name", api.StorageClassController().DeleteStorageClass) + // Service + httpRg.GET("api/v1/service", api.SvcController().GetSvcList) + httpRg.GET("api/v1/service/:name", api.SvcController().GetSvcDetails) + httpRg.POST("api/v1/service", api.SvcController().DeploySVC) + httpRg.DELETE("api/v1/service/:name", api.SvcController().DeleteSvc) } diff --git a/pkg/tasks/register_tasks.go b/pkg/tasks/register_tasks.go index 6afa0bf..26c71a2 100644 --- a/pkg/tasks/register_tasks.go +++ b/pkg/tasks/register_tasks.go @@ -158,4 +158,67 @@ func InitTaskRegistry() { RegisterTask(k8s.PvcService().GetPvcDetails, k8s.GetPvcDetailsInputParams{}) RegisterTask(k8s.PvcService().DeployPvc, k8s.DeployPvcInputParams{}) RegisterTask(k8s.PvcService().DeletePvc, k8s.DeletePvcInputParams{}) + + //replicaSet + RegisterTask(k8s.ReplicaSetService().GetReplicaSetList, k8s.GetReplicaSetListInputParams{}) + RegisterTask(k8s.ReplicaSetService().GetReplicaSetDetails, k8s.GetReplicaSetDetailsInputParams{}) + RegisterTask(k8s.ReplicaSetService().GetReplicaSetStats, k8s.GetReplicaSetStatsInputParams{}) + RegisterTask(k8s.ReplicaSetService().DeployReplicaSet, k8s.DeployReplicaSetInputParams{}) + RegisterTask(k8s.ReplicaSetService().DeleteReplicaSet, k8s.DeleteReplicaSetInputParams{}) + + //replicationController + RegisterTask(k8s.ReplicationControllerService().GetReplicationControllerList, k8s.GetReplicationControllerListInputParams{}) + RegisterTask(k8s.ReplicationControllerService().GetReplicationControllerList, k8s.GetReplicationControllerDetailsInputParams{}) + RegisterTask(k8s.ReplicationControllerService().DeployReplicationController, k8s.DeployReplicationControllerInputParams{}) + RegisterTask(k8s.ReplicationControllerService().DeleteReplicationController, k8s.DeleteReplicationControllerInputParams{}) + + //resourceQuota + RegisterTask(k8s.ResourceQuotaService().GetResourceQuotaList, k8s.GetResourceQuotaListInputParams{}) + RegisterTask(k8s.ResourceQuotaService().GetResourceQuotaDetails, k8s.GetResourceQuotaDetailsInputParams{}) + RegisterTask(k8s.ResourceQuotaService().DeployResourceQuota, k8s.DeployResourceQuotaInputParams{}) + RegisterTask(k8s.ResourceQuotaService().DeleteResourceQuota, k8s.DeleteResourceQuotaInputParams{}) + + //role + RegisterTask(k8s.RoleService().GetRoleList, k8s.GetRoleListInputParams{}) + RegisterTask(k8s.RoleService().GetRoleDetails, k8s.GetRoleDetailsInputParams{}) + RegisterTask(k8s.RoleService().DeployRole, k8s.DeployRoleInputParams{}) + RegisterTask(k8s.RoleService().DeleteRole, k8s.DeleteRoleInputParams{}) + + //roleBinding + RegisterTask(k8s.RoleBindingService().GetRoleBindingList, k8s.GetRoleBindingListInputParams{}) + RegisterTask(k8s.RoleBindingService().GetRoleBindingDetails, k8s.GetRoleBindingDetailsInputParams{}) + RegisterTask(k8s.RoleBindingService().DeployRoleBinding, k8s.DeployRoleBindingInputParams{}) + RegisterTask(k8s.RoleBindingService().DeleteRoleBinding, k8s.DeleteRoleBindingInputParams{}) + + //serviceAccount + RegisterTask(k8s.ServiceAccountService().GetServiceAccountList, k8s.GetServiceAccountListInputParams{}) + RegisterTask(k8s.ServiceAccountService().GetServiceAccountDetails, k8s.GetServiceAccountDetailsInputParams{}) + RegisterTask(k8s.ServiceAccountService().DeployServiceAccount, k8s.DeployServiceAccountInputParams{}) + RegisterTask(k8s.ServiceAccountService().DeleteServiceAccount, k8s.DeleteServiceAccountInputParams{}) + + //secret + RegisterTask(k8s.SecretService().GetSecretList, k8s.GetSecretListInputParams{}) + RegisterTask(k8s.SecretService().GetSecretDetails, k8s.GetSecretDetailsInputParams{}) + RegisterTask(k8s.SecretService().DeploySecret, k8s.DeploySecretInputParams{}) + RegisterTask(k8s.SecretService().DeleteSecret, k8s.DeleteSecretInputParams{}) + + //statefulSet + RegisterTask(k8s.StatefulSetService().GetStatefulSetList, k8s.GetStatefulSetListInputParams{}) + RegisterTask(k8s.StatefulSetService().GetStatefulSetDetails, k8s.GetStatefulSetDetailsInputParams{}) + RegisterTask(k8s.StatefulSetService().GetStatefulSetStats, k8s.GetStatefulSetStatsInputParams{}) + RegisterTask(k8s.StatefulSetService().GetStatefulSetPodList, k8s.GetStatefulSetPodListInputParams{}) + RegisterTask(k8s.StatefulSetService().DeployStatefulSet, k8s.DeployStatefulSetInputParams{}) + RegisterTask(k8s.StatefulSetService().DeleteStatefulSet, k8s.DeleteStatefulSetInputParams{}) + + //storageClass + RegisterTask(k8s.StorageClassService().GetStorageClassList, k8s.GetStorageClassListInputParams{}) + RegisterTask(k8s.StorageClassService().GetStorageClassDetails, k8s.GetStorageClassDetailsInputParams{}) + RegisterTask(k8s.StorageClassService().DeployStorageClass, k8s.DeployStorageClassInputParams{}) + RegisterTask(k8s.StorageClassService().DeleteStorageClass, k8s.DeleteStorageClassInputParams{}) + + //svc + RegisterTask(k8s.SvcService().GetSvcList, k8s.GetSvcListInputParams{}) + RegisterTask(k8s.SvcService().GetSvcDetails, k8s.GetSvcDetailsInputParams{}) + RegisterTask(k8s.SvcService().DeploySvc, k8s.DeploySvcInputParams{}) + RegisterTask(k8s.SvcService().DeleteSvc, k8s.DeleteSvcInputParams{}) } From 521f47d9f0b081114fdc0dead9ce8f36a77ff364 Mon Sep 17 00:00:00 2001 From: Toha Date: Tue, 28 Jan 2025 19:37:13 +0600 Subject: [PATCH 20/64] all controller --- pkg/controller/api/certificate.go | 4 + pkg/controller/api/cluster_role.go | 8 + pkg/controller/api/cluster_role_binding.go | 8 + pkg/controller/api/configmap.go | 8 + pkg/controller/api/controller_revision.go | 8 + pkg/controller/api/crd.go | 8 + pkg/controller/api/cronjob.go | 8 + pkg/controller/api/custom_resource.go | 8 + pkg/controller/api/daemonset.go | 10 + pkg/controller/api/deployment.go | 12 ++ pkg/controller/api/endpoints.go | 8 + pkg/controller/api/endpointslice.go | 8 + pkg/controller/api/event.go | 4 + pkg/controller/api/hpa.go | 4 + pkg/controller/api/ingress.go | 8 + pkg/controller/api/istio_gateway.go | 8 + pkg/controller/api/job.go | 8 + pkg/controller/api/load_balancer.go | 4 + pkg/controller/api/manifest.go | 2 + pkg/controller/api/namespace.go | 9 + pkg/controller/api/network_policy.go | 4 + pkg/controller/api/node.go | 10 + pkg/controller/api/pod.go | 12 ++ pkg/controller/api/pod_disruption_budgets.go | 8 + pkg/controller/api/pod_metrics.go | 4 + pkg/controller/api/pv.go | 8 + pkg/controller/api/pvc.go | 8 + pkg/controller/api/replicaset.go | 10 + pkg/controller/api/replication_controller.go | 8 + pkg/controller/api/resource_quota.go | 8 + pkg/controller/api/role.go | 8 + pkg/controller/api/role_binding.go | 8 + pkg/controller/api/sa.go | 8 + pkg/controller/api/secret.go | 8 + pkg/controller/api/statefulset.go | 12 ++ pkg/controller/api/storage_class.go | 8 + pkg/controller/api/svc.go | 8 + pkg/controller/api/virtual_service.go | 174 ++++++++++++++++++ pkg/controller/api/volume_snapshot.go | 172 +++++++++++++++++ pkg/controller/api/volume_snapshot_class.go | 87 +++++++++ pkg/controller/api/volume_snapshot_content.go | 87 +++++++++ pkg/server/router/routes.go | 16 ++ pkg/tasks/register_tasks.go | 20 ++ 43 files changed, 841 insertions(+) create mode 100644 pkg/controller/api/virtual_service.go create mode 100644 pkg/controller/api/volume_snapshot.go create mode 100644 pkg/controller/api/volume_snapshot_class.go create mode 100644 pkg/controller/api/volume_snapshot_content.go diff --git a/pkg/controller/api/certificate.go b/pkg/controller/api/certificate.go index 7f45e2b..a5442ef 100644 --- a/pkg/controller/api/certificate.go +++ b/pkg/controller/api/certificate.go @@ -68,6 +68,7 @@ func (ctrl *certificateController) GetCertificateList(ctx *gin.Context) { err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -97,6 +98,7 @@ func (ctrl *certificateController) GetCertificateDetails(ctx *gin.Context) { err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -130,6 +132,7 @@ func (ctrl *certificateController) DeployCertificate(ctx *gin.Context) { err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -159,6 +162,7 @@ func (ctrl *certificateController) DeleteCertificate(ctx *gin.Context) { err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/cluster_role.go b/pkg/controller/api/cluster_role.go index fe04414..238f52b 100644 --- a/pkg/controller/api/cluster_role.go +++ b/pkg/controller/api/cluster_role.go @@ -57,10 +57,12 @@ func (ctrl *clusterRoleController) GetClusterRoleList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -78,10 +80,12 @@ func (ctrl *clusterRoleController) GetClusterRoleDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -106,10 +110,12 @@ func (ctrl *clusterRoleController) DeployClusterRole(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -127,10 +133,12 @@ func (ctrl *clusterRoleController) DeleteClusterRole(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/cluster_role_binding.go b/pkg/controller/api/cluster_role_binding.go index df3f575..1c8ef87 100644 --- a/pkg/controller/api/cluster_role_binding.go +++ b/pkg/controller/api/cluster_role_binding.go @@ -56,10 +56,12 @@ func (ctrl *clusterRoleBindingController) GetClusterRoleBindingList(ctx *gin.Con res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -77,10 +79,12 @@ func (ctrl *clusterRoleBindingController) GetClusterRoleBindingDetails(ctx *gin. res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -105,10 +109,12 @@ func (ctrl *clusterRoleBindingController) DeployClusterRoleBinding(ctx *gin.Cont res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -126,10 +132,12 @@ func (ctrl *clusterRoleBindingController) DeleteClusterRoleBinding(ctx *gin.Cont res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/configmap.go b/pkg/controller/api/configmap.go index 2b610fc..3e0f233 100644 --- a/pkg/controller/api/configmap.go +++ b/pkg/controller/api/configmap.go @@ -64,10 +64,12 @@ func (ctrl *configMapController) GetConfigMapList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -93,10 +95,12 @@ func (ctrl *configMapController) GetConfigMapDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -126,10 +130,12 @@ func (ctrl *configMapController) DeployConfigMap(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -155,10 +161,12 @@ func (ctrl *configMapController) DeleteConfigMap(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/controller_revision.go b/pkg/controller/api/controller_revision.go index 46efecd..61f1474 100644 --- a/pkg/controller/api/controller_revision.go +++ b/pkg/controller/api/controller_revision.go @@ -64,10 +64,12 @@ func (ctrl *controllerRevisionController) GetControllerRevisionList(ctx *gin.Con res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -93,10 +95,12 @@ func (ctrl *controllerRevisionController) GetControllerRevisionDetails(ctx *gin. res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -126,10 +130,12 @@ func (ctrl *controllerRevisionController) DeployControllerRevision(ctx *gin.Cont res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -155,10 +161,12 @@ func (ctrl *controllerRevisionController) DeleteControllerRevision(ctx *gin.Cont res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/crd.go b/pkg/controller/api/crd.go index 3001f6a..c14c937 100644 --- a/pkg/controller/api/crd.go +++ b/pkg/controller/api/crd.go @@ -55,10 +55,12 @@ func (ctrl *crdController) GetCrdList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -76,10 +78,12 @@ func (ctrl *crdController) GetCrdDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -103,10 +107,12 @@ func (ctrl *crdController) DeployCrd(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -124,10 +130,12 @@ func (ctrl *crdController) DeleteCrd(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/cronjob.go b/pkg/controller/api/cronjob.go index 252528e..86afdd4 100644 --- a/pkg/controller/api/cronjob.go +++ b/pkg/controller/api/cronjob.go @@ -63,10 +63,12 @@ func (ctrl *cronJobController) GetCronJobList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -92,10 +94,12 @@ func (ctrl *cronJobController) GetCronJobDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -125,10 +129,12 @@ func (ctrl *cronJobController) DeployCronJob(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -154,10 +160,12 @@ func (ctrl *cronJobController) DeleteCronJob(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/custom_resource.go b/pkg/controller/api/custom_resource.go index 218d97a..0d254fb 100644 --- a/pkg/controller/api/custom_resource.go +++ b/pkg/controller/api/custom_resource.go @@ -62,10 +62,12 @@ func (ctrl *customResourceController) GetCustomResourceList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -89,10 +91,12 @@ func (ctrl *customResourceController) GetCustomResourceDetails(ctx *gin.Context) res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -122,10 +126,12 @@ func (ctrl *customResourceController) DeployCustomResource(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -148,10 +154,12 @@ func (ctrl *customResourceController) DeleteCustomResource(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/daemonset.go b/pkg/controller/api/daemonset.go index c9b3aa7..9fecbe2 100644 --- a/pkg/controller/api/daemonset.go +++ b/pkg/controller/api/daemonset.go @@ -66,10 +66,12 @@ func (ctrl *daemonSetController) GetDaemonSetList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -95,10 +97,12 @@ func (ctrl *daemonSetController) GetDaemonSetDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -128,10 +132,12 @@ func (ctrl *daemonSetController) DeployDaemonSet(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -157,10 +163,12 @@ func (ctrl *daemonSetController) DeleteDaemonSet(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -201,10 +209,12 @@ func (ctrl *daemonSetController) GetDaemonSetStats(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/deployment.go b/pkg/controller/api/deployment.go index 9a50ff0..11b1e08 100644 --- a/pkg/controller/api/deployment.go +++ b/pkg/controller/api/deployment.go @@ -67,10 +67,12 @@ func (ctrl *deploymentController) GetDeploymentList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -96,10 +98,12 @@ func (ctrl *deploymentController) GetDeploymentDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -129,10 +133,12 @@ func (ctrl *deploymentController) DeployDeployment(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -158,10 +164,12 @@ func (ctrl *deploymentController) DeleteDeployment(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -202,10 +210,12 @@ func (ctrl *deploymentController) GetDeploymentStats(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -257,10 +267,12 @@ func (ctrl *deploymentController) GetDeploymentPodList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/endpoints.go b/pkg/controller/api/endpoints.go index 4d5a340..2bbafd7 100644 --- a/pkg/controller/api/endpoints.go +++ b/pkg/controller/api/endpoints.go @@ -64,10 +64,12 @@ func (ctrl *endpointsController) GetEndpointsList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -93,10 +95,12 @@ func (ctrl *endpointsController) GetEndpointsDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -127,10 +131,12 @@ func (ctrl *endpointsController) DeployEndpoints(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -155,10 +161,12 @@ func (ctrl *endpointsController) DeleteEndpoints(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/endpointslice.go b/pkg/controller/api/endpointslice.go index 319e8a2..ed78234 100644 --- a/pkg/controller/api/endpointslice.go +++ b/pkg/controller/api/endpointslice.go @@ -63,10 +63,12 @@ func (ctrl *endpointSliceController) GetEndpointSliceList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -92,10 +94,12 @@ func (ctrl *endpointSliceController) GetEndpointSliceDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -126,10 +130,12 @@ func (ctrl *endpointSliceController) DeployEndpointSlice(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -153,10 +159,12 @@ func (ctrl *endpointSliceController) DeleteEndpointSlice(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/event.go b/pkg/controller/api/event.go index 0c345a7..1666f1e 100644 --- a/pkg/controller/api/event.go +++ b/pkg/controller/api/event.go @@ -63,10 +63,12 @@ func (ctrl *eventController) GetEventList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -93,10 +95,12 @@ func (ctrl *eventController) GetEventDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/hpa.go b/pkg/controller/api/hpa.go index dbacca6..be2188b 100644 --- a/pkg/controller/api/hpa.go +++ b/pkg/controller/api/hpa.go @@ -60,10 +60,12 @@ func (ctrl *hpaController) GetHpaList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -90,10 +92,12 @@ func (ctrl *hpaController) GetHpaDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/ingress.go b/pkg/controller/api/ingress.go index 4dbddce..0991371 100644 --- a/pkg/controller/api/ingress.go +++ b/pkg/controller/api/ingress.go @@ -65,10 +65,12 @@ func (ctrl *ingressController) GetIngressList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -95,10 +97,12 @@ func (ctrl *ingressController) GetIngressDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -128,10 +132,12 @@ func (ctrl *ingressController) DeployIngress(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -157,10 +163,12 @@ func (ctrl *ingressController) DeleteIngress(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/istio_gateway.go b/pkg/controller/api/istio_gateway.go index 2b3a948..802f29d 100644 --- a/pkg/controller/api/istio_gateway.go +++ b/pkg/controller/api/istio_gateway.go @@ -65,10 +65,12 @@ func (ctrl *istioGatewayController) GetIstioGatewayList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -95,10 +97,12 @@ func (ctrl *istioGatewayController) GetIstioGatewayDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -128,10 +132,12 @@ func (ctrl *istioGatewayController) DeployIstioGateway(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -157,10 +163,12 @@ func (ctrl *istioGatewayController) DeleteIstioGateway(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/job.go b/pkg/controller/api/job.go index 77f6a61..002cd64 100644 --- a/pkg/controller/api/job.go +++ b/pkg/controller/api/job.go @@ -65,10 +65,12 @@ func (ctrl *jobController) GetJobList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -95,10 +97,12 @@ func (ctrl *jobController) GetJobDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -127,10 +131,12 @@ func (ctrl *jobController) DeployJob(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -156,10 +162,12 @@ func (ctrl *jobController) DeleteJob(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/load_balancer.go b/pkg/controller/api/load_balancer.go index 72344af..ffc97a4 100644 --- a/pkg/controller/api/load_balancer.go +++ b/pkg/controller/api/load_balancer.go @@ -60,10 +60,12 @@ func (ctrl *loadBalancerController) GetLoadBalancerList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -90,10 +92,12 @@ func (ctrl *loadBalancerController) GetLoadBalancerDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/manifest.go b/pkg/controller/api/manifest.go index 6f35138..7720891 100644 --- a/pkg/controller/api/manifest.go +++ b/pkg/controller/api/manifest.go @@ -59,10 +59,12 @@ func (ctrl *manifestController) DeployManifest(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/namespace.go b/pkg/controller/api/namespace.go index e973823..95fdcc8 100644 --- a/pkg/controller/api/namespace.go +++ b/pkg/controller/api/namespace.go @@ -71,6 +71,7 @@ func (ctrl *namespaceController) GetNamespaceList(ctx *gin.Context) { err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -87,10 +88,12 @@ func (ctrl *namespaceController) GetNamespaceNameList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -116,10 +119,12 @@ func (ctrl *namespaceController) DeployNamespace(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -137,10 +142,12 @@ func (ctrl *namespaceController) GetNamespaceDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -159,10 +166,12 @@ func (ctrl *namespaceController) DeleteNamespace(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/network_policy.go b/pkg/controller/api/network_policy.go index bcaa351..8edc697 100644 --- a/pkg/controller/api/network_policy.go +++ b/pkg/controller/api/network_policy.go @@ -62,10 +62,12 @@ func (ctrl *networkPolicyController) GetNetworkPolicyList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -92,10 +94,12 @@ func (ctrl *networkPolicyController) GetNetworkPolicyDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/node.go b/pkg/controller/api/node.go index d4a8c0d..cb9b1be 100644 --- a/pkg/controller/api/node.go +++ b/pkg/controller/api/node.go @@ -55,10 +55,12 @@ func (ctrl *nodeController) GetNodeList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -77,10 +79,12 @@ func (ctrl *nodeController) GetNodeDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -99,10 +103,12 @@ func (ctrl *nodeController) NodeCordon(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -130,10 +136,12 @@ func (ctrl *nodeController) NodeTaint(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -159,10 +167,12 @@ func (ctrl *nodeController) NodeUnTaint(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/pod.go b/pkg/controller/api/pod.go index 4354f5f..df66f74 100644 --- a/pkg/controller/api/pod.go +++ b/pkg/controller/api/pod.go @@ -68,10 +68,12 @@ func (ctrl *podController) GetPodList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -98,10 +100,12 @@ func (ctrl *podController) GetPodDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -131,10 +135,12 @@ func (ctrl *podController) DeployPod(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -160,10 +166,12 @@ func (ctrl *podController) DeletePod(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -205,10 +213,12 @@ func (ctrl *podController) GetPodStats(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -248,10 +258,12 @@ func (ctrl *podController) GetPodLogs(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/pod_disruption_budgets.go b/pkg/controller/api/pod_disruption_budgets.go index f379f1d..f4209ac 100644 --- a/pkg/controller/api/pod_disruption_budgets.go +++ b/pkg/controller/api/pod_disruption_budgets.go @@ -65,10 +65,12 @@ func (ctrl *podDisruptionBudgetsController) GetPodDisruptionBudgetsList(ctx *gin res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -95,10 +97,12 @@ func (ctrl *podDisruptionBudgetsController) GetPodDisruptionBudgetsDetails(ctx * res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -128,10 +132,12 @@ func (ctrl *podDisruptionBudgetsController) DeployPodDisruptionBudgets(ctx *gin. res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -157,10 +163,12 @@ func (ctrl *podDisruptionBudgetsController) DeletePodDisruptionBudgets(ctx *gin. res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/pod_metrics.go b/pkg/controller/api/pod_metrics.go index 2db8de3..1297731 100644 --- a/pkg/controller/api/pod_metrics.go +++ b/pkg/controller/api/pod_metrics.go @@ -44,10 +44,12 @@ func (ctrl *podMetricsController) GetPodMetricsList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -74,10 +76,12 @@ func (ctrl *podMetricsController) GetPodMetricsDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/pv.go b/pkg/controller/api/pv.go index f26428d..da58c02 100644 --- a/pkg/controller/api/pv.go +++ b/pkg/controller/api/pv.go @@ -58,10 +58,12 @@ func (ctrl *pvController) GetPvList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -80,10 +82,12 @@ func (ctrl *pvController) GetPvDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -108,10 +112,12 @@ func (ctrl *pvController) DeployPv(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -129,10 +135,12 @@ func (ctrl *pvController) DeletePv(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/pvc.go b/pkg/controller/api/pvc.go index d92215b..a2afcb4 100644 --- a/pkg/controller/api/pvc.go +++ b/pkg/controller/api/pvc.go @@ -65,10 +65,12 @@ func (ctrl *pvcController) GetPvcList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -95,10 +97,12 @@ func (ctrl *pvcController) GetPvcDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -128,10 +132,12 @@ func (ctrl *pvcController) DeployPvc(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -157,10 +163,12 @@ func (ctrl *pvcController) DeletePvc(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/replicaset.go b/pkg/controller/api/replicaset.go index 57e7267..3bcbc16 100644 --- a/pkg/controller/api/replicaset.go +++ b/pkg/controller/api/replicaset.go @@ -65,10 +65,12 @@ func (ctrl *replicaSetController) GetReplicaSetList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -95,10 +97,12 @@ func (ctrl *replicaSetController) GetReplicaSetDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -128,10 +132,12 @@ func (ctrl *replicaSetController) DeployReplicaSet(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -157,10 +163,12 @@ func (ctrl *replicaSetController) DeleteReplicaSet(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -202,10 +210,12 @@ func (ctrl *replicaSetController) GetReplicaSetStats(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/replication_controller.go b/pkg/controller/api/replication_controller.go index 28a9258..8787f37 100644 --- a/pkg/controller/api/replication_controller.go +++ b/pkg/controller/api/replication_controller.go @@ -65,10 +65,12 @@ func (ctrl *replicationControllerController) GetReplicationControllerList(ctx *g res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -95,10 +97,12 @@ func (ctrl *replicationControllerController) GetReplicationControllerDetails(ctx res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -128,10 +132,12 @@ func (ctrl *replicationControllerController) DeployReplicationController(ctx *gi res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -157,10 +163,12 @@ func (ctrl *replicationControllerController) DeleteReplicationController(ctx *gi res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/resource_quota.go b/pkg/controller/api/resource_quota.go index aee7e91..6bafb02 100644 --- a/pkg/controller/api/resource_quota.go +++ b/pkg/controller/api/resource_quota.go @@ -65,10 +65,12 @@ func (ctrl *resourceQuotaController) GetResourceQuotaList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -95,10 +97,12 @@ func (ctrl *resourceQuotaController) GetResourceQuotaDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -130,10 +134,12 @@ func (ctrl *resourceQuotaController) DeployResourceQuota(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -160,10 +166,12 @@ func (ctrl *resourceQuotaController) DeleteResourceQuota(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/role.go b/pkg/controller/api/role.go index 870ca24..7496001 100644 --- a/pkg/controller/api/role.go +++ b/pkg/controller/api/role.go @@ -65,10 +65,12 @@ func (ctrl *roleController) GetRoleList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -95,10 +97,12 @@ func (ctrl *roleController) GetRoleDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -128,10 +132,12 @@ func (ctrl *roleController) DeployRole(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -157,10 +163,12 @@ func (ctrl *roleController) DeleteRole(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/role_binding.go b/pkg/controller/api/role_binding.go index 9df9fb6..f4450b0 100644 --- a/pkg/controller/api/role_binding.go +++ b/pkg/controller/api/role_binding.go @@ -65,10 +65,12 @@ func (ctrl *roleBindingController) GetRoleBindingList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -95,10 +97,12 @@ func (ctrl *roleBindingController) GetRoleBindingDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -128,10 +132,12 @@ func (ctrl *roleBindingController) DeployRoleBinding(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -157,10 +163,12 @@ func (ctrl *roleBindingController) DeleteRoleBinding(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/sa.go b/pkg/controller/api/sa.go index ddd8e06..bc9e224 100644 --- a/pkg/controller/api/sa.go +++ b/pkg/controller/api/sa.go @@ -65,10 +65,12 @@ func (ctrl *serviceAccountController) GetServiceAccountList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -95,10 +97,12 @@ func (ctrl *serviceAccountController) GetServiceAccountDetails(ctx *gin.Context) res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -128,10 +132,12 @@ func (ctrl *serviceAccountController) DeployServiceAccount(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -157,10 +163,12 @@ func (ctrl *serviceAccountController) DeleteServiceAccount(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/secret.go b/pkg/controller/api/secret.go index 425bef8..8fa1eb8 100644 --- a/pkg/controller/api/secret.go +++ b/pkg/controller/api/secret.go @@ -65,10 +65,12 @@ func (ctrl *secretController) GetSecretList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -95,10 +97,12 @@ func (ctrl *secretController) GetSecretDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -123,10 +127,12 @@ func (ctrl *secretController) DeploySecret(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -144,10 +150,12 @@ func (ctrl *secretController) DeleteSecret(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/statefulset.go b/pkg/controller/api/statefulset.go index 51db975..4d41079 100644 --- a/pkg/controller/api/statefulset.go +++ b/pkg/controller/api/statefulset.go @@ -67,10 +67,12 @@ func (ctrl *statefulSetController) GetStatefulSetList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -97,10 +99,12 @@ func (ctrl *statefulSetController) GetStatefulSetDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -130,10 +134,12 @@ func (ctrl *statefulSetController) DeployStatefulSet(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -159,10 +165,12 @@ func (ctrl *statefulSetController) DeleteStatefulSet(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -204,10 +212,12 @@ func (ctrl *statefulSetController) GetStatefulSetStats(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -248,10 +258,12 @@ func (ctrl *statefulSetController) GetStatefulSetPodList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/storage_class.go b/pkg/controller/api/storage_class.go index 6380254..6bfa628 100644 --- a/pkg/controller/api/storage_class.go +++ b/pkg/controller/api/storage_class.go @@ -57,10 +57,12 @@ func (ctrl *storageClassController) GetStorageClassList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -79,10 +81,12 @@ func (ctrl *storageClassController) GetStorageClassDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -107,10 +111,12 @@ func (ctrl *storageClassController) DeployStorageClass(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -128,10 +134,12 @@ func (ctrl *storageClassController) DeleteStorageClass(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/svc.go b/pkg/controller/api/svc.go index 7e32f6d..9bf61d7 100644 --- a/pkg/controller/api/svc.go +++ b/pkg/controller/api/svc.go @@ -65,10 +65,12 @@ func (ctrl *svcController) GetSvcList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -95,10 +97,12 @@ func (ctrl *svcController) GetSvcDetails(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -129,10 +133,12 @@ func (ctrl *svcController) DeploySVC(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } @@ -158,10 +164,12 @@ func (ctrl *svcController) DeleteSvc(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { SendErrorResponse(ctx, err.Error()) + return } SendResponse(ctx, result) } diff --git a/pkg/controller/api/virtual_service.go b/pkg/controller/api/virtual_service.go new file mode 100644 index 0000000..edfe84d --- /dev/null +++ b/pkg/controller/api/virtual_service.go @@ -0,0 +1,174 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" + "istio.io/client-go/pkg/apis/networking/v1beta1" +) + +type VirtualServiceControllerInterface interface { + GetVirtualServiceList(ctx *gin.Context) + GetVirtualServiceDetails(ctx *gin.Context) + DeployVirtualService(ctx *gin.Context) + DeleteVirtualService(ctx *gin.Context) +} + +type virtualServiceController struct { +} + +var vsec virtualServiceController + +func VirtualServiceController() *virtualServiceController { + return &vsec +} + +func (ctrl *virtualServiceController) GetVirtualServiceList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetVirtualServiceListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Continue = ctx.Query("continue") + input.Search = ctx.Query("q") + input.Limit = ctx.Query("limit") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for VirtualService List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.VirtualServiceService().GetVirtualServiceList) + logRequestedTaskController("virtual-service", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + SendResponse(ctx, result) +} + +func (ctrl *virtualServiceController) GetVirtualServiceDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetVirtualServiceDetailsInputParams) + input.VirtualServiceName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.VirtualServiceService().GetVirtualServiceDetails) + logRequestedTaskController("virtual-service", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + SendResponse(ctx, result) +} + +func (ctrl *virtualServiceController) DeployVirtualService(ctx *gin.Context) { + var result ResponseDTO + payload := new(v1beta1.VirtualService) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy VirtualService payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployVirtualServiceInputParams) + input.VirtualService = payload + if input.VirtualService.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "virtualService deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.VirtualServiceService().DeployVirtualService) + logRequestedTaskController("virtual-service", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + SendResponse(ctx, result) +} + +func (ctrl *virtualServiceController) DeleteVirtualService(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteVirtualServiceInputParams) + input.VirtualServiceName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.VirtualServiceService().DeleteVirtualService) + logRequestedTaskController("virtual-service", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/volume_snapshot.go b/pkg/controller/api/volume_snapshot.go new file mode 100644 index 0000000..2c85881 --- /dev/null +++ b/pkg/controller/api/volume_snapshot.go @@ -0,0 +1,172 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/dto" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" +) + +type VolumeSnapshotControllerInterface interface { + GetVolumeSnapshotList(ctx *gin.Context) + GetVolumeSnapshotDetails(ctx *gin.Context) + DeployVolumeSnapshot(ctx *gin.Context) + DeleteVolumeSnapshot(ctx *gin.Context) +} + +type volumeSnapshotController struct { +} + +var vsc volumeSnapshotController + +func VolumeSnapshotController() *volumeSnapshotController { + return &vsc +} + +func (ctrl *volumeSnapshotController) GetVolumeSnapshotList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetVolumeSnapshotListInputParams) + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + input.Search = ctx.Query("q") + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for VolumeSnapshot List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + taskName := tasks.GetTaskName(k8s.VolumeSnapshotService().GetVolumeSnapshotList) + logRequestedTaskController("volume-snapshot", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + SendResponse(ctx, result) +} + +func (ctrl *volumeSnapshotController) GetVolumeSnapshotDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetVolumeSnapshotDetailsInputParams) + input.VolumeSnapshotName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.VolumeSnapshotService().GetVolumeSnapshotDetails) + logRequestedTaskController("volume-snapshot", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + SendResponse(ctx, result) +} + +func (ctrl *volumeSnapshotController) DeployVolumeSnapshot(ctx *gin.Context) { + var result ResponseDTO + payload := new(dto.VolumeSnapshotV1) + if err := ctx.Bind(payload); err != nil { + log.Logger.Errorw("Failed to bind deploy VolumeSnapshot payload", "err", err.Error()) + SendErrorResponse(ctx, err.Error()) + return + } + + input := new(k8s.DeployVolumeSnapshotInputParams) + input.VolumeSnapshot = payload + if input.VolumeSnapshot.Namespace == "" { + log.Logger.Errorw("namespace required in payload", "value", "volumeSnapshot deploy") + SendErrorResponse(ctx, ErrNamespaceEmpty) + return + } + taskName := tasks.GetTaskName(k8s.VolumeSnapshotService().DeployVolumeSnapshot) + logRequestedTaskController("volume-snapshot", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + SendResponse(ctx, result) +} + +func (ctrl *volumeSnapshotController) DeleteVolumeSnapshot(ctx *gin.Context) { + var result ResponseDTO + input := new(k8s.DeleteVolumeSnapshotInputParams) + input.VolumeSnapshotName = ctx.Param("name") + + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace + taskName := tasks.GetTaskName(k8s.VolumeSnapshotService().DeleteVolumeSnapshot) + logRequestedTaskController("volume-snapshot", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/volume_snapshot_class.go b/pkg/controller/api/volume_snapshot_class.go new file mode 100644 index 0000000..1e65bfc --- /dev/null +++ b/pkg/controller/api/volume_snapshot_class.go @@ -0,0 +1,87 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" +) + +type VolumeSnapshotClassControllerInterface interface { + GetVolumeSnapshotClassList(ctx *gin.Context) + GetVolumeSnapshotClassDetails(ctx *gin.Context) +} + +type volumeSnapshotClassController struct { +} + +var vsclc volumeSnapshotClassController + +func VolumeSnapshotClassController() *volumeSnapshotClassController { + return &vsclc +} + +func (ctrl *volumeSnapshotClassController) GetVolumeSnapshotClassList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetVolumeSnapshotClassListInputParams) + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for VolumeSnapshotClass List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + input.Search = ctx.Query("q") + taskName := tasks.GetTaskName(k8s.VolumeSnapshotClassService().GetVolumeSnapshotClassList) + logRequestedTaskController("volume-snapshot-class", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + SendResponse(ctx, result) +} + +func (ctrl *volumeSnapshotClassController) GetVolumeSnapshotClassDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetVolumeSnapshotClassDetailsInputParams) + input.VolumeSnapshotClassName = ctx.Param("name") + taskName := tasks.GetTaskName(k8s.VolumeSnapshotClassService().GetVolumeSnapshotClassDetails) + logRequestedTaskController("volume-snapshot-class", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + SendResponse(ctx, result) +} diff --git a/pkg/controller/api/volume_snapshot_content.go b/pkg/controller/api/volume_snapshot_content.go new file mode 100644 index 0000000..6f94008 --- /dev/null +++ b/pkg/controller/api/volume_snapshot_content.go @@ -0,0 +1,87 @@ +package api + +import ( + "encoding/json" + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/controller/worker" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/krack8/lighthouse/pkg/tasks" +) + +type VolumeSnapshotContentControllerInterface interface { + GetVolumeSnapshotContentList(ctx *gin.Context) + GetVolumeSnapshotContentDetails(ctx *gin.Context) +} + +type volumeSnapshotContentController struct { +} + +var vscc volumeSnapshotContentController + +func VolumeSnapshotContentController() *volumeSnapshotContentController { + return &vscc +} + +func (ctrl *volumeSnapshotContentController) GetVolumeSnapshotContentList(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetVolumeSnapshotContentListInputParams) + + queryLabel := ctx.Query("labels") + if queryLabel != "" { + jsonLabel := []byte(queryLabel) + queryLabelMap := map[string]string{} + + err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + if err != nil { + log.Logger.Error("query labels unmarshal error ", "err", err.Error()) + } + if queryLabelMap != nil { + input.Labels = queryLabelMap + log.Logger.Info("Filter by param for VolumeSnapshotContent List param Map: ", queryLabelMap, " values: ", ctx.Query("labels")) + } + } + input.Search = ctx.Query("q") + taskName := tasks.GetTaskName(k8s.VolumeSnapshotContentService().GetVolumeSnapshotContentList) + logRequestedTaskController("volume-snapshot-content", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + SendResponse(ctx, result) +} + +func (ctrl *volumeSnapshotContentController) GetVolumeSnapshotContentDetails(ctx *gin.Context) { + var result ResponseDTO + + input := new(k8s.GetVolumeSnapshotContentDetailsInputParams) + input.VolumeSnapshotContentName = ctx.Param("name") + taskName := tasks.GetTaskName(k8s.VolumeSnapshotContentService().GetVolumeSnapshotContentDetails) + logRequestedTaskController("volume-snapshot-content", taskName) + inputTask, err := json.Marshal(input) + if err != nil { + logErrMarshalTaskController(taskName, err) + } + res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + err = json.Unmarshal([]byte(res.Output), &result) + if err != nil { + SendErrorResponse(ctx, err.Error()) + return + } + SendResponse(ctx, result) +} diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index 9172303..ddfb019 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -218,4 +218,20 @@ func AddApiRoutes(httpRg *gin.RouterGroup) { httpRg.GET("api/v1/service/:name", api.SvcController().GetSvcDetails) httpRg.POST("api/v1/service", api.SvcController().DeploySVC) httpRg.DELETE("api/v1/service/:name", api.SvcController().DeleteSvc) + // Virtual Service + httpRg.GET("api/v1/virtual-service", api.VirtualServiceController().GetVirtualServiceList) + httpRg.GET("api/v1/virtual-service/:name", api.VirtualServiceController().GetVirtualServiceDetails) + httpRg.POST("api/v1/virtual-service", api.VirtualServiceController().DeployVirtualService) + httpRg.DELETE("api/v1/virtual-service/:name", api.VirtualServiceController().DeleteVirtualService) + // Volume Snapshot + httpRg.GET("api/v1/volume-snapshot", api.VolumeSnapshotController().GetVolumeSnapshotList) + httpRg.GET("api/v1/volume-snapshot/:name", api.VolumeSnapshotController().GetVolumeSnapshotDetails) + httpRg.POST("api/v1/volume-snapshot", api.VolumeSnapshotController().DeployVolumeSnapshot) + httpRg.DELETE("api/v1/volume-snapshot/:name", api.VolumeSnapshotController().DeleteVolumeSnapshot) + // Volume Snapshot Content + httpRg.GET("api/v1/volume-snapshot-content", api.VolumeSnapshotContentController().GetVolumeSnapshotContentList) + httpRg.GET("api/v1/volume-snapshot-content/:name", api.VolumeSnapshotContentController().GetVolumeSnapshotContentDetails) + // Volume Snapshot Class + httpRg.GET("api/v1/volume-snapshot-class", api.VolumeSnapshotClassController().GetVolumeSnapshotClassList) + httpRg.GET("api/v1/volume-snapshot-class/:name", api.VolumeSnapshotClassController().GetVolumeSnapshotClassDetails) } diff --git a/pkg/tasks/register_tasks.go b/pkg/tasks/register_tasks.go index 26c71a2..bca00c0 100644 --- a/pkg/tasks/register_tasks.go +++ b/pkg/tasks/register_tasks.go @@ -221,4 +221,24 @@ func InitTaskRegistry() { RegisterTask(k8s.SvcService().GetSvcDetails, k8s.GetSvcDetailsInputParams{}) RegisterTask(k8s.SvcService().DeploySvc, k8s.DeploySvcInputParams{}) RegisterTask(k8s.SvcService().DeleteSvc, k8s.DeleteSvcInputParams{}) + + //virtualService + RegisterTask(k8s.VirtualServiceService().GetVirtualServiceList, k8s.GetVirtualServiceListInputParams{}) + RegisterTask(k8s.VirtualServiceService().GetVirtualServiceDetails, k8s.GetVirtualServiceDetailsInputParams{}) + RegisterTask(k8s.VirtualServiceService().DeployVirtualService, k8s.DeployVirtualServiceInputParams{}) + RegisterTask(k8s.VirtualServiceService().DeleteVirtualService, k8s.DeleteVirtualServiceInputParams{}) + + //volumeSnapshot + RegisterTask(k8s.VolumeSnapshotService().GetVolumeSnapshotList, k8s.GetVolumeSnapshotListInputParams{}) + RegisterTask(k8s.VolumeSnapshotService().GetVolumeSnapshotDetails, k8s.GetVolumeSnapshotDetailsInputParams{}) + RegisterTask(k8s.VolumeSnapshotService().DeployVolumeSnapshot, k8s.DeployVolumeSnapshotInputParams{}) + RegisterTask(k8s.VolumeSnapshotService().DeleteVolumeSnapshot, k8s.DeleteVolumeSnapshotInputParams{}) + + //volumeSnapshotClass + RegisterTask(k8s.VolumeSnapshotClassService().GetVolumeSnapshotClassList, k8s.GetVolumeSnapshotClassListInputParams{}) + RegisterTask(k8s.VolumeSnapshotClassService().GetVolumeSnapshotClassDetails, k8s.GetVolumeSnapshotClassDetailsInputParams{}) + + //volumeSnapshotContent + RegisterTask(k8s.VolumeSnapshotContentService().GetVolumeSnapshotContentList, k8s.GetVolumeSnapshotContentListInputParams{}) + RegisterTask(k8s.VolumeSnapshotContentService().GetVolumeSnapshotContentDetails, k8s.GetVolumeSnapshotContentDetailsInputParams{}) } From b6c886ef801ceec2fd4aff9de63b78b90dc88dd0 Mon Sep 17 00:00:00 2001 From: Nahid Date: Wed, 29 Jan 2025 15:02:42 +0600 Subject: [PATCH 21/64] refactor: modify routes with middleware --- go.mod | 2 +- pkg/auth/authApi/init_global_var.go | 52 +++ .../controllers/role_permission_controller.go | 6 + pkg/auth/controllers/user_controller.go | 6 + pkg/auth/models/user.go | 3 +- pkg/auth/services/rbac_service.go | 12 +- pkg/auth/services/user_service.go | 3 +- pkg/controller/main.go | 4 + pkg/server/router/routes.go | 371 ++++++++++-------- pkg/server/server.go | 15 - 10 files changed, 288 insertions(+), 186 deletions(-) create mode 100644 pkg/auth/authApi/init_global_var.go diff --git a/go.mod b/go.mod index abacaf9..1d287fd 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,6 @@ require ( github.com/go-playground/validator/v10 v10.24.0 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/google/uuid v1.6.0 - github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 github.com/joho/godotenv v1.5.1 github.com/kubernetes-csi/external-snapshotter/client/v6 v6.3.0 @@ -86,6 +85,7 @@ require ( github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/gorilla/mux v1.8.0 // indirect github.com/gosuri/uitable v0.0.4 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect diff --git a/pkg/auth/authApi/init_global_var.go b/pkg/auth/authApi/init_global_var.go new file mode 100644 index 0000000..26b6ee9 --- /dev/null +++ b/pkg/auth/authApi/init_global_var.go @@ -0,0 +1,52 @@ +package authApi + +import ( + "github.com/krack8/lighthouse/pkg/auth/controllers" + "github.com/krack8/lighthouse/pkg/auth/services" + "sync" +) + +var ( + // Global service instances + UserService *services.UserService + RbacService *services.RbacService + + // UserController Global controller instances + UserController *controllers.UserController + RbacController *controllers.RbacController + + once sync.Once +) + +// Init initializes all services and controllers +func Init() { + once.Do(func() { + // Initialize services + UserService = &services.UserService{} + RbacService = &services.RbacService{} + + // Initialize controllers with services + UserController = controllers.NewUserController(UserService) + RbacController = controllers.NewRbacController(RbacService) + }) +} + +// GetUserService returns the global UserService instance +func GetUserService() *services.UserService { + return UserService +} + +// GetRbacService returns the global RbacService instance +func GetRbacService() *services.RbacService { + return RbacService +} + +// GetUserController returns the global UserController instance +func GetUserController() *controllers.UserController { + return UserController +} + +// GetRbacController returns the global RbacController instance +func GetRbacController() *controllers.RbacController { + return RbacController +} diff --git a/pkg/auth/controllers/role_permission_controller.go b/pkg/auth/controllers/role_permission_controller.go index 2b65555..17306b6 100644 --- a/pkg/auth/controllers/role_permission_controller.go +++ b/pkg/auth/controllers/role_permission_controller.go @@ -12,6 +12,12 @@ type RbacController struct { RbacService *services.RbacService } +func NewRbacController(rbacService *services.RbacService) *RbacController { + return &RbacController{ + RbacService: rbacService, + } +} + // CreatePermissionHandler handles the creation of a new permission func (rbac *RbacController) CreatePermissionHandler(c *gin.Context) { var permission models.Permission diff --git a/pkg/auth/controllers/user_controller.go b/pkg/auth/controllers/user_controller.go index 0cc76a6..6f4eaa8 100644 --- a/pkg/auth/controllers/user_controller.go +++ b/pkg/auth/controllers/user_controller.go @@ -12,6 +12,12 @@ type UserController struct { UserService *services.UserService } +func NewUserController(userService *services.UserService) *UserController { + return &UserController{ + UserService: userService, + } +} + // CreateUserHandler handles the creation of a new user. func (uc *UserController) CreateUserHandler(c *gin.Context) { var user models.User diff --git a/pkg/auth/models/user.go b/pkg/auth/models/user.go index 64e8d0e..a8bf2f5 100644 --- a/pkg/auth/models/user.go +++ b/pkg/auth/models/user.go @@ -20,9 +20,10 @@ type User struct { Username string `json:"username" bson:"username" validate:"required,email"` FirstName string `json:"first_name" bson:"first_name"` LastName string `json:"last_name" bson:"last_name"` - Password string `json:"password" bson:"password" validate:"required,min=6,max=15"` + Password string `json:"-" bson:"password" validate:"required,min=6,max=15"` UserType UserType `json:"user_type" bson:"user_type" validate:"required,oneof=ADMIN USER"` Roles []Role `json:"roles" bson:"roles"` + ClusterIdList []string `json:"clusterIdList" bson:"clusterIdList"` UserIsActive bool `json:"user_is_active" bson:"user_is_active" validate:"required"` IsVerified bool `json:"is_verified" bson:"is_verified" validate:"required"` ForgotPasswordToken string `json:"forgot_password_token,omitempty" bson:"forgot_password_token"` diff --git a/pkg/auth/services/rbac_service.go b/pkg/auth/services/rbac_service.go index 19f0610..58dcd1c 100644 --- a/pkg/auth/services/rbac_service.go +++ b/pkg/auth/services/rbac_service.go @@ -12,10 +12,16 @@ import ( "time" ) -// RBAC Service struct for user operations +// RBAC service handles rbac-related business logic type RbacService struct { - RbacCollection Collection - Context context.Context + collection Collection +} + +// NewRbacService creates a new RbacService instance +func NewRbacService(collection Collection) *RbacService { + return &RbacService{ + collection: collection, + } } // CreatePermission creates a new permission diff --git a/pkg/auth/services/user_service.go b/pkg/auth/services/user_service.go index 34901b8..38c21e5 100644 --- a/pkg/auth/services/user_service.go +++ b/pkg/auth/services/user_service.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" db "github.com/krack8/lighthouse/pkg/auth/config" + "github.com/krack8/lighthouse/pkg/auth/utils" "time" "github.com/krack8/lighthouse/pkg/auth/models" @@ -125,7 +126,7 @@ func (s *UserService) UpdateUser(userID string, updatedUser *models.User) error "firstname": updatedUser.FirstName, "lastname": updatedUser.LastName, "username": updatedUser.Username, - "password": updatedUser.Password, + "password": utils.HashPassword(updatedUser.Password), "usertype": updatedUser.UserType, "roles": updatedUser.Roles, "isactive": updatedUser.UserIsActive, diff --git a/pkg/controller/main.go b/pkg/controller/main.go index c70435e..eb625c4 100644 --- a/pkg/controller/main.go +++ b/pkg/controller/main.go @@ -2,6 +2,7 @@ package main import ( "github.com/joho/godotenv" + "github.com/krack8/lighthouse/pkg/auth/authApi" "github.com/krack8/lighthouse/pkg/auth/config" "github.com/krack8/lighthouse/pkg/controller/worker" _log "github.com/krack8/lighthouse/pkg/log" @@ -36,6 +37,9 @@ func main() { // Initialize the default user if needed config.InitializeDefaultUser() + // Initialize auth controllers with services + authApi.Init() + // Start HTTP server server.Start() log.Println("HTTP server listening on :8080") diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index ddfb019..1678e33 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -2,6 +2,7 @@ package router import ( "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/auth/authApi" "github.com/krack8/lighthouse/pkg/auth/controllers" middleware "github.com/krack8/lighthouse/pkg/auth/middlewares" "github.com/krack8/lighthouse/pkg/controller/api" @@ -25,213 +26,253 @@ func AddApiRoutes(httpRg *gin.RouterGroup) { apiGroup := httpRg.Group("/api/v1", middleware.AuthMiddleware()) // User routes - apiGroup.POST("/users", userController.CreateUserHandler) - apiGroup.GET("/users", userController.GetAllUsersHandler) - apiGroup.GET("/users/:id", userController.GetUserHandler) - apiGroup.PUT("/users/:id", userController.UpdateUserHandler) - apiGroup.DELETE("/users/:id", userController.DeleteUserHandler) + apiGroup.POST("/users", authApi.UserController.CreateUserHandler) + apiGroup.GET("/users", authApi.UserController.GetAllUsersHandler) + apiGroup.GET("/users/:id", authApi.UserController.GetUserHandler) + apiGroup.PUT("/users/:id", authApi.UserController.UpdateUserHandler) + apiGroup.DELETE("/users/:id", authApi.UserController.DeleteUserHandler) // RBAC routes - apiGroup.POST("/rbac/permissions", rbacController.CreatePermissionHandler) - apiGroup.POST("/rbac/roles", rbacController.CreateRoleHandler) - apiGroup.POST("/rbac/assign-roles", rbacController.AssignRolesHandler) + apiGroup.POST("/rbac/permissions", authApi.RbacController.CreatePermissionHandler) + apiGroup.POST("/rbac/roles", authApi.RbacController.CreateRoleHandler) + apiGroup.POST("/rbac/assign-roles", authApi.RbacController.AssignRolesHandler) // Namespace - httpRg.GET("api/v1/namespace", api.NamespaceController().GetNamespaceList) - httpRg.GET("api/v1/namespace/names", api.NamespaceController().GetNamespaceNameList) - httpRg.GET("api/v1/namespace/:name", api.NamespaceController().GetNamespaceDetails) - httpRg.POST("api/v1/namespace", api.NamespaceController().DeployNamespace) - httpRg.DELETE("api/v1/namespace/:name", api.NamespaceController().DeleteNamespace) + apiGroup.GET("api/v1/namespace", api.NamespaceController().GetNamespaceList) + apiGroup.GET("api/v1/namespace/names", api.NamespaceController().GetNamespaceNameList) + apiGroup.GET("api/v1/namespace/:name", api.NamespaceController().GetNamespaceDetails) + apiGroup.POST("api/v1/namespace", api.NamespaceController().DeployNamespace) + apiGroup.DELETE("api/v1/namespace/:name", api.NamespaceController().DeleteNamespace) + // Certificate - httpRg.GET("api/v1/certificate", api.CertificateController().GetCertificateList) - httpRg.GET("api/v1/certificate/:name", api.CertificateController().GetCertificateDetails) - httpRg.POST("api/v1/certificate", api.CertificateController().DeployCertificate) - httpRg.DELETE("api/v1/certificate/:name", api.CertificateController().DeleteCertificate) + apiGroup.GET("api/v1/certificate", api.CertificateController().GetCertificateList) + apiGroup.GET("api/v1/certificate/:name", api.CertificateController().GetCertificateDetails) + apiGroup.POST("api/v1/certificate", api.CertificateController().DeployCertificate) + apiGroup.DELETE("api/v1/certificate/:name", api.CertificateController().DeleteCertificate) + // Config Map - httpRg.GET("api/v1/config-map", api.ConfigMapController().GetConfigMapList) - httpRg.GET("api/v1/config-map/:name", api.ConfigMapController().GetConfigMapDetails) - httpRg.POST("api/v1/config-map", api.ConfigMapController().DeployConfigMap) - httpRg.DELETE("api/v1/config-map/:name", api.ConfigMapController().DeleteConfigMap) + apiGroup.GET("api/v1/config-map", api.ConfigMapController().GetConfigMapList) + apiGroup.GET("api/v1/config-map/:name", api.ConfigMapController().GetConfigMapDetails) + apiGroup.POST("api/v1/config-map", api.ConfigMapController().DeployConfigMap) + apiGroup.DELETE("api/v1/config-map/:name", api.ConfigMapController().DeleteConfigMap) + // ClusterRole - httpRg.GET("api/v1/cluster-role", api.ClusterRoleController().GetClusterRoleList) - httpRg.GET("api/v1/cluster-role/:name", api.ClusterRoleController().GetClusterRoleDetails) - httpRg.POST("api/v1/cluster-role", api.ClusterRoleController().DeployClusterRole) - httpRg.DELETE("api/v1/cluster-role/:name", api.ClusterRoleController().DeleteClusterRole) + apiGroup.GET("api/v1/cluster-role", api.ClusterRoleController().GetClusterRoleList) + apiGroup.GET("api/v1/cluster-role/:name", api.ClusterRoleController().GetClusterRoleDetails) + apiGroup.POST("api/v1/cluster-role", api.ClusterRoleController().DeployClusterRole) + apiGroup.DELETE("api/v1/cluster-role/:name", api.ClusterRoleController().DeleteClusterRole) + // ClusterRoleBinding - httpRg.GET("api/v1/cluster-role-binding", api.ClusterRoleBindingController().GetClusterRoleBindingList) - httpRg.GET("api/v1/cluster-role-binding/:name", api.ClusterRoleBindingController().GetClusterRoleBindingDetails) - httpRg.POST("api/v1/cluster-role-binding", api.ClusterRoleBindingController().DeployClusterRoleBinding) - httpRg.DELETE("api/v1/cluster-role-binding/:name", api.ClusterRoleBindingController().DeleteClusterRoleBinding) + apiGroup.GET("api/v1/cluster-role-binding", api.ClusterRoleBindingController().GetClusterRoleBindingList) + apiGroup.GET("api/v1/cluster-role-binding/:name", api.ClusterRoleBindingController().GetClusterRoleBindingDetails) + apiGroup.POST("api/v1/cluster-role-binding", api.ClusterRoleBindingController().DeployClusterRoleBinding) + apiGroup.DELETE("api/v1/cluster-role-binding/:name", api.ClusterRoleBindingController().DeleteClusterRoleBinding) + // ControllerRevision - httpRg.GET("api/v1/controller-revision", api.ControllerRevisionController().GetControllerRevisionList) - httpRg.GET("api/v1/controller-revision/:name", api.ControllerRevisionController().GetControllerRevisionDetails) - httpRg.POST("api/v1/controller-revision", api.ControllerRevisionController().DeployControllerRevision) - httpRg.DELETE("api/v1/controller-revision/:name", api.ControllerRevisionController().DeleteControllerRevision) + apiGroup.GET("api/v1/controller-revision", api.ControllerRevisionController().GetControllerRevisionList) + apiGroup.GET("api/v1/controller-revision/:name", api.ControllerRevisionController().GetControllerRevisionDetails) + apiGroup.POST("api/v1/controller-revision", api.ControllerRevisionController().DeployControllerRevision) + apiGroup.DELETE("api/v1/controller-revision/:name", api.ControllerRevisionController().DeleteControllerRevision) + // CRD - httpRg.GET("api/v1/crd", api.CrdController().GetCrdList) - httpRg.GET("api/v1/crd/:name", api.CrdController().GetCrdDetails) - httpRg.POST("api/v1/crd", api.CrdController().DeployCrd) - httpRg.DELETE("api/v1/crd/:name", api.CrdController().DeleteCrd) + apiGroup.GET("api/v1/crd", api.CrdController().GetCrdList) + apiGroup.GET("api/v1/crd/:name", api.CrdController().GetCrdDetails) + apiGroup.POST("api/v1/crd", api.CrdController().DeployCrd) + apiGroup.DELETE("api/v1/crd/:name", api.CrdController().DeleteCrd) + // Custom Resource - httpRg.GET("api/v1/custom-resource", api.CustomResourceController().GetCustomResourceList) - httpRg.GET("api/v1/custom-resource/:name", api.CustomResourceController().GetCustomResourceDetails) - httpRg.POST("api/v1/custom-resource", api.CustomResourceController().DeployCustomResource) - httpRg.DELETE("api/v1/custom-resource/:name", api.CustomResourceController().DeleteCustomResource) + apiGroup.GET("api/v1/custom-resource", api.CustomResourceController().GetCustomResourceList) + apiGroup.GET("api/v1/custom-resource/:name", api.CustomResourceController().GetCustomResourceDetails) + apiGroup.POST("api/v1/custom-resource", api.CustomResourceController().DeployCustomResource) + apiGroup.DELETE("api/v1/custom-resource/:name", api.CustomResourceController().DeleteCustomResource) + //Cronjob - httpRg.GET("api/v1/cronjob", api.CronJobController().GetCronJobList) - httpRg.GET("api/v1/cronjob/:name", api.CronJobController().GetCronJobDetails) - httpRg.POST("api/v1/cronjob", api.CronJobController().DeployCronJob) - httpRg.DELETE("api/v1/cronjob/:name", api.CronJobController().DeleteCronJob) + apiGroup.GET("api/v1/cronjob", api.CronJobController().GetCronJobList) + apiGroup.GET("api/v1/cronjob/:name", api.CronJobController().GetCronJobDetails) + apiGroup.POST("api/v1/cronjob", api.CronJobController().DeployCronJob) + apiGroup.DELETE("api/v1/cronjob/:name", api.CronJobController().DeleteCronJob) + // Daemonset - httpRg.GET("api/v1/daemonset", api.DaemonSetController().GetDaemonSetList) - httpRg.GET("api/v1/daemonset/:name", api.DaemonSetController().GetDaemonSetDetails) - httpRg.POST("api/v1/daemonset", api.DaemonSetController().DeployDaemonSet) - httpRg.DELETE("api/v1/daemonset/:name", api.DaemonSetController().DeleteDaemonSet) - httpRg.GET("api/v1/daemonset/stats", api.DaemonSetController().GetDaemonSetStats) + apiGroup.GET("api/v1/daemonset", api.DaemonSetController().GetDaemonSetList) + apiGroup.GET("api/v1/daemonset/:name", api.DaemonSetController().GetDaemonSetDetails) + apiGroup.POST("api/v1/daemonset", api.DaemonSetController().DeployDaemonSet) + apiGroup.DELETE("api/v1/daemonset/:name", api.DaemonSetController().DeleteDaemonSet) + apiGroup.GET("api/v1/daemonset/stats", api.DaemonSetController().GetDaemonSetStats) + // Deployment - httpRg.GET("api/v1/deployment", api.DeploymentController().GetDeploymentList) - httpRg.GET("api/v1/deployment/:name", api.DeploymentController().GetDeploymentDetails) - httpRg.POST("api/v1/deployment", api.DeploymentController().DeployDeployment) - httpRg.DELETE("api/v1/deployment/:name", api.DeploymentController().DeleteDeployment) - httpRg.GET("api/v1/deployment/stats", api.DeploymentController().GetDeploymentStats) - httpRg.GET("api/v1/deployment/:name/pods", api.DeploymentController().GetDeploymentPodList) + apiGroup.GET("api/v1/deployment", api.DeploymentController().GetDeploymentList) + apiGroup.GET("api/v1/deployment/:name", api.DeploymentController().GetDeploymentDetails) + apiGroup.POST("api/v1/deployment", api.DeploymentController().DeployDeployment) + apiGroup.DELETE("api/v1/deployment/:name", api.DeploymentController().DeleteDeployment) + apiGroup.GET("api/v1/deployment/stats", api.DeploymentController().GetDeploymentStats) + apiGroup.GET("api/v1/deployment/:name/pods", api.DeploymentController().GetDeploymentPodList) + // Endpoints - httpRg.GET("api/v1/endpoints", api.EndpointsController().GetEndpointsList) - httpRg.GET("api/v1/endpoints/:name", api.EndpointsController().GetEndpointsDetails) - httpRg.POST("api/v1/endpoints", api.EndpointsController().DeployEndpoints) - httpRg.DELETE("api/v1/endpoints/:name", api.EndpointsController().DeleteEndpoints) + apiGroup.GET("api/v1/endpoints", api.EndpointsController().GetEndpointsList) + apiGroup.GET("api/v1/endpoints/:name", api.EndpointsController().GetEndpointsDetails) + apiGroup.POST("api/v1/endpoints", api.EndpointsController().DeployEndpoints) + apiGroup.DELETE("api/v1/endpoints/:name", api.EndpointsController().DeleteEndpoints) + // EndpointSlice - httpRg.GET("api/v1/endpoint-slice", api.EndpointSliceController().GetEndpointSliceList) - httpRg.GET("api/v1/endpoint-slice/:name", api.EndpointSliceController().GetEndpointSliceDetails) - httpRg.POST("api/v1/endpoint-slice", api.EndpointSliceController().DeployEndpointSlice) - httpRg.DELETE("api/v1/endpoint-slice/:name", api.EndpointSliceController().DeleteEndpointSlice) + apiGroup.GET("api/v1/endpoint-slice", api.EndpointSliceController().GetEndpointSliceList) + apiGroup.GET("api/v1/endpoint-slice/:name", api.EndpointSliceController().GetEndpointSliceDetails) + apiGroup.POST("api/v1/endpoint-slice", api.EndpointSliceController().DeployEndpointSlice) + apiGroup.DELETE("api/v1/endpoint-slice/:name", api.EndpointSliceController().DeleteEndpointSlice) + // event - httpRg.GET("api/v1/event", api.EventController().GetEventList) - httpRg.GET("api/v1/event/:name", api.EventController().GetEventDetails) + apiGroup.GET("api/v1/event", api.EventController().GetEventList) + apiGroup.GET("api/v1/event/:name", api.EventController().GetEventDetails) + // HPA - httpRg.GET("api/v1/hpa", api.HpaController().GetHpaList) - httpRg.GET("api/v1/hpa/:name", api.HpaController().GetHpaDetails) + apiGroup.GET("api/v1/hpa", api.HpaController().GetHpaList) + apiGroup.GET("api/v1/hpa/:name", api.HpaController().GetHpaDetails) + // Ingress - httpRg.GET("api/v1/ingress", api.IngressController().GetIngressList) - httpRg.GET("api/v1/ingress/:name", api.IngressController().GetIngressDetails) - httpRg.POST("api/v1/ingress", api.IngressController().DeployIngress) - httpRg.DELETE("api/v1/ingress/:name", api.IngressController().DeleteIngress) + apiGroup.GET("api/v1/ingress", api.IngressController().GetIngressList) + apiGroup.GET("api/v1/ingress/:name", api.IngressController().GetIngressDetails) + apiGroup.POST("api/v1/ingress", api.IngressController().DeployIngress) + apiGroup.DELETE("api/v1/ingress/:name", api.IngressController().DeleteIngress) + // Istio Gateway - httpRg.GET("api/v1/gateway", api.IstioGatewayController().GetIstioGatewayList) - httpRg.GET("api/v1/gateway/:name", api.IstioGatewayController().GetIstioGatewayDetails) - httpRg.POST("api/v1/gateway", api.IstioGatewayController().DeployIstioGateway) - httpRg.DELETE("api/v1/gateway/:name", api.IstioGatewayController().DeleteIstioGateway) + apiGroup.GET("api/v1/gateway", api.IstioGatewayController().GetIstioGatewayList) + apiGroup.GET("api/v1/gateway/:name", api.IstioGatewayController().GetIstioGatewayDetails) + apiGroup.POST("api/v1/gateway", api.IstioGatewayController().DeployIstioGateway) + apiGroup.DELETE("api/v1/gateway/:name", api.IstioGatewayController().DeleteIstioGateway) + //Job - httpRg.GET("api/v1/job", api.JobController().GetJobList) - httpRg.GET("api/v1/job/:name", api.JobController().GetJobDetails) - httpRg.POST("api/v1/job", api.JobController().DeployJob) - httpRg.DELETE("api/v1/job/:name", api.JobController().DeleteJob) + apiGroup.GET("api/v1/job", api.JobController().GetJobList) + apiGroup.GET("api/v1/job/:name", api.JobController().GetJobDetails) + apiGroup.POST("api/v1/job", api.JobController().DeployJob) + apiGroup.DELETE("api/v1/job/:name", api.JobController().DeleteJob) + //Load Balancer - httpRg.GET("api/v1/load-balancer", api.LoadBalancerController().GetLoadBalancerList) - httpRg.GET("api/v1/load-balancer/:name", api.LoadBalancerController().GetLoadBalancerDetails) + apiGroup.GET("api/v1/load-balancer", api.LoadBalancerController().GetLoadBalancerList) + apiGroup.GET("api/v1/load-balancer/:name", api.LoadBalancerController().GetLoadBalancerDetails) + // Manifest - httpRg.POST("api/v1/manifest", api.ManifestController().DeployManifest) + apiGroup.POST("api/v1/manifest", api.ManifestController().DeployManifest) + // Network Policy - httpRg.GET("api/v1/network-policy", api.NetworkPolicyController().GetNetworkPolicyList) - httpRg.GET("api/v1/network-policy/:name", api.NetworkPolicyController().GetNetworkPolicyDetails) + apiGroup.GET("api/v1/network-policy", api.NetworkPolicyController().GetNetworkPolicyList) + apiGroup.GET("api/v1/network-policy/:name", api.NetworkPolicyController().GetNetworkPolicyDetails) + //Node - httpRg.GET("api/v1/node", api.NodeController().GetNodeList) - httpRg.GET("api/v1/node/:name", api.NodeController().GetNodeDetails) - httpRg.GET("api/v1/node/cordon/:name", api.NodeController().NodeCordon) - httpRg.POST("api/v1/node/taint/:name", api.NodeController().NodeTaint) - httpRg.POST("api/v1/node/untaint/:name", api.NodeController().NodeUnTaint) + apiGroup.GET("api/v1/node", api.NodeController().GetNodeList) + apiGroup.GET("api/v1/node/:name", api.NodeController().GetNodeDetails) + apiGroup.GET("api/v1/node/cordon/:name", api.NodeController().NodeCordon) + apiGroup.POST("api/v1/node/taint/:name", api.NodeController().NodeTaint) + apiGroup.POST("api/v1/node/untaint/:name", api.NodeController().NodeUnTaint) + // Pod - httpRg.GET("api/v1/pod", api.PodController().GetPodList) - httpRg.GET("api/v1/pod/:name", api.PodController().GetPodDetails) - httpRg.GET("api/v1/pod/logs/:name", api.PodController().GetPodLogs) - httpRg.POST("api/v1/pod", api.PodController().DeployPod) - httpRg.DELETE("api/v1/pod/:name", api.PodController().DeletePod) - httpRg.GET("api/v1/pod/stats", api.PodController().GetPodStats) + apiGroup.GET("api/v1/pod", api.PodController().GetPodList) + apiGroup.GET("api/v1/pod/:name", api.PodController().GetPodDetails) + apiGroup.GET("api/v1/pod/logs/:name", api.PodController().GetPodLogs) + apiGroup.POST("api/v1/pod", api.PodController().DeployPod) + apiGroup.DELETE("api/v1/pod/:name", api.PodController().DeletePod) + apiGroup.GET("api/v1/pod/stats", api.PodController().GetPodStats) + // PodDisruptionBudgets - httpRg.GET("api/v1/PDB", api.PodDisruptionBudgetsController().GetPodDisruptionBudgetsList) - httpRg.GET("api/v1/PDB/:name", api.PodDisruptionBudgetsController().GetPodDisruptionBudgetsDetails) - httpRg.POST("api/v1/PDB", api.PodDisruptionBudgetsController().DeployPodDisruptionBudgets) - httpRg.DELETE("api/v1/PDB/:name", api.PodDisruptionBudgetsController().DeletePodDisruptionBudgets) + apiGroup.GET("api/v1/PDB", api.PodDisruptionBudgetsController().GetPodDisruptionBudgetsList) + apiGroup.GET("api/v1/PDB/:name", api.PodDisruptionBudgetsController().GetPodDisruptionBudgetsDetails) + apiGroup.POST("api/v1/PDB", api.PodDisruptionBudgetsController().DeployPodDisruptionBudgets) + apiGroup.DELETE("api/v1/PDB/:name", api.PodDisruptionBudgetsController().DeletePodDisruptionBudgets) + // Pod Metrics - httpRg.GET("api/v1/pod-metrics", api.PodMetricsController().GetPodMetricsList) - httpRg.GET("api/v1/pod-metrics/:pod", api.PodMetricsController().GetPodMetricsDetails) + apiGroup.GET("api/v1/pod-metrics", api.PodMetricsController().GetPodMetricsList) + apiGroup.GET("api/v1/pod-metrics/:pod", api.PodMetricsController().GetPodMetricsDetails) + // PV - httpRg.GET("api/v1/pv", api.PvController().GetPvList) - httpRg.GET("api/v1/pv/:name", api.PvController().GetPvDetails) - httpRg.POST("api/v1/pv", api.PvController().DeployPv) - httpRg.DELETE("api/v1/pv/:name", api.PvController().DeletePv) + apiGroup.GET("api/v1/pv", api.PvController().GetPvList) + apiGroup.GET("api/v1/pv/:name", api.PvController().GetPvDetails) + apiGroup.POST("api/v1/pv", api.PvController().DeployPv) + apiGroup.DELETE("api/v1/pv/:name", api.PvController().DeletePv) + // Persistent Volume Claim - httpRg.GET("api/v1/pvc", api.PvcController().GetPvcList) - httpRg.GET("api/v1/pvc/:name", api.PvcController().GetPvcDetails) - httpRg.POST("api/v1/pvc", api.PvcController().DeployPvc) - httpRg.DELETE("api/v1/pvc/:name", api.PvcController().DeletePvc) + apiGroup.GET("api/v1/pvc", api.PvcController().GetPvcList) + apiGroup.GET("api/v1/pvc/:name", api.PvcController().GetPvcDetails) + apiGroup.POST("api/v1/pvc", api.PvcController().DeployPvc) + apiGroup.DELETE("api/v1/pvc/:name", api.PvcController().DeletePvc) + // ReplicaSet - httpRg.GET("api/v1/replicaset", api.ReplicaSetController().GetReplicaSetList) - httpRg.GET("api/v1/replicaset/:name", api.ReplicaSetController().GetReplicaSetDetails) - httpRg.GET("api/v1/replicaset/stats", api.ReplicaSetController().GetReplicaSetStats) - httpRg.POST("api/v1/replicaset", api.ReplicaSetController().DeployReplicaSet) - httpRg.DELETE("api/v1/replicaset/:name", api.ReplicaSetController().DeleteReplicaSet) + apiGroup.GET("api/v1/replicaset", api.ReplicaSetController().GetReplicaSetList) + apiGroup.GET("api/v1/replicaset/:name", api.ReplicaSetController().GetReplicaSetDetails) + apiGroup.GET("api/v1/replicaset/stats", api.ReplicaSetController().GetReplicaSetStats) + apiGroup.POST("api/v1/replicaset", api.ReplicaSetController().DeployReplicaSet) + apiGroup.DELETE("api/v1/replicaset/:name", api.ReplicaSetController().DeleteReplicaSet) + // ReplicationController - httpRg.GET("api/v1/replication-controller", api.ReplicationControllerController().GetReplicationControllerList) - httpRg.GET("api/v1/replication-controller/:name", api.ReplicationControllerController().GetReplicationControllerDetails) - httpRg.POST("api/v1/replication-controller", api.ReplicationControllerController().DeployReplicationController) - httpRg.DELETE("api/v1/replication-controller/:name", api.ReplicationControllerController().DeleteReplicationController) + apiGroup.GET("api/v1/replication-controller", api.ReplicationControllerController().GetReplicationControllerList) + apiGroup.GET("api/v1/replication-controller/:name", api.ReplicationControllerController().GetReplicationControllerDetails) + apiGroup.POST("api/v1/replication-controller", api.ReplicationControllerController().DeployReplicationController) + apiGroup.DELETE("api/v1/replication-controller/:name", api.ReplicationControllerController().DeleteReplicationController) + // Resource Quota - httpRg.GET("api/v1/resource-quota", api.ResourceQuotaController().GetResourceQuotaList) - httpRg.GET("api/v1/resource-quota/:name", api.ResourceQuotaController().GetResourceQuotaDetails) - httpRg.POST("api/v1/resource-quota", api.ResourceQuotaController().DeployResourceQuota) - httpRg.DELETE("api/v1/resource-quota/:name", api.ResourceQuotaController().DeleteResourceQuota) + apiGroup.GET("api/v1/resource-quota", api.ResourceQuotaController().GetResourceQuotaList) + apiGroup.GET("api/v1/resource-quota/:name", api.ResourceQuotaController().GetResourceQuotaDetails) + apiGroup.POST("api/v1/resource-quota", api.ResourceQuotaController().DeployResourceQuota) + apiGroup.DELETE("api/v1/resource-quota/:name", api.ResourceQuotaController().DeleteResourceQuota) + // Role - httpRg.GET("api/v1/role", api.RoleController().GetRoleList) - httpRg.GET("api/v1/role/:name", api.RoleController().GetRoleDetails) - httpRg.POST("api/v1/role", api.RoleController().DeployRole) - httpRg.DELETE("api/v1/role/:name", api.RoleController().DeleteRole) + apiGroup.GET("api/v1/role", api.RoleController().GetRoleList) + apiGroup.GET("api/v1/role/:name", api.RoleController().GetRoleDetails) + apiGroup.POST("api/v1/role", api.RoleController().DeployRole) + apiGroup.DELETE("api/v1/role/:name", api.RoleController().DeleteRole) + // RoleBinding - httpRg.GET("api/v1/role-binding", api.RoleBindingController().GetRoleBindingList) - httpRg.GET("api/v1/role-binding/:name", api.RoleBindingController().GetRoleBindingDetails) - httpRg.POST("api/v1/role-binding", api.RoleBindingController().DeployRoleBinding) - httpRg.DELETE("api/v1/role-binding/:name", api.RoleBindingController().DeleteRoleBinding) + apiGroup.GET("api/v1/role-binding", api.RoleBindingController().GetRoleBindingList) + apiGroup.GET("api/v1/role-binding/:name", api.RoleBindingController().GetRoleBindingDetails) + apiGroup.POST("api/v1/role-binding", api.RoleBindingController().DeployRoleBinding) + apiGroup.DELETE("api/v1/role-binding/:name", api.RoleBindingController().DeleteRoleBinding) + // Service Account - httpRg.GET("api/v1/service-account", api.ServiceAccountController().GetServiceAccountList) - httpRg.GET("api/v1/service-account/:name", api.ServiceAccountController().GetServiceAccountDetails) - httpRg.POST("api/v1/service-account", api.ServiceAccountController().DeployServiceAccount) - httpRg.DELETE("api/v1/service-account/:name", api.ServiceAccountController().DeleteServiceAccount) + apiGroup.GET("api/v1/service-account", api.ServiceAccountController().GetServiceAccountList) + apiGroup.GET("api/v1/service-account/:name", api.ServiceAccountController().GetServiceAccountDetails) + apiGroup.POST("api/v1/service-account", api.ServiceAccountController().DeployServiceAccount) + apiGroup.DELETE("api/v1/service-account/:name", api.ServiceAccountController().DeleteServiceAccount) + // Secret - httpRg.GET("api/v1/secret", api.SecretController().GetSecretList) - httpRg.GET("api/v1/secret/:name", api.SecretController().GetSecretDetails) - httpRg.POST("api/v1/secret", api.SecretController().DeploySecret) - httpRg.DELETE("api/v1/secret/:name", api.SecretController().DeleteSecret) + apiGroup.GET("api/v1/secret", api.SecretController().GetSecretList) + apiGroup.GET("api/v1/secret/:name", api.SecretController().GetSecretDetails) + apiGroup.POST("api/v1/secret", api.SecretController().DeploySecret) + apiGroup.DELETE("api/v1/secret/:name", api.SecretController().DeleteSecret) + // StatefulSet - httpRg.GET("api/v1/statefulset", api.StatefulSetController().GetStatefulSetList) - httpRg.GET("api/v1/statefulset/:name", api.StatefulSetController().GetStatefulSetDetails) - httpRg.POST("api/v1/statefulset", api.StatefulSetController().DeployStatefulSet) - httpRg.DELETE("api/v1/statefulset/:name", api.StatefulSetController().DeleteStatefulSet) - httpRg.GET("api/v1/statefulset/stats", api.StatefulSetController().GetStatefulSetStats) - httpRg.GET("api/v1/statefulset/:name/pods", api.StatefulSetController().GetStatefulSetPodList) + apiGroup.GET("api/v1/statefulset", api.StatefulSetController().GetStatefulSetList) + apiGroup.GET("api/v1/statefulset/:name", api.StatefulSetController().GetStatefulSetDetails) + apiGroup.POST("api/v1/statefulset", api.StatefulSetController().DeployStatefulSet) + apiGroup.DELETE("api/v1/statefulset/:name", api.StatefulSetController().DeleteStatefulSet) + apiGroup.GET("api/v1/statefulset/stats", api.StatefulSetController().GetStatefulSetStats) + apiGroup.GET("api/v1/statefulset/:name/pods", api.StatefulSetController().GetStatefulSetPodList) + // Storage class - httpRg.GET("api/v1/storage-class", api.StorageClassController().GetStorageClassList) - httpRg.GET("api/v1/storage-class/:name", api.StorageClassController().GetStorageClassDetails) - httpRg.POST("api/v1/storage-class", api.StorageClassController().DeployStorageClass) - httpRg.DELETE("api/v1/storage-class/:name", api.StorageClassController().DeleteStorageClass) + apiGroup.GET("api/v1/storage-class", api.StorageClassController().GetStorageClassList) + apiGroup.GET("api/v1/storage-class/:name", api.StorageClassController().GetStorageClassDetails) + apiGroup.POST("api/v1/storage-class", api.StorageClassController().DeployStorageClass) + apiGroup.DELETE("api/v1/storage-class/:name", api.StorageClassController().DeleteStorageClass) + // Service - httpRg.GET("api/v1/service", api.SvcController().GetSvcList) - httpRg.GET("api/v1/service/:name", api.SvcController().GetSvcDetails) - httpRg.POST("api/v1/service", api.SvcController().DeploySVC) - httpRg.DELETE("api/v1/service/:name", api.SvcController().DeleteSvc) + apiGroup.GET("api/v1/service", api.SvcController().GetSvcList) + apiGroup.GET("api/v1/service/:name", api.SvcController().GetSvcDetails) + apiGroup.POST("api/v1/service", api.SvcController().DeploySVC) + apiGroup.DELETE("api/v1/service/:name", api.SvcController().DeleteSvc) + // Virtual Service - httpRg.GET("api/v1/virtual-service", api.VirtualServiceController().GetVirtualServiceList) - httpRg.GET("api/v1/virtual-service/:name", api.VirtualServiceController().GetVirtualServiceDetails) - httpRg.POST("api/v1/virtual-service", api.VirtualServiceController().DeployVirtualService) - httpRg.DELETE("api/v1/virtual-service/:name", api.VirtualServiceController().DeleteVirtualService) + apiGroup.GET("api/v1/virtual-service", api.VirtualServiceController().GetVirtualServiceList) + apiGroup.GET("api/v1/virtual-service/:name", api.VirtualServiceController().GetVirtualServiceDetails) + apiGroup.POST("api/v1/virtual-service", api.VirtualServiceController().DeployVirtualService) + apiGroup.DELETE("api/v1/virtual-service/:name", api.VirtualServiceController().DeleteVirtualService) + // Volume Snapshot - httpRg.GET("api/v1/volume-snapshot", api.VolumeSnapshotController().GetVolumeSnapshotList) - httpRg.GET("api/v1/volume-snapshot/:name", api.VolumeSnapshotController().GetVolumeSnapshotDetails) - httpRg.POST("api/v1/volume-snapshot", api.VolumeSnapshotController().DeployVolumeSnapshot) - httpRg.DELETE("api/v1/volume-snapshot/:name", api.VolumeSnapshotController().DeleteVolumeSnapshot) + apiGroup.GET("api/v1/volume-snapshot", api.VolumeSnapshotController().GetVolumeSnapshotList) + apiGroup.GET("api/v1/volume-snapshot/:name", api.VolumeSnapshotController().GetVolumeSnapshotDetails) + apiGroup.POST("api/v1/volume-snapshot", api.VolumeSnapshotController().DeployVolumeSnapshot) + apiGroup.DELETE("api/v1/volume-snapshot/:name", api.VolumeSnapshotController().DeleteVolumeSnapshot) + // Volume Snapshot Content - httpRg.GET("api/v1/volume-snapshot-content", api.VolumeSnapshotContentController().GetVolumeSnapshotContentList) - httpRg.GET("api/v1/volume-snapshot-content/:name", api.VolumeSnapshotContentController().GetVolumeSnapshotContentDetails) + apiGroup.GET("api/v1/volume-snapshot-content", api.VolumeSnapshotContentController().GetVolumeSnapshotContentList) + apiGroup.GET("api/v1/volume-snapshot-content/:name", api.VolumeSnapshotContentController().GetVolumeSnapshotContentDetails) + // Volume Snapshot Class - httpRg.GET("api/v1/volume-snapshot-class", api.VolumeSnapshotClassController().GetVolumeSnapshotClassList) - httpRg.GET("api/v1/volume-snapshot-class/:name", api.VolumeSnapshotClassController().GetVolumeSnapshotClassDetails) + apiGroup.GET("api/v1/volume-snapshot-class", api.VolumeSnapshotClassController().GetVolumeSnapshotClassList) + apiGroup.GET("api/v1/volume-snapshot-class/:name", api.VolumeSnapshotClassController().GetVolumeSnapshotClassDetails) } diff --git a/pkg/server/server.go b/pkg/server/server.go index cf7ff49..38db60c 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -21,22 +21,7 @@ func Start() { r.Use(cors.New(corsConfig), gin.LoggerWithWriter(gin.DefaultWriter, "/health", "/swagger/*any")) // Setting API Base Path for HTTP APIs httpRouter := r.Group("/") - //r.GET("/ws/v1/pod/logs/:name", v1.PodController().GetPodStreamLogs) - // Setting up all Http Routes - /*// Initialize services and controllers - userService := &services.UserService{} // Ensure it is properly initialized - userController := &controllers.UserController{UserService: userService} - - rbacService := &services.RbacService{} // Ensure it is properly initialized - rbacController := &controllers.RbacController{RbacService: rbacService} - - // Initialize routes from various route files - routes.InitPermissionRoutes(rbacController, router) // permission-related routes - routes.InitRoleRoutes(rbacController, router) // role-related routes - - routes.InitAuthRoutes(router) // Auth-related routes - routes.InitUserRoutes(userController, router) // user-related routes*/ // Get the application port from the environment port := os.Getenv("PORT") if port == "" { From a655c4579b90baab0e58032efdab647c71d18e49 Mon Sep 17 00:00:00 2001 From: Toha Date: Wed, 29 Jan 2025 15:37:25 +0600 Subject: [PATCH 22/64] namespace list error return --- pkg/controller/api/namespace.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/controller/api/namespace.go b/pkg/controller/api/namespace.go index 95fdcc8..b3df4d3 100644 --- a/pkg/controller/api/namespace.go +++ b/pkg/controller/api/namespace.go @@ -67,6 +67,7 @@ func (ctrl *namespaceController) GetNamespaceList(ctx *gin.Context) { res, err := worker.TaskToAgent().SendToWorker(ctx, taskName, inputTask) if err != nil { k8s.SendErrorResponse(ctx, err.Error()) + return } err = json.Unmarshal([]byte(res.Output), &result) if err != nil { From 58120607c9f4d43da0f765eef697e7ae3c5bb2e6 Mon Sep 17 00:00:00 2001 From: Toha Date: Wed, 29 Jan 2025 17:06:24 +0600 Subject: [PATCH 23/64] changes routes and noauth --- pkg/.env | 4 +- pkg/config/config.go | 25 +++ pkg/controller/main.go | 2 + pkg/server/router/routes.go | 341 +++++++++++++++++------------------- pkg/server/server.go | 45 ++++- 5 files changed, 236 insertions(+), 181 deletions(-) diff --git a/pkg/.env b/pkg/.env index 9311aa7..1e29349 100644 --- a/pkg/.env +++ b/pkg/.env @@ -11,4 +11,6 @@ JWT_REFRESH_SECRET=your_refresh_jwt_secret_key # Token Expiry Configuration ACCESS_TOKEN_EXPIRY=15m -REFRESH_TOKEN_EXPIRY=24h \ No newline at end of file +REFRESH_TOKEN_EXPIRY=24h + +NO_AUTH="FALSE" \ No newline at end of file diff --git a/pkg/config/config.go b/pkg/config/config.go index b0ff1ad..0b090e3 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -1,10 +1,35 @@ package config +import ( + "github.com/joho/godotenv" + "github.com/krack8/lighthouse/pkg/log" + "os" +) + var ServerPort = "8080" var PageLimit = int64(10) var isK8 = false var KubeConfigFile = "dev-config.yaml" +var NoAuth = false func IsK8() bool { return isK8 } + +func InitEnvironmentVariables() { + err := godotenv.Load("../.env") + if err != nil { + log.Logger.Errorw("Failed to Load environment file", "err", err.Error()) + os.Exit(1) + } + if os.Getenv("NO_AUTH") == "TRUE" { + NoAuth = true + log.Logger.Infow("Started with NO AUTH enabled", "[NO-AUTH]", NoAuth) + } else { + log.Logger.Infow("Started with NO AUTH disabled", "[NO-AUTH]", NoAuth) + } +} + +func IsNoAuth() bool { + return NoAuth +} diff --git a/pkg/controller/main.go b/pkg/controller/main.go index eb625c4..b6afd6e 100644 --- a/pkg/controller/main.go +++ b/pkg/controller/main.go @@ -4,6 +4,7 @@ import ( "github.com/joho/godotenv" "github.com/krack8/lighthouse/pkg/auth/authApi" "github.com/krack8/lighthouse/pkg/auth/config" + cfg "github.com/krack8/lighthouse/pkg/config" "github.com/krack8/lighthouse/pkg/controller/worker" _log "github.com/krack8/lighthouse/pkg/log" "github.com/krack8/lighthouse/pkg/server" @@ -14,6 +15,7 @@ import ( func main() { _log.InitializeLogger() worker.StartGrpcServer() + cfg.InitEnvironmentVariables() // Load environment variables from .env file if err := godotenv.Load("../.env"); err != nil { diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index 1678e33..cb1f8c0 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -4,7 +4,6 @@ import ( "github.com/gin-gonic/gin" "github.com/krack8/lighthouse/pkg/auth/authApi" "github.com/krack8/lighthouse/pkg/auth/controllers" - middleware "github.com/krack8/lighthouse/pkg/auth/middlewares" "github.com/krack8/lighthouse/pkg/controller/api" ) @@ -15,264 +14,254 @@ var rbacController *controllers.RbacController func AddApiRoutes(httpRg *gin.RouterGroup) { - // Define the login route separately without middleware - // Login route - httpRg.POST("/auth/login", controllers.LoginHandler) - - // Refresh token route - httpRg.POST("/auth/refresh-token", controllers.RefreshTokenHandler) - - // Apply the AuthMiddleware to the /api/v1 routes - apiGroup := httpRg.Group("/api/v1", middleware.AuthMiddleware()) - // User routes - apiGroup.POST("/users", authApi.UserController.CreateUserHandler) - apiGroup.GET("/users", authApi.UserController.GetAllUsersHandler) - apiGroup.GET("/users/:id", authApi.UserController.GetUserHandler) - apiGroup.PUT("/users/:id", authApi.UserController.UpdateUserHandler) - apiGroup.DELETE("/users/:id", authApi.UserController.DeleteUserHandler) + httpRg.POST("/users", authApi.UserController.CreateUserHandler) + httpRg.GET("/users", authApi.UserController.GetAllUsersHandler) + httpRg.GET("/users/:id", authApi.UserController.GetUserHandler) + httpRg.PUT("/users/:id", authApi.UserController.UpdateUserHandler) + httpRg.DELETE("/users/:id", authApi.UserController.DeleteUserHandler) // RBAC routes - apiGroup.POST("/rbac/permissions", authApi.RbacController.CreatePermissionHandler) - apiGroup.POST("/rbac/roles", authApi.RbacController.CreateRoleHandler) - apiGroup.POST("/rbac/assign-roles", authApi.RbacController.AssignRolesHandler) + httpRg.POST("/rbac/permissions", authApi.RbacController.CreatePermissionHandler) + httpRg.POST("/rbac/roles", authApi.RbacController.CreateRoleHandler) + httpRg.POST("/rbac/assign-roles", authApi.RbacController.AssignRolesHandler) // Namespace - apiGroup.GET("api/v1/namespace", api.NamespaceController().GetNamespaceList) - apiGroup.GET("api/v1/namespace/names", api.NamespaceController().GetNamespaceNameList) - apiGroup.GET("api/v1/namespace/:name", api.NamespaceController().GetNamespaceDetails) - apiGroup.POST("api/v1/namespace", api.NamespaceController().DeployNamespace) - apiGroup.DELETE("api/v1/namespace/:name", api.NamespaceController().DeleteNamespace) + httpRg.GET("/namespace", api.NamespaceController().GetNamespaceList) + httpRg.GET("/namespace/names", api.NamespaceController().GetNamespaceNameList) + httpRg.GET("/namespace/:name", api.NamespaceController().GetNamespaceDetails) + httpRg.POST("/namespace", api.NamespaceController().DeployNamespace) + httpRg.DELETE("/namespace/:name", api.NamespaceController().DeleteNamespace) // Certificate - apiGroup.GET("api/v1/certificate", api.CertificateController().GetCertificateList) - apiGroup.GET("api/v1/certificate/:name", api.CertificateController().GetCertificateDetails) - apiGroup.POST("api/v1/certificate", api.CertificateController().DeployCertificate) - apiGroup.DELETE("api/v1/certificate/:name", api.CertificateController().DeleteCertificate) + httpRg.GET("/certificate", api.CertificateController().GetCertificateList) + httpRg.GET("/certificate/:name", api.CertificateController().GetCertificateDetails) + httpRg.POST("/certificate", api.CertificateController().DeployCertificate) + httpRg.DELETE("/certificate/:name", api.CertificateController().DeleteCertificate) // Config Map - apiGroup.GET("api/v1/config-map", api.ConfigMapController().GetConfigMapList) - apiGroup.GET("api/v1/config-map/:name", api.ConfigMapController().GetConfigMapDetails) - apiGroup.POST("api/v1/config-map", api.ConfigMapController().DeployConfigMap) - apiGroup.DELETE("api/v1/config-map/:name", api.ConfigMapController().DeleteConfigMap) + httpRg.GET("/config-map", api.ConfigMapController().GetConfigMapList) + httpRg.GET("/config-map/:name", api.ConfigMapController().GetConfigMapDetails) + httpRg.POST("/config-map", api.ConfigMapController().DeployConfigMap) + httpRg.DELETE("/config-map/:name", api.ConfigMapController().DeleteConfigMap) // ClusterRole - apiGroup.GET("api/v1/cluster-role", api.ClusterRoleController().GetClusterRoleList) - apiGroup.GET("api/v1/cluster-role/:name", api.ClusterRoleController().GetClusterRoleDetails) - apiGroup.POST("api/v1/cluster-role", api.ClusterRoleController().DeployClusterRole) - apiGroup.DELETE("api/v1/cluster-role/:name", api.ClusterRoleController().DeleteClusterRole) + httpRg.GET("/cluster-role", api.ClusterRoleController().GetClusterRoleList) + httpRg.GET("/cluster-role/:name", api.ClusterRoleController().GetClusterRoleDetails) + httpRg.POST("/cluster-role", api.ClusterRoleController().DeployClusterRole) + httpRg.DELETE("/cluster-role/:name", api.ClusterRoleController().DeleteClusterRole) // ClusterRoleBinding - apiGroup.GET("api/v1/cluster-role-binding", api.ClusterRoleBindingController().GetClusterRoleBindingList) - apiGroup.GET("api/v1/cluster-role-binding/:name", api.ClusterRoleBindingController().GetClusterRoleBindingDetails) - apiGroup.POST("api/v1/cluster-role-binding", api.ClusterRoleBindingController().DeployClusterRoleBinding) - apiGroup.DELETE("api/v1/cluster-role-binding/:name", api.ClusterRoleBindingController().DeleteClusterRoleBinding) + httpRg.GET("/cluster-role-binding", api.ClusterRoleBindingController().GetClusterRoleBindingList) + httpRg.GET("/cluster-role-binding/:name", api.ClusterRoleBindingController().GetClusterRoleBindingDetails) + httpRg.POST("/cluster-role-binding", api.ClusterRoleBindingController().DeployClusterRoleBinding) + httpRg.DELETE("/cluster-role-binding/:name", api.ClusterRoleBindingController().DeleteClusterRoleBinding) // ControllerRevision - apiGroup.GET("api/v1/controller-revision", api.ControllerRevisionController().GetControllerRevisionList) - apiGroup.GET("api/v1/controller-revision/:name", api.ControllerRevisionController().GetControllerRevisionDetails) - apiGroup.POST("api/v1/controller-revision", api.ControllerRevisionController().DeployControllerRevision) - apiGroup.DELETE("api/v1/controller-revision/:name", api.ControllerRevisionController().DeleteControllerRevision) + httpRg.GET("/controller-revision", api.ControllerRevisionController().GetControllerRevisionList) + httpRg.GET("/controller-revision/:name", api.ControllerRevisionController().GetControllerRevisionDetails) + httpRg.POST("/controller-revision", api.ControllerRevisionController().DeployControllerRevision) + httpRg.DELETE("/controller-revision/:name", api.ControllerRevisionController().DeleteControllerRevision) // CRD - apiGroup.GET("api/v1/crd", api.CrdController().GetCrdList) - apiGroup.GET("api/v1/crd/:name", api.CrdController().GetCrdDetails) - apiGroup.POST("api/v1/crd", api.CrdController().DeployCrd) - apiGroup.DELETE("api/v1/crd/:name", api.CrdController().DeleteCrd) + httpRg.GET("/crd", api.CrdController().GetCrdList) + httpRg.GET("/crd/:name", api.CrdController().GetCrdDetails) + httpRg.POST("/crd", api.CrdController().DeployCrd) + httpRg.DELETE("/crd/:name", api.CrdController().DeleteCrd) // Custom Resource - apiGroup.GET("api/v1/custom-resource", api.CustomResourceController().GetCustomResourceList) - apiGroup.GET("api/v1/custom-resource/:name", api.CustomResourceController().GetCustomResourceDetails) - apiGroup.POST("api/v1/custom-resource", api.CustomResourceController().DeployCustomResource) - apiGroup.DELETE("api/v1/custom-resource/:name", api.CustomResourceController().DeleteCustomResource) + httpRg.GET("/custom-resource", api.CustomResourceController().GetCustomResourceList) + httpRg.GET("/custom-resource/:name", api.CustomResourceController().GetCustomResourceDetails) + httpRg.POST("/custom-resource", api.CustomResourceController().DeployCustomResource) + httpRg.DELETE("/custom-resource/:name", api.CustomResourceController().DeleteCustomResource) //Cronjob - apiGroup.GET("api/v1/cronjob", api.CronJobController().GetCronJobList) - apiGroup.GET("api/v1/cronjob/:name", api.CronJobController().GetCronJobDetails) - apiGroup.POST("api/v1/cronjob", api.CronJobController().DeployCronJob) - apiGroup.DELETE("api/v1/cronjob/:name", api.CronJobController().DeleteCronJob) + httpRg.GET("/cronjob", api.CronJobController().GetCronJobList) + httpRg.GET("/cronjob/:name", api.CronJobController().GetCronJobDetails) + httpRg.POST("/cronjob", api.CronJobController().DeployCronJob) + httpRg.DELETE("/cronjob/:name", api.CronJobController().DeleteCronJob) // Daemonset - apiGroup.GET("api/v1/daemonset", api.DaemonSetController().GetDaemonSetList) - apiGroup.GET("api/v1/daemonset/:name", api.DaemonSetController().GetDaemonSetDetails) - apiGroup.POST("api/v1/daemonset", api.DaemonSetController().DeployDaemonSet) - apiGroup.DELETE("api/v1/daemonset/:name", api.DaemonSetController().DeleteDaemonSet) - apiGroup.GET("api/v1/daemonset/stats", api.DaemonSetController().GetDaemonSetStats) + httpRg.GET("/daemonset", api.DaemonSetController().GetDaemonSetList) + httpRg.GET("/daemonset/:name", api.DaemonSetController().GetDaemonSetDetails) + httpRg.POST("/daemonset", api.DaemonSetController().DeployDaemonSet) + httpRg.DELETE("/daemonset/:name", api.DaemonSetController().DeleteDaemonSet) + httpRg.GET("/daemonset/stats", api.DaemonSetController().GetDaemonSetStats) // Deployment - apiGroup.GET("api/v1/deployment", api.DeploymentController().GetDeploymentList) - apiGroup.GET("api/v1/deployment/:name", api.DeploymentController().GetDeploymentDetails) - apiGroup.POST("api/v1/deployment", api.DeploymentController().DeployDeployment) - apiGroup.DELETE("api/v1/deployment/:name", api.DeploymentController().DeleteDeployment) - apiGroup.GET("api/v1/deployment/stats", api.DeploymentController().GetDeploymentStats) - apiGroup.GET("api/v1/deployment/:name/pods", api.DeploymentController().GetDeploymentPodList) + httpRg.GET("/deployment", api.DeploymentController().GetDeploymentList) + httpRg.GET("/deployment/:name", api.DeploymentController().GetDeploymentDetails) + httpRg.POST("/deployment", api.DeploymentController().DeployDeployment) + httpRg.DELETE("/deployment/:name", api.DeploymentController().DeleteDeployment) + httpRg.GET("/deployment/stats", api.DeploymentController().GetDeploymentStats) + httpRg.GET("/deployment/:name/pods", api.DeploymentController().GetDeploymentPodList) // Endpoints - apiGroup.GET("api/v1/endpoints", api.EndpointsController().GetEndpointsList) - apiGroup.GET("api/v1/endpoints/:name", api.EndpointsController().GetEndpointsDetails) - apiGroup.POST("api/v1/endpoints", api.EndpointsController().DeployEndpoints) - apiGroup.DELETE("api/v1/endpoints/:name", api.EndpointsController().DeleteEndpoints) + httpRg.GET("/endpoints", api.EndpointsController().GetEndpointsList) + httpRg.GET("/endpoints/:name", api.EndpointsController().GetEndpointsDetails) + httpRg.POST("/endpoints", api.EndpointsController().DeployEndpoints) + httpRg.DELETE("/endpoints/:name", api.EndpointsController().DeleteEndpoints) // EndpointSlice - apiGroup.GET("api/v1/endpoint-slice", api.EndpointSliceController().GetEndpointSliceList) - apiGroup.GET("api/v1/endpoint-slice/:name", api.EndpointSliceController().GetEndpointSliceDetails) - apiGroup.POST("api/v1/endpoint-slice", api.EndpointSliceController().DeployEndpointSlice) - apiGroup.DELETE("api/v1/endpoint-slice/:name", api.EndpointSliceController().DeleteEndpointSlice) + httpRg.GET("/endpoint-slice", api.EndpointSliceController().GetEndpointSliceList) + httpRg.GET("/endpoint-slice/:name", api.EndpointSliceController().GetEndpointSliceDetails) + httpRg.POST("/endpoint-slice", api.EndpointSliceController().DeployEndpointSlice) + httpRg.DELETE("/endpoint-slice/:name", api.EndpointSliceController().DeleteEndpointSlice) // event - apiGroup.GET("api/v1/event", api.EventController().GetEventList) - apiGroup.GET("api/v1/event/:name", api.EventController().GetEventDetails) + httpRg.GET("/event", api.EventController().GetEventList) + httpRg.GET("/event/:name", api.EventController().GetEventDetails) // HPA - apiGroup.GET("api/v1/hpa", api.HpaController().GetHpaList) - apiGroup.GET("api/v1/hpa/:name", api.HpaController().GetHpaDetails) + httpRg.GET("/hpa", api.HpaController().GetHpaList) + httpRg.GET("/hpa/:name", api.HpaController().GetHpaDetails) // Ingress - apiGroup.GET("api/v1/ingress", api.IngressController().GetIngressList) - apiGroup.GET("api/v1/ingress/:name", api.IngressController().GetIngressDetails) - apiGroup.POST("api/v1/ingress", api.IngressController().DeployIngress) - apiGroup.DELETE("api/v1/ingress/:name", api.IngressController().DeleteIngress) + httpRg.GET("/ingress", api.IngressController().GetIngressList) + httpRg.GET("/ingress/:name", api.IngressController().GetIngressDetails) + httpRg.POST("/ingress", api.IngressController().DeployIngress) + httpRg.DELETE("/ingress/:name", api.IngressController().DeleteIngress) // Istio Gateway - apiGroup.GET("api/v1/gateway", api.IstioGatewayController().GetIstioGatewayList) - apiGroup.GET("api/v1/gateway/:name", api.IstioGatewayController().GetIstioGatewayDetails) - apiGroup.POST("api/v1/gateway", api.IstioGatewayController().DeployIstioGateway) - apiGroup.DELETE("api/v1/gateway/:name", api.IstioGatewayController().DeleteIstioGateway) + httpRg.GET("/gateway", api.IstioGatewayController().GetIstioGatewayList) + httpRg.GET("/gateway/:name", api.IstioGatewayController().GetIstioGatewayDetails) + httpRg.POST("/gateway", api.IstioGatewayController().DeployIstioGateway) + httpRg.DELETE("/gateway/:name", api.IstioGatewayController().DeleteIstioGateway) //Job - apiGroup.GET("api/v1/job", api.JobController().GetJobList) - apiGroup.GET("api/v1/job/:name", api.JobController().GetJobDetails) - apiGroup.POST("api/v1/job", api.JobController().DeployJob) - apiGroup.DELETE("api/v1/job/:name", api.JobController().DeleteJob) + httpRg.GET("/job", api.JobController().GetJobList) + httpRg.GET("/job/:name", api.JobController().GetJobDetails) + httpRg.POST("/job", api.JobController().DeployJob) + httpRg.DELETE("/job/:name", api.JobController().DeleteJob) //Load Balancer - apiGroup.GET("api/v1/load-balancer", api.LoadBalancerController().GetLoadBalancerList) - apiGroup.GET("api/v1/load-balancer/:name", api.LoadBalancerController().GetLoadBalancerDetails) + httpRg.GET("/load-balancer", api.LoadBalancerController().GetLoadBalancerList) + httpRg.GET("/load-balancer/:name", api.LoadBalancerController().GetLoadBalancerDetails) // Manifest - apiGroup.POST("api/v1/manifest", api.ManifestController().DeployManifest) + httpRg.POST("/manifest", api.ManifestController().DeployManifest) // Network Policy - apiGroup.GET("api/v1/network-policy", api.NetworkPolicyController().GetNetworkPolicyList) - apiGroup.GET("api/v1/network-policy/:name", api.NetworkPolicyController().GetNetworkPolicyDetails) + httpRg.GET("/network-policy", api.NetworkPolicyController().GetNetworkPolicyList) + httpRg.GET("/network-policy/:name", api.NetworkPolicyController().GetNetworkPolicyDetails) //Node - apiGroup.GET("api/v1/node", api.NodeController().GetNodeList) - apiGroup.GET("api/v1/node/:name", api.NodeController().GetNodeDetails) - apiGroup.GET("api/v1/node/cordon/:name", api.NodeController().NodeCordon) - apiGroup.POST("api/v1/node/taint/:name", api.NodeController().NodeTaint) - apiGroup.POST("api/v1/node/untaint/:name", api.NodeController().NodeUnTaint) + httpRg.GET("/node", api.NodeController().GetNodeList) + httpRg.GET("/node/:name", api.NodeController().GetNodeDetails) + httpRg.GET("/node/cordon/:name", api.NodeController().NodeCordon) + httpRg.POST("/node/taint/:name", api.NodeController().NodeTaint) + httpRg.POST("/node/untaint/:name", api.NodeController().NodeUnTaint) // Pod - apiGroup.GET("api/v1/pod", api.PodController().GetPodList) - apiGroup.GET("api/v1/pod/:name", api.PodController().GetPodDetails) - apiGroup.GET("api/v1/pod/logs/:name", api.PodController().GetPodLogs) - apiGroup.POST("api/v1/pod", api.PodController().DeployPod) - apiGroup.DELETE("api/v1/pod/:name", api.PodController().DeletePod) - apiGroup.GET("api/v1/pod/stats", api.PodController().GetPodStats) + httpRg.GET("/pod", api.PodController().GetPodList) + httpRg.GET("/pod/:name", api.PodController().GetPodDetails) + httpRg.GET("/pod/logs/:name", api.PodController().GetPodLogs) + httpRg.POST("/pod", api.PodController().DeployPod) + httpRg.DELETE("/pod/:name", api.PodController().DeletePod) + httpRg.GET("/pod/stats", api.PodController().GetPodStats) // PodDisruptionBudgets - apiGroup.GET("api/v1/PDB", api.PodDisruptionBudgetsController().GetPodDisruptionBudgetsList) - apiGroup.GET("api/v1/PDB/:name", api.PodDisruptionBudgetsController().GetPodDisruptionBudgetsDetails) - apiGroup.POST("api/v1/PDB", api.PodDisruptionBudgetsController().DeployPodDisruptionBudgets) - apiGroup.DELETE("api/v1/PDB/:name", api.PodDisruptionBudgetsController().DeletePodDisruptionBudgets) + httpRg.GET("/PDB", api.PodDisruptionBudgetsController().GetPodDisruptionBudgetsList) + httpRg.GET("/PDB/:name", api.PodDisruptionBudgetsController().GetPodDisruptionBudgetsDetails) + httpRg.POST("/PDB", api.PodDisruptionBudgetsController().DeployPodDisruptionBudgets) + httpRg.DELETE("/PDB/:name", api.PodDisruptionBudgetsController().DeletePodDisruptionBudgets) // Pod Metrics - apiGroup.GET("api/v1/pod-metrics", api.PodMetricsController().GetPodMetricsList) - apiGroup.GET("api/v1/pod-metrics/:pod", api.PodMetricsController().GetPodMetricsDetails) + httpRg.GET("/pod-metrics", api.PodMetricsController().GetPodMetricsList) + httpRg.GET("/pod-metrics/:pod", api.PodMetricsController().GetPodMetricsDetails) // PV - apiGroup.GET("api/v1/pv", api.PvController().GetPvList) - apiGroup.GET("api/v1/pv/:name", api.PvController().GetPvDetails) - apiGroup.POST("api/v1/pv", api.PvController().DeployPv) - apiGroup.DELETE("api/v1/pv/:name", api.PvController().DeletePv) + httpRg.GET("/pv", api.PvController().GetPvList) + httpRg.GET("/pv/:name", api.PvController().GetPvDetails) + httpRg.POST("/pv", api.PvController().DeployPv) + httpRg.DELETE("/pv/:name", api.PvController().DeletePv) // Persistent Volume Claim - apiGroup.GET("api/v1/pvc", api.PvcController().GetPvcList) - apiGroup.GET("api/v1/pvc/:name", api.PvcController().GetPvcDetails) - apiGroup.POST("api/v1/pvc", api.PvcController().DeployPvc) - apiGroup.DELETE("api/v1/pvc/:name", api.PvcController().DeletePvc) + httpRg.GET("/pvc", api.PvcController().GetPvcList) + httpRg.GET("/pvc/:name", api.PvcController().GetPvcDetails) + httpRg.POST("/pvc", api.PvcController().DeployPvc) + httpRg.DELETE("/pvc/:name", api.PvcController().DeletePvc) // ReplicaSet - apiGroup.GET("api/v1/replicaset", api.ReplicaSetController().GetReplicaSetList) - apiGroup.GET("api/v1/replicaset/:name", api.ReplicaSetController().GetReplicaSetDetails) - apiGroup.GET("api/v1/replicaset/stats", api.ReplicaSetController().GetReplicaSetStats) - apiGroup.POST("api/v1/replicaset", api.ReplicaSetController().DeployReplicaSet) - apiGroup.DELETE("api/v1/replicaset/:name", api.ReplicaSetController().DeleteReplicaSet) + httpRg.GET("/replicaset", api.ReplicaSetController().GetReplicaSetList) + httpRg.GET("/replicaset/:name", api.ReplicaSetController().GetReplicaSetDetails) + httpRg.GET("/replicaset/stats", api.ReplicaSetController().GetReplicaSetStats) + httpRg.POST("/replicaset", api.ReplicaSetController().DeployReplicaSet) + httpRg.DELETE("/replicaset/:name", api.ReplicaSetController().DeleteReplicaSet) // ReplicationController - apiGroup.GET("api/v1/replication-controller", api.ReplicationControllerController().GetReplicationControllerList) - apiGroup.GET("api/v1/replication-controller/:name", api.ReplicationControllerController().GetReplicationControllerDetails) - apiGroup.POST("api/v1/replication-controller", api.ReplicationControllerController().DeployReplicationController) - apiGroup.DELETE("api/v1/replication-controller/:name", api.ReplicationControllerController().DeleteReplicationController) + httpRg.GET("/replication-controller", api.ReplicationControllerController().GetReplicationControllerList) + httpRg.GET("/replication-controller/:name", api.ReplicationControllerController().GetReplicationControllerDetails) + httpRg.POST("/replication-controller", api.ReplicationControllerController().DeployReplicationController) + httpRg.DELETE("/replication-controller/:name", api.ReplicationControllerController().DeleteReplicationController) // Resource Quota - apiGroup.GET("api/v1/resource-quota", api.ResourceQuotaController().GetResourceQuotaList) - apiGroup.GET("api/v1/resource-quota/:name", api.ResourceQuotaController().GetResourceQuotaDetails) - apiGroup.POST("api/v1/resource-quota", api.ResourceQuotaController().DeployResourceQuota) - apiGroup.DELETE("api/v1/resource-quota/:name", api.ResourceQuotaController().DeleteResourceQuota) + httpRg.GET("/resource-quota", api.ResourceQuotaController().GetResourceQuotaList) + httpRg.GET("/resource-quota/:name", api.ResourceQuotaController().GetResourceQuotaDetails) + httpRg.POST("/resource-quota", api.ResourceQuotaController().DeployResourceQuota) + httpRg.DELETE("/resource-quota/:name", api.ResourceQuotaController().DeleteResourceQuota) // Role - apiGroup.GET("api/v1/role", api.RoleController().GetRoleList) - apiGroup.GET("api/v1/role/:name", api.RoleController().GetRoleDetails) - apiGroup.POST("api/v1/role", api.RoleController().DeployRole) - apiGroup.DELETE("api/v1/role/:name", api.RoleController().DeleteRole) + httpRg.GET("/role", api.RoleController().GetRoleList) + httpRg.GET("/role/:name", api.RoleController().GetRoleDetails) + httpRg.POST("/role", api.RoleController().DeployRole) + httpRg.DELETE("/role/:name", api.RoleController().DeleteRole) // RoleBinding - apiGroup.GET("api/v1/role-binding", api.RoleBindingController().GetRoleBindingList) - apiGroup.GET("api/v1/role-binding/:name", api.RoleBindingController().GetRoleBindingDetails) - apiGroup.POST("api/v1/role-binding", api.RoleBindingController().DeployRoleBinding) - apiGroup.DELETE("api/v1/role-binding/:name", api.RoleBindingController().DeleteRoleBinding) + httpRg.GET("/role-binding", api.RoleBindingController().GetRoleBindingList) + httpRg.GET("/role-binding/:name", api.RoleBindingController().GetRoleBindingDetails) + httpRg.POST("/role-binding", api.RoleBindingController().DeployRoleBinding) + httpRg.DELETE("/role-binding/:name", api.RoleBindingController().DeleteRoleBinding) // Service Account - apiGroup.GET("api/v1/service-account", api.ServiceAccountController().GetServiceAccountList) - apiGroup.GET("api/v1/service-account/:name", api.ServiceAccountController().GetServiceAccountDetails) - apiGroup.POST("api/v1/service-account", api.ServiceAccountController().DeployServiceAccount) - apiGroup.DELETE("api/v1/service-account/:name", api.ServiceAccountController().DeleteServiceAccount) + httpRg.GET("/service-account", api.ServiceAccountController().GetServiceAccountList) + httpRg.GET("/service-account/:name", api.ServiceAccountController().GetServiceAccountDetails) + httpRg.POST("/service-account", api.ServiceAccountController().DeployServiceAccount) + httpRg.DELETE("/service-account/:name", api.ServiceAccountController().DeleteServiceAccount) // Secret - apiGroup.GET("api/v1/secret", api.SecretController().GetSecretList) - apiGroup.GET("api/v1/secret/:name", api.SecretController().GetSecretDetails) - apiGroup.POST("api/v1/secret", api.SecretController().DeploySecret) - apiGroup.DELETE("api/v1/secret/:name", api.SecretController().DeleteSecret) + httpRg.GET("/secret", api.SecretController().GetSecretList) + httpRg.GET("/secret/:name", api.SecretController().GetSecretDetails) + httpRg.POST("/secret", api.SecretController().DeploySecret) + httpRg.DELETE("/secret/:name", api.SecretController().DeleteSecret) // StatefulSet - apiGroup.GET("api/v1/statefulset", api.StatefulSetController().GetStatefulSetList) - apiGroup.GET("api/v1/statefulset/:name", api.StatefulSetController().GetStatefulSetDetails) - apiGroup.POST("api/v1/statefulset", api.StatefulSetController().DeployStatefulSet) - apiGroup.DELETE("api/v1/statefulset/:name", api.StatefulSetController().DeleteStatefulSet) - apiGroup.GET("api/v1/statefulset/stats", api.StatefulSetController().GetStatefulSetStats) - apiGroup.GET("api/v1/statefulset/:name/pods", api.StatefulSetController().GetStatefulSetPodList) + httpRg.GET("/statefulset", api.StatefulSetController().GetStatefulSetList) + httpRg.GET("/statefulset/:name", api.StatefulSetController().GetStatefulSetDetails) + httpRg.POST("/statefulset", api.StatefulSetController().DeployStatefulSet) + httpRg.DELETE("/statefulset/:name", api.StatefulSetController().DeleteStatefulSet) + httpRg.GET("/statefulset/stats", api.StatefulSetController().GetStatefulSetStats) + httpRg.GET("/statefulset/:name/pods", api.StatefulSetController().GetStatefulSetPodList) // Storage class - apiGroup.GET("api/v1/storage-class", api.StorageClassController().GetStorageClassList) - apiGroup.GET("api/v1/storage-class/:name", api.StorageClassController().GetStorageClassDetails) - apiGroup.POST("api/v1/storage-class", api.StorageClassController().DeployStorageClass) - apiGroup.DELETE("api/v1/storage-class/:name", api.StorageClassController().DeleteStorageClass) + httpRg.GET("/storage-class", api.StorageClassController().GetStorageClassList) + httpRg.GET("/storage-class/:name", api.StorageClassController().GetStorageClassDetails) + httpRg.POST("/storage-class", api.StorageClassController().DeployStorageClass) + httpRg.DELETE("/storage-class/:name", api.StorageClassController().DeleteStorageClass) // Service - apiGroup.GET("api/v1/service", api.SvcController().GetSvcList) - apiGroup.GET("api/v1/service/:name", api.SvcController().GetSvcDetails) - apiGroup.POST("api/v1/service", api.SvcController().DeploySVC) - apiGroup.DELETE("api/v1/service/:name", api.SvcController().DeleteSvc) + httpRg.GET("/service", api.SvcController().GetSvcList) + httpRg.GET("/service/:name", api.SvcController().GetSvcDetails) + httpRg.POST("/service", api.SvcController().DeploySVC) + httpRg.DELETE("/service/:name", api.SvcController().DeleteSvc) // Virtual Service - apiGroup.GET("api/v1/virtual-service", api.VirtualServiceController().GetVirtualServiceList) - apiGroup.GET("api/v1/virtual-service/:name", api.VirtualServiceController().GetVirtualServiceDetails) - apiGroup.POST("api/v1/virtual-service", api.VirtualServiceController().DeployVirtualService) - apiGroup.DELETE("api/v1/virtual-service/:name", api.VirtualServiceController().DeleteVirtualService) + httpRg.GET("/virtual-service", api.VirtualServiceController().GetVirtualServiceList) + httpRg.GET("/virtual-service/:name", api.VirtualServiceController().GetVirtualServiceDetails) + httpRg.POST("/virtual-service", api.VirtualServiceController().DeployVirtualService) + httpRg.DELETE("/virtual-service/:name", api.VirtualServiceController().DeleteVirtualService) // Volume Snapshot - apiGroup.GET("api/v1/volume-snapshot", api.VolumeSnapshotController().GetVolumeSnapshotList) - apiGroup.GET("api/v1/volume-snapshot/:name", api.VolumeSnapshotController().GetVolumeSnapshotDetails) - apiGroup.POST("api/v1/volume-snapshot", api.VolumeSnapshotController().DeployVolumeSnapshot) - apiGroup.DELETE("api/v1/volume-snapshot/:name", api.VolumeSnapshotController().DeleteVolumeSnapshot) + httpRg.GET("/volume-snapshot", api.VolumeSnapshotController().GetVolumeSnapshotList) + httpRg.GET("/volume-snapshot/:name", api.VolumeSnapshotController().GetVolumeSnapshotDetails) + httpRg.POST("/volume-snapshot", api.VolumeSnapshotController().DeployVolumeSnapshot) + httpRg.DELETE("/volume-snapshot/:name", api.VolumeSnapshotController().DeleteVolumeSnapshot) // Volume Snapshot Content - apiGroup.GET("api/v1/volume-snapshot-content", api.VolumeSnapshotContentController().GetVolumeSnapshotContentList) - apiGroup.GET("api/v1/volume-snapshot-content/:name", api.VolumeSnapshotContentController().GetVolumeSnapshotContentDetails) + httpRg.GET("/volume-snapshot-content", api.VolumeSnapshotContentController().GetVolumeSnapshotContentList) + httpRg.GET("/volume-snapshot-content/:name", api.VolumeSnapshotContentController().GetVolumeSnapshotContentDetails) // Volume Snapshot Class - apiGroup.GET("api/v1/volume-snapshot-class", api.VolumeSnapshotClassController().GetVolumeSnapshotClassList) - apiGroup.GET("api/v1/volume-snapshot-class/:name", api.VolumeSnapshotClassController().GetVolumeSnapshotClassDetails) + httpRg.GET("/volume-snapshot-class", api.VolumeSnapshotClassController().GetVolumeSnapshotClassList) + httpRg.GET("/volume-snapshot-class/:name", api.VolumeSnapshotClassController().GetVolumeSnapshotClassDetails) } diff --git a/pkg/server/server.go b/pkg/server/server.go index 38db60c..bf18a59 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -1,8 +1,12 @@ package server import ( + "fmt" "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/auth/controllers" + middleware "github.com/krack8/lighthouse/pkg/auth/middlewares" + cfg "github.com/krack8/lighthouse/pkg/config" _log "github.com/krack8/lighthouse/pkg/log" "github.com/krack8/lighthouse/pkg/server/router" "net/http" @@ -18,10 +22,16 @@ func Start() { corsConfig.AllowCredentials = true corsConfig.AllowHeaders = []string{"Origin", "*"} corsConfig.AddAllowMethods("OPTIONS") + //r.Use(cors.New(corsConfig)) r.Use(cors.New(corsConfig), gin.LoggerWithWriter(gin.DefaultWriter, "/health", "/swagger/*any")) - // Setting API Base Path for HTTP APIs - httpRouter := r.Group("/") + // Setting API Base Path for HTTP APIs + httpRouter := r.Group("api/v1") + fmt.Println(cfg.IsNoAuth()) + if !cfg.IsNoAuth() { + // Apply the AuthMiddleware to the / routes + httpRouter = r.Group("api/v1", middleware.AuthMiddleware()) + } // Get the application port from the environment port := os.Getenv("PORT") if port == "" { @@ -29,10 +39,37 @@ func Start() { } router.AddApiRoutes(httpRouter) - //r.GET("/health", api.Home().Health) - //r.GET("/", api.Home().Index) + r.GET("/health", Home().Health) + r.GET("/", Home().Index) + // Define the login route separately without middleware + // Login route + r.POST("/auth/login", controllers.LoginHandler) + // Refresh token route + r.POST("/auth/refresh-token", controllers.RefreshTokenHandler) + err := r.Run(":" + port) // listen and serve if err != nil { _log.Logger.Errorw("Failed to start server", "err", err.Error()) } } + +type HomeInf interface { + Index(c *gin.Context) + Health(c *gin.Context) +} + +type home struct{} + +func Home() HomeInf { + return &home{} +} + +func (h *home) Index(ctx *gin.Context) { + ctx.Data(http.StatusOK, "application/json; charset=utf-8", []byte("This is KloverCloud Lighthouse")) + return +} + +func (h *home) Health(ctx *gin.Context) { + ctx.Data(http.StatusOK, "application/json; charset=utf-8", []byte("I am live!")) + return +} From 41c51135e766cb92c2a9436d3cf560226559f88c Mon Sep 17 00:00:00 2001 From: Toha Date: Wed, 29 Jan 2025 17:11:00 +0600 Subject: [PATCH 24/64] config changes --- pkg/.env | 3 ++- pkg/agent/main.go | 1 + pkg/config/config.go | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/.env b/pkg/.env index 1e29349..634c4d5 100644 --- a/pkg/.env +++ b/pkg/.env @@ -13,4 +13,5 @@ JWT_REFRESH_SECRET=your_refresh_jwt_secret_key ACCESS_TOKEN_EXPIRY=15m REFRESH_TOKEN_EXPIRY=24h -NO_AUTH="FALSE" \ No newline at end of file +NO_AUTH="FALSE" +KUBE_CONFIG_FILE="dev-config.yaml" \ No newline at end of file diff --git a/pkg/agent/main.go b/pkg/agent/main.go index 1a46370..20b2b05 100644 --- a/pkg/agent/main.go +++ b/pkg/agent/main.go @@ -18,6 +18,7 @@ var taskMutex sync.Mutex func main() { _log.InitializeLogger() + config.InitEnvironmentVariables() config.InitiateKubeClientSet() // For demonstration, we'll just run a single worker that belongs to "GroupA". groupName := "GroupA" diff --git a/pkg/config/config.go b/pkg/config/config.go index 0b090e3..2eec5f9 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -28,6 +28,7 @@ func InitEnvironmentVariables() { } else { log.Logger.Infow("Started with NO AUTH disabled", "[NO-AUTH]", NoAuth) } + KubeConfigFile = os.Getenv("KUBE_CONFIG_FILE") } func IsNoAuth() bool { From a71bb3e76b493d82e14ae93c5694bbc0e4b33e8a Mon Sep 17 00:00:00 2001 From: Toha Date: Wed, 29 Jan 2025 17:58:29 +0600 Subject: [PATCH 25/64] comment env --- pkg/.env | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/.env b/pkg/.env index 634c4d5..0a9bddb 100644 --- a/pkg/.env +++ b/pkg/.env @@ -12,6 +12,6 @@ JWT_REFRESH_SECRET=your_refresh_jwt_secret_key # Token Expiry Configuration ACCESS_TOKEN_EXPIRY=15m REFRESH_TOKEN_EXPIRY=24h - -NO_AUTH="FALSE" +#TRUE/FALSE +NO_AUTH="TRUE" KUBE_CONFIG_FILE="dev-config.yaml" \ No newline at end of file From a25724e494037222c2b4e10d3b02f01e24296618 Mon Sep 17 00:00:00 2001 From: Toha Date: Thu, 30 Jan 2025 16:00:00 +0600 Subject: [PATCH 26/64] response dto omitempty --- .gitignore | 4 +++- README.md | 9 +++++++++ pkg/controller/api/response_sender.go | 4 ++-- pkg/k8s/certificate.go | 7 +++++-- pkg/k8s/k8s.go | 4 ++-- 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index d1a0e6f..7646f8d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ .idea .vscode node_modules -coverage \ No newline at end of file +coverage +.env +*.patch \ No newline at end of file diff --git a/README.md b/README.md index 5c39443..94bc2b4 100644 --- a/README.md +++ b/README.md @@ -19,4 +19,13 @@ go run main.go Generate Protobuf Go Files ```azure protoc --go_out=. --go-grpc_out=. pkg/common/pb/PROTO_FILE_NAME +``` + +Noauth Mode +``` +environment variables +// Noauth enabled +NO_AUTH="TRUE" +// Noauth disabled +NO_AUTH="FALSE" ``` \ No newline at end of file diff --git a/pkg/controller/api/response_sender.go b/pkg/controller/api/response_sender.go index ec39414..c16ee1b 100644 --- a/pkg/controller/api/response_sender.go +++ b/pkg/controller/api/response_sender.go @@ -9,8 +9,8 @@ import ( type ResponseDTO struct { Status string `json:"status"` - Msg string `json:"msg,omitempty"` - Data interface{} `json:"data,omitempty"` + Msg string `json:"msg"` + Data interface{} `json:"data"` } var nilResponse ResponseDTO = ResponseDTO{} diff --git a/pkg/k8s/certificate.go b/pkg/k8s/certificate.go index c3deb13..93b6ad7 100644 --- a/pkg/k8s/certificate.go +++ b/pkg/k8s/certificate.go @@ -112,7 +112,7 @@ func (p *GetCertificateListInputParams) Find(c context.Context, certificateClien func (p *GetCertificateListInputParams) Process(c context.Context) error { log.Logger.Debugw("fetching certificate list") - var certificateList []*dto.Certificate + var certificateList = []*dto.Certificate{} var err error limit := cfg.PageLimit @@ -181,7 +181,10 @@ func (svc *certificateService) GetCertificateList(c context.Context, p GetCertif if err != nil { return nil, err } - return p.output, nil + return ResponseDTO{ + Status: "success", + Data: p.output, + }, nil } type GetCertificateDetailsInputParams struct { diff --git a/pkg/k8s/k8s.go b/pkg/k8s/k8s.go index f947b54..954deb5 100644 --- a/pkg/k8s/k8s.go +++ b/pkg/k8s/k8s.go @@ -15,8 +15,8 @@ import ( type ResponseDTO struct { Status string `json:"status"` - Msg string `json:"msg,omitempty"` - Data interface{} `json:"data,omitempty"` + Msg string `json:"msg"` + Data interface{} `json:"data"` } var clientset *kubernetes.Clientset From f94c9b9139f475bcdd66d90a549b53044e190672 Mon Sep 17 00:00:00 2001 From: Toha Date: Fri, 31 Jan 2025 23:51:03 +0600 Subject: [PATCH 27/64] e2e test for home and health --- pkg/k8s_test/k8s_test.go | 47 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/pkg/k8s_test/k8s_test.go b/pkg/k8s_test/k8s_test.go index ad75b22..a3e8475 100644 --- a/pkg/k8s_test/k8s_test.go +++ b/pkg/k8s_test/k8s_test.go @@ -2,10 +2,14 @@ package k8s_test import ( "context" + cfg "github.com/krack8/lighthouse/pkg/config" "github.com/krack8/lighthouse/pkg/k8s" + "github.com/stretchr/testify/suite" + "io" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/fake" + "net/http" "testing" ) @@ -44,3 +48,46 @@ func TestListNamespaces(t *testing.T) { } } } + +var ( + BaseUrl = "http://127.0.0.1:" + cfg.ServerPort + HealthEndpoint = "/health" + IndexEndpoint = "/" +) + +type EndToEndSuite struct { + suite.Suite + client *http.Client +} + +func TestEndToEnd(t *testing.T) { + suite.Run(t, new(EndToEndSuite)) +} + +func (s *EndToEndSuite) SetupSuite() { + s.client = &http.Client{} +} + +func (s *EndToEndSuite) SetupTest() { + // Set up before *each* test runs (e.g., reset mocks, clear databases) +} + +func (s *EndToEndSuite) TearDownTest() { + // Clean up after *each* test runs +} + +func (s *EndToEndSuite) TestHealthCheck() { + resp, _ := s.client.Get(BaseUrl + HealthEndpoint) + defer resp.Body.Close() + s.Equal(resp.StatusCode, http.StatusOK) + body, _ := io.ReadAll(resp.Body) + s.Equal("I am live!", string(body)) +} + +func (s *EndToEndSuite) TestHealthIndex() { + resp, _ := s.client.Get(BaseUrl + IndexEndpoint) + defer resp.Body.Close() + s.Equal(resp.StatusCode, http.StatusOK) + body, _ := io.ReadAll(resp.Body) + s.Equal("This is KloverCloud Lighthouse", string(body)) +} From 1151dfce4357da771117f0a2bfc1d203852e8538 Mon Sep 17 00:00:00 2001 From: Nahid Date: Sun, 2 Feb 2025 11:57:18 +0600 Subject: [PATCH 28/64] feat: user profile api --- pkg/auth/controllers/user_controller.go | 18 ++++++++++++++++++ pkg/auth/enum/category.go | 8 ++++++++ pkg/auth/middlewares/auth.go | 3 ++- pkg/auth/models/rbac.go | 16 +++++++++------- pkg/auth/services/user_service.go | 13 +++++++++++++ pkg/server/router/routes.go | 1 + 6 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 pkg/auth/enum/category.go diff --git a/pkg/auth/controllers/user_controller.go b/pkg/auth/controllers/user_controller.go index 6f4eaa8..d935822 100644 --- a/pkg/auth/controllers/user_controller.go +++ b/pkg/auth/controllers/user_controller.go @@ -90,3 +90,21 @@ func (uc *UserController) DeleteUserHandler(c *gin.Context) { utils.RespondWithJSON(c, http.StatusOK, gin.H{"message": "User deleted successfully"}) } + +// GetUserProfileInfoHandler fetch user details by token. +func (uc *UserController) GetUserProfileInfoHandler(c *gin.Context) { + username, exists := c.Get("username") + if !exists { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Username not found in context"}) + return + } + // username is of type interface{}, so cast it to string + usernameStr := username.(string) + user, err := uc.UserService.GetUserProfileInfo(usernameStr) + if err != nil { + utils.RespondWithError(c, http.StatusInternalServerError, err.Error()) + return + } + + utils.RespondWithJSON(c, http.StatusOK, user) +} diff --git a/pkg/auth/enum/category.go b/pkg/auth/enum/category.go new file mode 100644 index 0000000..2260548 --- /dev/null +++ b/pkg/auth/enum/category.go @@ -0,0 +1,8 @@ +package enum + +type PermissionCategory string + +const ( + CLUSTER PermissionCategory = "CLUSTER" + HELM PermissionCategory = "HELM" +) diff --git a/pkg/auth/middlewares/auth.go b/pkg/auth/middlewares/auth.go index 228c673..ba56e6c 100644 --- a/pkg/auth/middlewares/auth.go +++ b/pkg/auth/middlewares/auth.go @@ -65,7 +65,8 @@ func AuthMiddleware() gin.HandlerFunc { c.Abort() return } - + // store username + c.Set("username", claims.Username) if user.UserType == models.RegularUser { // Collect all permissions of the user's roles var permissions []string diff --git a/pkg/auth/models/rbac.go b/pkg/auth/models/rbac.go index 7351f69..ed15e67 100644 --- a/pkg/auth/models/rbac.go +++ b/pkg/auth/models/rbac.go @@ -1,19 +1,21 @@ package models import ( + "github.com/krack8/lighthouse/pkg/auth/enum" "go.mongodb.org/mongo-driver/bson/primitive" "time" ) // Permission represents a specific action that can be performed on a resource type Permission struct { - ID primitive.ObjectID `json:"id" bson:"_id,omitempty"` - Name string `json:"name" bson:"name"` - Description string `json:"description" bson:"description"` - Route string `json:"route" bson:"route"` // URL path - Method string `json:"method" bson:"method"` // HTTP method (GET, POST, etc.) - CreatedAt time.Time `json:"created_at" bson:"created_at"` - UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` + ID primitive.ObjectID `json:"id" bson:"_id,omitempty"` + Name string `json:"name" bson:"name"` + Description string `json:"description" bson:"description"` + Route string `json:"route" bson:"route"` // URL path + Method string `json:"method" bson:"method"` // HTTP method (GET, POST, etc.) + Category enum.PermissionCategory `json:"category" bson:"category"` + CreatedAt time.Time `json:"created_at" bson:"created_at"` + UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` } // Role represents a user role with associated permissions diff --git a/pkg/auth/services/user_service.go b/pkg/auth/services/user_service.go index 38c21e5..d4c2684 100644 --- a/pkg/auth/services/user_service.go +++ b/pkg/auth/services/user_service.go @@ -185,3 +185,16 @@ func GetUserByUsername(username string) (*models.User, error) { return &user, nil } + +// GetUserProfileINfo fetch User Profile Info +func (s *UserService) GetUserProfileInfo(username string) (*models.User, error) { + if username == "" { + return nil, errors.New("username cannot be empty") + } + user, _ := GetUserByUsername(username) + + if user == nil { + return nil, errors.New("user do not exists") + } + return user, nil +} diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index cb1f8c0..365a916 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -20,6 +20,7 @@ func AddApiRoutes(httpRg *gin.RouterGroup) { httpRg.GET("/users/:id", authApi.UserController.GetUserHandler) httpRg.PUT("/users/:id", authApi.UserController.UpdateUserHandler) httpRg.DELETE("/users/:id", authApi.UserController.DeleteUserHandler) + httpRg.GET("/users/profile", authApi.UserController.GetUserProfileInfoHandler) // RBAC routes httpRg.POST("/rbac/permissions", authApi.RbacController.CreatePermissionHandler) From bfb573e8966ede0f9e95a6c354ad63c81d9a9364 Mon Sep 17 00:00:00 2001 From: Nahid Date: Sun, 2 Feb 2025 12:11:32 +0600 Subject: [PATCH 29/64] chore: use convenient env name --- pkg/.env | 2 +- pkg/auth/controllers/user_controller.go | 4 ++-- pkg/config/config.go | 2 +- pkg/server/server.go | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/.env b/pkg/.env index 0a9bddb..e7824ae 100644 --- a/pkg/.env +++ b/pkg/.env @@ -13,5 +13,5 @@ JWT_REFRESH_SECRET=your_refresh_jwt_secret_key ACCESS_TOKEN_EXPIRY=15m REFRESH_TOKEN_EXPIRY=24h #TRUE/FALSE -NO_AUTH="TRUE" +AUTH_ENABLED="TRUE" KUBE_CONFIG_FILE="dev-config.yaml" \ No newline at end of file diff --git a/pkg/auth/controllers/user_controller.go b/pkg/auth/controllers/user_controller.go index d935822..caf4d87 100644 --- a/pkg/auth/controllers/user_controller.go +++ b/pkg/auth/controllers/user_controller.go @@ -95,14 +95,14 @@ func (uc *UserController) DeleteUserHandler(c *gin.Context) { func (uc *UserController) GetUserProfileInfoHandler(c *gin.Context) { username, exists := c.Get("username") if !exists { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Username not found in context"}) + c.JSON(http.StatusBadRequest, gin.H{"error": "Username not found in context.Please Enable AUTH"}) return } // username is of type interface{}, so cast it to string usernameStr := username.(string) user, err := uc.UserService.GetUserProfileInfo(usernameStr) if err != nil { - utils.RespondWithError(c, http.StatusInternalServerError, err.Error()) + utils.RespondWithError(c, http.StatusBadRequest, err.Error()) return } diff --git a/pkg/config/config.go b/pkg/config/config.go index 2eec5f9..4e9800f 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -22,7 +22,7 @@ func InitEnvironmentVariables() { log.Logger.Errorw("Failed to Load environment file", "err", err.Error()) os.Exit(1) } - if os.Getenv("NO_AUTH") == "TRUE" { + if os.Getenv("AUTH_ENABLED") == "TRUE" { NoAuth = true log.Logger.Infow("Started with NO AUTH enabled", "[NO-AUTH]", NoAuth) } else { diff --git a/pkg/server/server.go b/pkg/server/server.go index bf18a59..d35d7ff 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -43,9 +43,9 @@ func Start() { r.GET("/", Home().Index) // Define the login route separately without middleware // Login route - r.POST("/auth/login", controllers.LoginHandler) + r.POST("/api/auth/login", controllers.LoginHandler) // Refresh token route - r.POST("/auth/refresh-token", controllers.RefreshTokenHandler) + r.POST("/api/auth/refresh-token", controllers.RefreshTokenHandler) err := r.Run(":" + port) // listen and serve if err != nil { From a2e9b0ab549daae8e8dcba7f229f56aa975721bb Mon Sep 17 00:00:00 2001 From: Nahid Date: Sun, 2 Feb 2025 13:15:33 +0600 Subject: [PATCH 30/64] feat: Implement register cluster APIs --- pkg/auth/authApi/init_global_var.go | 12 ++- pkg/auth/config/db.go | 79 +++++++++++++++++ pkg/auth/controllers/cluster_controller.go | 42 +++++++++ pkg/auth/enum/cluster_type.go | 8 ++ pkg/auth/enum/table.go | 8 +- pkg/auth/models/cluster.go | 39 +++++++++ pkg/auth/services/cluster_service.go | 99 ++++++++++++++++++++++ pkg/auth/utils/utils.go | 12 +++ pkg/config/config.go | 12 +-- pkg/controller/main.go | 3 + pkg/server/router/routes.go | 4 + pkg/server/server.go | 4 +- 12 files changed, 307 insertions(+), 15 deletions(-) create mode 100644 pkg/auth/controllers/cluster_controller.go create mode 100644 pkg/auth/enum/cluster_type.go create mode 100644 pkg/auth/models/cluster.go create mode 100644 pkg/auth/services/cluster_service.go diff --git a/pkg/auth/authApi/init_global_var.go b/pkg/auth/authApi/init_global_var.go index 26b6ee9..9ee242c 100644 --- a/pkg/auth/authApi/init_global_var.go +++ b/pkg/auth/authApi/init_global_var.go @@ -8,12 +8,14 @@ import ( var ( // Global service instances - UserService *services.UserService - RbacService *services.RbacService + UserService *services.UserService + RbacService *services.RbacService + ClusterService *services.ClusterService // UserController Global controller instances - UserController *controllers.UserController - RbacController *controllers.RbacController + UserController *controllers.UserController + RbacController *controllers.RbacController + ClusterController *controllers.ClusterController once sync.Once ) @@ -24,10 +26,12 @@ func Init() { // Initialize services UserService = &services.UserService{} RbacService = &services.RbacService{} + ClusterService = &services.ClusterService{} // Initialize controllers with services UserController = controllers.NewUserController(UserService) RbacController = controllers.NewRbacController(RbacService) + ClusterController = controllers.NewClusterController(ClusterService) }) } diff --git a/pkg/auth/config/db.go b/pkg/auth/config/db.go index 4a0b292..0aa2a04 100644 --- a/pkg/auth/config/db.go +++ b/pkg/auth/config/db.go @@ -21,6 +21,8 @@ var ( PermissionCollection *mongo.Collection RoleCollection *mongo.Collection UserCollection *mongo.Collection + ClusterCollection *mongo.Collection + TokenCollection *mongo.Collection ) // ConnectDB initializes the MongoDB client and collections. @@ -57,6 +59,8 @@ func ConnectDB() (*mongo.Client, context.Context, error) { UserCollection = client.Database(dbName).Collection(string(enum.UsersTable)) PermissionCollection = client.Database(dbName).Collection(string(enum.PermissionsTable)) RoleCollection = client.Database(dbName).Collection(string(enum.RolesTable)) + ClusterCollection = client.Database(dbName).Collection(string(enum.ClusterTable)) + TokenCollection = client.Database(dbName).Collection(string(enum.TokenTable)) log.Println("Successfully connected to MongoDB") return client, ctx, nil @@ -162,3 +166,78 @@ func InitRBAC() { } } } + +// InitializeClusters creates default clusters if none exist +func InitializeClusters() { + clusterCount, err := ClusterCollection.CountDocuments(context.Background(), bson.M{}) + if err != nil { + log.Fatalf("Error counting clusters: %v", err) + } + + if clusterCount == 0 { + // Create master cluster + masterToken := utils.GenerateSecureToken(32) + masterCluster := models.Cluster{ + ID: primitive.NewObjectID(), + Name: "master-cluster", + ClusterType: enum.MASTER, + Token: masterToken, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + IsActive: true, + } + + // Create agent cluster + agentToken := utils.GenerateSecureToken(32) + agentCluster := models.Cluster{ + ID: primitive.NewObjectID(), + Name: "agent-cluster", + ClusterType: enum.AGENT, + Token: agentToken, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + IsActive: true, + } + + masterCluster.MasterClusterId = masterCluster.ID.Hex() + agentCluster.MasterClusterId = masterCluster.ID.Hex() + // Insert clusters + clusters := []interface{}{masterCluster, agentCluster} + _, err := ClusterCollection.InsertMany(context.Background(), clusters) + if err != nil { + log.Fatalf("Error creating default clusters: %v", err) + } + + // Create token validations + masterTokenValidation := models.TokenValidation{ + ID: primitive.NewObjectID(), + ClusterID: masterCluster.ID, + Token: masterToken, + IsValid: true, + ExpiresAt: time.Now().AddDate(1, 0, 0), // Token valid for 1 year + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + + agentTokenValidation := models.TokenValidation{ + ID: primitive.NewObjectID(), + ClusterID: agentCluster.ID, + Token: agentToken, + IsValid: true, + ExpiresAt: time.Now().AddDate(1, 0, 0), // Token valid for 1 year + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + + // Insert token validations + tokenValidations := []interface{}{masterTokenValidation, agentTokenValidation} + _, err = TokenCollection.InsertMany(context.Background(), tokenValidations) + if err != nil { + log.Fatalf("Error creating token validations: %v", err) + } + + log.Println("Default clusters and token validations created successfully") + } else { + log.Println("Clusters already exist. No default clusters created.") + } +} diff --git a/pkg/auth/controllers/cluster_controller.go b/pkg/auth/controllers/cluster_controller.go new file mode 100644 index 0000000..0b29209 --- /dev/null +++ b/pkg/auth/controllers/cluster_controller.go @@ -0,0 +1,42 @@ +package controllers + +import ( + "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/auth/services" + "github.com/krack8/lighthouse/pkg/auth/utils" + "net/http" +) + +type ClusterController struct { + ClusterService *services.ClusterService +} + +func NewClusterController(clusterService *services.ClusterService) *ClusterController { + return &ClusterController{ + ClusterService: clusterService, + } +} + +// GetClusterHandler handles fetching a Cluster by ID. +func (uc *ClusterController) GetClusterHandler(c *gin.Context) { + id := c.Param("id") + + Cluster, err := uc.ClusterService.GetCluster(id) + if err != nil { + utils.RespondWithError(c, http.StatusInternalServerError, err.Error()) + return + } + + utils.RespondWithJSON(c, http.StatusOK, Cluster) +} + +// GetAllClustersHandler handles fetching all Clusters. +func (uc *ClusterController) GetAllClustersHandler(c *gin.Context) { + ClusterList, err := uc.ClusterService.GetAllClusters() + if err != nil { + utils.RespondWithError(c, http.StatusInternalServerError, err.Error()) + return + } + + utils.RespondWithJSON(c, http.StatusOK, ClusterList) +} diff --git a/pkg/auth/enum/cluster_type.go b/pkg/auth/enum/cluster_type.go new file mode 100644 index 0000000..4b7bc51 --- /dev/null +++ b/pkg/auth/enum/cluster_type.go @@ -0,0 +1,8 @@ +package enum + +type ClusterType string + +const ( + MASTER ClusterType = "MASTER" + AGENT ClusterType = "AGENT" +) diff --git a/pkg/auth/enum/table.go b/pkg/auth/enum/table.go index ef1ec04..c20c537 100644 --- a/pkg/auth/enum/table.go +++ b/pkg/auth/enum/table.go @@ -4,7 +4,9 @@ package enum type TableName string const ( - UsersTable TableName = "users" // Enum for the User table name - PermissionsTable TableName = "permissions" // Enum for the User table name - RolesTable TableName = "roles" // Enum for the User table name + UsersTable TableName = "users" + PermissionsTable TableName = "permissions" + RolesTable TableName = "roles" + ClusterTable TableName = "cluster" + TokenTable TableName = "token" ) diff --git a/pkg/auth/models/cluster.go b/pkg/auth/models/cluster.go new file mode 100644 index 0000000..2941fe0 --- /dev/null +++ b/pkg/auth/models/cluster.go @@ -0,0 +1,39 @@ +package models + +import ( + "crypto/rand" + "encoding/hex" + "github.com/krack8/lighthouse/pkg/auth/enum" + "go.mongodb.org/mongo-driver/bson/primitive" + "time" +) + +type Cluster struct { + ID primitive.ObjectID `json:"_id" bson:"_id,omitempty"` + Name string `json:"name" bson:"name"` + ClusterType enum.ClusterType `json:"cluster_type" bson:"cluster_type"` // e.g., "MASTER", "AGENT" + Token string `json:"-" bson:"token"` + MasterClusterId string `json:"masterClusterId" bson:"masterClusterId"` + CreatedAt time.Time `json:"created_at" bson:"created_at"` + UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` + IsActive bool `json:"is_active" bson:"is_active"` +} + +type TokenValidation struct { + ID primitive.ObjectID `json:"_id" bson:"_id,omitempty"` + ClusterID primitive.ObjectID `json:"cluster_id" bson:"cluster_id"` + Token string `json:"token" bson:"token"` + IsValid bool `json:"is_valid" bson:"is_valid"` + ExpiresAt time.Time `json:"expires_at" bson:"expires_at"` + CreatedAt time.Time `json:"created_at" bson:"created_at"` + UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` +} + +// Generate secure token +func generateSecureToken(length int) string { + b := make([]byte, length) + if _, err := rand.Read(b); err != nil { + return "" + } + return hex.EncodeToString(b) +} diff --git a/pkg/auth/services/cluster_service.go b/pkg/auth/services/cluster_service.go new file mode 100644 index 0000000..6641c43 --- /dev/null +++ b/pkg/auth/services/cluster_service.go @@ -0,0 +1,99 @@ +package services + +import ( + "context" + "errors" + "fmt" + db "github.com/krack8/lighthouse/pkg/auth/config" + "time" + + "github.com/krack8/lighthouse/pkg/auth/models" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" +) + +// ClusterService handles cluster-related business logic +type ClusterService struct { + collection Collection +} + +// NewClusterService creates a new ClusterService instance +func NewClusterService(collection Collection) *ClusterService { + return &ClusterService{ + collection: collection, + } +} + +// GetCluster retrieves a cluster by ID +func (s *ClusterService) GetCluster(clusterID string) (*models.Cluster, error) { + if clusterID == "" { + return nil, errors.New("cluster ID cannot be empty") + } + + objectID, err := primitive.ObjectIDFromHex(clusterID) + if err != nil { + return nil, fmt.Errorf("invalid cluster ID format: %w", err) + } + + var cluster models.Cluster + filter := bson.M{"_id": objectID} + result := db.ClusterCollection.FindOne(context.Background(), filter) + if err := result.Decode(&cluster); err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + return nil, errors.New("cluster not found") + } + return nil, fmt.Errorf("failed to fetch cluster: %w", err) + } + + return &cluster, nil +} + +// GetAllclusters retrieves all clusters +func (s *ClusterService) GetAllClusters() ([]models.Cluster, error) { + cursor, err := db.ClusterCollection.Find(context.Background(), bson.M{}) + if err != nil { + return nil, fmt.Errorf("failed to fetch clusters: %w", err) + } + defer cursor.Close(context.Background()) + + var clusters []models.Cluster + for cursor.Next(context.Background()) { + var cluster models.Cluster + if err := cursor.Decode(&cluster); err != nil { + return nil, fmt.Errorf("failed to decode cluster: %w", err) + } + clusters = append(clusters, cluster) + } + + if err := cursor.Err(); err != nil { + return nil, fmt.Errorf("cursor error: %w", err) + } + + return clusters, nil +} + +func ValidateClusterToken(token string) (*models.Cluster, error) { + var tokenValidation models.TokenValidation + err := db.TokenCollection.FindOne(context.Background(), bson.M{ + "token": token, + "is_valid": true, + "expires_at": bson.M{"$gt": time.Now()}, + }).Decode(&tokenValidation) + + if err != nil { + return nil, fmt.Errorf("invalid or expired token") + } + + var cluster models.Cluster + err = db.ClusterCollection.FindOne(context.Background(), bson.M{ + "_id": tokenValidation.ClusterID, + "is_active": true, + }).Decode(&cluster) + + if err != nil { + return nil, fmt.Errorf("cluster not found or inactive") + } + + return &cluster, nil +} diff --git a/pkg/auth/utils/utils.go b/pkg/auth/utils/utils.go index b419659..1c5bf55 100644 --- a/pkg/auth/utils/utils.go +++ b/pkg/auth/utils/utils.go @@ -1,6 +1,9 @@ package utils import ( + "crypto/rand" + "encoding/hex" + "fmt" "golang.org/x/crypto/bcrypt" "log" ) @@ -20,3 +23,12 @@ func CheckPassword(password, hashedPassword string) bool { err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password)) return err == nil // Return true if passwords match, false otherwise } + +func GenerateSecureToken(length int) string { + bytes := make([]byte, length) + if _, err := rand.Read(bytes); err != nil { + _ = fmt.Errorf("failed to generate secure token: %w", err) + return "" + } + return hex.EncodeToString(bytes) +} diff --git a/pkg/config/config.go b/pkg/config/config.go index 4e9800f..d21aab5 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -10,7 +10,7 @@ var ServerPort = "8080" var PageLimit = int64(10) var isK8 = false var KubeConfigFile = "dev-config.yaml" -var NoAuth = false +var Auth = false func IsK8() bool { return isK8 @@ -23,14 +23,14 @@ func InitEnvironmentVariables() { os.Exit(1) } if os.Getenv("AUTH_ENABLED") == "TRUE" { - NoAuth = true - log.Logger.Infow("Started with NO AUTH enabled", "[NO-AUTH]", NoAuth) + Auth = true + log.Logger.Infow("Started with NO AUTH enabled", "[NO-AUTH]", Auth) } else { - log.Logger.Infow("Started with NO AUTH disabled", "[NO-AUTH]", NoAuth) + log.Logger.Infow("Started with NO AUTH disabled", "[NO-AUTH]", Auth) } KubeConfigFile = os.Getenv("KUBE_CONFIG_FILE") } -func IsNoAuth() bool { - return NoAuth +func IsAuth() bool { + return Auth } diff --git a/pkg/controller/main.go b/pkg/controller/main.go index b6afd6e..c14ac46 100644 --- a/pkg/controller/main.go +++ b/pkg/controller/main.go @@ -39,6 +39,9 @@ func main() { // Initialize the default user if needed config.InitializeDefaultUser() + // Initialize the default cluster if needed + config.InitializeClusters() + // Initialize auth controllers with services authApi.Init() diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index 365a916..08a2963 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -22,6 +22,10 @@ func AddApiRoutes(httpRg *gin.RouterGroup) { httpRg.DELETE("/users/:id", authApi.UserController.DeleteUserHandler) httpRg.GET("/users/profile", authApi.UserController.GetUserProfileInfoHandler) + // Cluster routes + httpRg.GET("/clusters", authApi.ClusterController.GetAllClustersHandler) + httpRg.GET("/clusters/:id", authApi.ClusterController.GetClusterHandler) + // RBAC routes httpRg.POST("/rbac/permissions", authApi.RbacController.CreatePermissionHandler) httpRg.POST("/rbac/roles", authApi.RbacController.CreateRoleHandler) diff --git a/pkg/server/server.go b/pkg/server/server.go index d35d7ff..1c14c05 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -27,8 +27,8 @@ func Start() { // Setting API Base Path for HTTP APIs httpRouter := r.Group("api/v1") - fmt.Println(cfg.IsNoAuth()) - if !cfg.IsNoAuth() { + fmt.Println(cfg.IsAuth()) + if cfg.IsAuth() { // Apply the AuthMiddleware to the / routes httpRouter = r.Group("api/v1", middleware.AuthMiddleware()) } From 15a9162bae8ad067c094437b6c56bc292dcb5a5d Mon Sep 17 00:00:00 2001 From: Nahid Date: Sun, 2 Feb 2025 13:31:08 +0600 Subject: [PATCH 31/64] chore: API modification. Add filter --- pkg/auth/services/cluster_service.go | 16 ++++++++++++---- pkg/auth/services/user_service.go | 7 ++++++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/pkg/auth/services/cluster_service.go b/pkg/auth/services/cluster_service.go index 6641c43..f4a7392 100644 --- a/pkg/auth/services/cluster_service.go +++ b/pkg/auth/services/cluster_service.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" db "github.com/krack8/lighthouse/pkg/auth/config" + "github.com/krack8/lighthouse/pkg/auth/enum" "time" "github.com/krack8/lighthouse/pkg/auth/models" @@ -49,13 +50,20 @@ func (s *ClusterService) GetCluster(clusterID string) (*models.Cluster, error) { return &cluster, nil } -// GetAllclusters retrieves all clusters func (s *ClusterService) GetAllClusters() ([]models.Cluster, error) { - cursor, err := db.ClusterCollection.Find(context.Background(), bson.M{}) + // Filter for AGENT clusters + filter := bson.M{"cluster_type": bson.M{"$eq": enum.AGENT}} + + cursor, err := db.ClusterCollection.Find(context.Background(), filter) if err != nil { - return nil, fmt.Errorf("failed to fetch clusters: %w", err) + return nil, fmt.Errorf("failed to fetch non-master clusters: %w", err) } - defer cursor.Close(context.Background()) + defer func(cursor *mongo.Cursor, ctx context.Context) { + err := cursor.Close(ctx) + if err != nil { + + } + }(cursor, context.Background()) var clusters []models.Cluster for cursor.Next(context.Background()) { diff --git a/pkg/auth/services/user_service.go b/pkg/auth/services/user_service.go index d4c2684..0c24685 100644 --- a/pkg/auth/services/user_service.go +++ b/pkg/auth/services/user_service.go @@ -91,7 +91,12 @@ func (s *UserService) GetAllUsers() ([]models.User, error) { if err != nil { return nil, fmt.Errorf("failed to fetch users: %w", err) } - defer cursor.Close(context.Background()) + defer func(cursor *mongo.Cursor, ctx context.Context) { + err := cursor.Close(ctx) + if err != nil { + + } + }(cursor, context.Background()) var users []models.User for cursor.Next(context.Background()) { From eed82413dd467a2312d04ce807b230f0ad412d0a Mon Sep 17 00:00:00 2001 From: Nahid Date: Sun, 2 Feb 2025 13:43:23 +0600 Subject: [PATCH 32/64] chore: Modify Init Function --- pkg/auth/config/db.go | 2 ++ pkg/auth/enum/category.go | 1 + 2 files changed, 3 insertions(+) diff --git a/pkg/auth/config/db.go b/pkg/auth/config/db.go index 0aa2a04..b31e98c 100644 --- a/pkg/auth/config/db.go +++ b/pkg/auth/config/db.go @@ -120,6 +120,7 @@ func InitRBAC() { Name: "Create User", Description: "Permission to create a user", Route: "/users", + Category: enum.DEFAULT, Method: "POST", CreatedAt: time.Now(), UpdatedAt: time.Now(), @@ -130,6 +131,7 @@ func InitRBAC() { Description: "Create Role", Route: "/roles", Method: "POST", + Category: enum.DEFAULT, CreatedAt: time.Now(), UpdatedAt: time.Now(), }, diff --git a/pkg/auth/enum/category.go b/pkg/auth/enum/category.go index 2260548..b9bd935 100644 --- a/pkg/auth/enum/category.go +++ b/pkg/auth/enum/category.go @@ -3,6 +3,7 @@ package enum type PermissionCategory string const ( + DEFAULT PermissionCategory = "DEFAULT" CLUSTER PermissionCategory = "CLUSTER" HELM PermissionCategory = "HELM" ) From 96b558115fa33603f3dd46ef867a76297ada3d60 Mon Sep 17 00:00:00 2001 From: Toha Date: Sun, 2 Feb 2025 16:28:18 +0600 Subject: [PATCH 33/64] error and json redundant conversion --- pkg/controller/api/daemonset.go | 4 ++-- pkg/controller/api/deployment.go | 6 +++--- pkg/controller/api/endpoints.go | 2 +- pkg/controller/api/endpointslice.go | 2 +- pkg/controller/api/event.go | 2 +- pkg/controller/api/hpa.go | 2 +- pkg/controller/api/ingress.go | 2 +- pkg/controller/api/istio_gateway.go | 2 +- pkg/controller/api/job.go | 2 +- pkg/controller/api/load_balancer.go | 2 +- pkg/controller/api/network_policy.go | 2 +- pkg/controller/api/node.go | 2 +- pkg/controller/api/pod.go | 4 ++-- pkg/controller/api/pod_disruption_budgets.go | 2 +- pkg/controller/api/pv.go | 2 +- pkg/controller/api/pvc.go | 2 +- pkg/controller/api/replicaset.go | 4 ++-- pkg/controller/api/replication_controller.go | 2 +- pkg/controller/api/resource_quota.go | 2 +- pkg/controller/api/role.go | 2 +- pkg/controller/api/role_binding.go | 2 +- pkg/controller/api/sa.go | 2 +- pkg/controller/api/secret.go | 2 +- pkg/controller/api/statefulset.go | 6 +++--- pkg/controller/api/storage_class.go | 2 +- pkg/controller/api/svc.go | 2 +- pkg/controller/api/virtual_service.go | 2 +- pkg/controller/api/volume_snapshot.go | 2 +- pkg/controller/api/volume_snapshot_class.go | 2 +- pkg/controller/api/volume_snapshot_content.go | 2 +- pkg/k8s/deployment.go | 9 ++++++--- pkg/k8s/statefulset.go | 9 ++++++--- 32 files changed, 49 insertions(+), 43 deletions(-) diff --git a/pkg/controller/api/daemonset.go b/pkg/controller/api/daemonset.go index 9fecbe2..9cdd3c0 100644 --- a/pkg/controller/api/daemonset.go +++ b/pkg/controller/api/daemonset.go @@ -48,7 +48,7 @@ func (ctrl *daemonSetController) GetDaemonSetList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } @@ -191,7 +191,7 @@ func (ctrl *daemonSetController) GetDaemonSetStats(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/deployment.go b/pkg/controller/api/deployment.go index 11b1e08..5a879a0 100644 --- a/pkg/controller/api/deployment.go +++ b/pkg/controller/api/deployment.go @@ -49,7 +49,7 @@ func (ctrl *deploymentController) GetDeploymentList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } @@ -192,7 +192,7 @@ func (ctrl *deploymentController) GetDeploymentStats(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } @@ -249,7 +249,7 @@ func (ctrl *deploymentController) GetDeploymentPodList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/endpoints.go b/pkg/controller/api/endpoints.go index 2bbafd7..87d2d66 100644 --- a/pkg/controller/api/endpoints.go +++ b/pkg/controller/api/endpoints.go @@ -42,7 +42,7 @@ func (ctrl *endpointsController) GetEndpointsList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/endpointslice.go b/pkg/controller/api/endpointslice.go index ed78234..afa8d38 100644 --- a/pkg/controller/api/endpointslice.go +++ b/pkg/controller/api/endpointslice.go @@ -41,7 +41,7 @@ func (ctrl *endpointSliceController) GetEndpointSliceList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/event.go b/pkg/controller/api/event.go index 1666f1e..86e4fb4 100644 --- a/pkg/controller/api/event.go +++ b/pkg/controller/api/event.go @@ -45,7 +45,7 @@ func (ctrl *eventController) GetEventList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/hpa.go b/pkg/controller/api/hpa.go index be2188b..40ff982 100644 --- a/pkg/controller/api/hpa.go +++ b/pkg/controller/api/hpa.go @@ -42,7 +42,7 @@ func (ctrl *hpaController) GetHpaList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/ingress.go b/pkg/controller/api/ingress.go index 0991371..6d26818 100644 --- a/pkg/controller/api/ingress.go +++ b/pkg/controller/api/ingress.go @@ -47,7 +47,7 @@ func (ctrl *ingressController) GetIngressList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/istio_gateway.go b/pkg/controller/api/istio_gateway.go index 802f29d..5b4bd1e 100644 --- a/pkg/controller/api/istio_gateway.go +++ b/pkg/controller/api/istio_gateway.go @@ -47,7 +47,7 @@ func (ctrl *istioGatewayController) GetIstioGatewayList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/job.go b/pkg/controller/api/job.go index 002cd64..db1b29f 100644 --- a/pkg/controller/api/job.go +++ b/pkg/controller/api/job.go @@ -47,7 +47,7 @@ func (ctrl *jobController) GetJobList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/load_balancer.go b/pkg/controller/api/load_balancer.go index ffc97a4..bc55cb4 100644 --- a/pkg/controller/api/load_balancer.go +++ b/pkg/controller/api/load_balancer.go @@ -42,7 +42,7 @@ func (ctrl *loadBalancerController) GetLoadBalancerList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/network_policy.go b/pkg/controller/api/network_policy.go index 8edc697..eabce31 100644 --- a/pkg/controller/api/network_policy.go +++ b/pkg/controller/api/network_policy.go @@ -44,7 +44,7 @@ func (ctrl *networkPolicyController) GetNetworkPolicyList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/node.go b/pkg/controller/api/node.go index cb9b1be..58653ff 100644 --- a/pkg/controller/api/node.go +++ b/pkg/controller/api/node.go @@ -37,7 +37,7 @@ func (ctrl *nodeController) GetNodeList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Errorw("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/pod.go b/pkg/controller/api/pod.go index df66f74..cdf871e 100644 --- a/pkg/controller/api/pod.go +++ b/pkg/controller/api/pod.go @@ -50,7 +50,7 @@ func (ctrl *podController) GetPodList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } @@ -195,7 +195,7 @@ func (ctrl *podController) GetPodStats(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/pod_disruption_budgets.go b/pkg/controller/api/pod_disruption_budgets.go index f4209ac..aee2722 100644 --- a/pkg/controller/api/pod_disruption_budgets.go +++ b/pkg/controller/api/pod_disruption_budgets.go @@ -47,7 +47,7 @@ func (ctrl *podDisruptionBudgetsController) GetPodDisruptionBudgetsList(ctx *gin jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/pv.go b/pkg/controller/api/pv.go index da58c02..89bff7e 100644 --- a/pkg/controller/api/pv.go +++ b/pkg/controller/api/pv.go @@ -37,7 +37,7 @@ func (ctrl *pvController) GetPvList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/pvc.go b/pkg/controller/api/pvc.go index a2afcb4..4c46360 100644 --- a/pkg/controller/api/pvc.go +++ b/pkg/controller/api/pvc.go @@ -47,7 +47,7 @@ func (ctrl *pvcController) GetPvcList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/replicaset.go b/pkg/controller/api/replicaset.go index 3bcbc16..07e431a 100644 --- a/pkg/controller/api/replicaset.go +++ b/pkg/controller/api/replicaset.go @@ -47,7 +47,7 @@ func (ctrl *replicaSetController) GetReplicaSetList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } @@ -192,7 +192,7 @@ func (ctrl *replicaSetController) GetReplicaSetStats(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/replication_controller.go b/pkg/controller/api/replication_controller.go index 8787f37..53fb1d1 100644 --- a/pkg/controller/api/replication_controller.go +++ b/pkg/controller/api/replication_controller.go @@ -47,7 +47,7 @@ func (ctrl *replicationControllerController) GetReplicationControllerList(ctx *g jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/resource_quota.go b/pkg/controller/api/resource_quota.go index 6bafb02..e95fb1b 100644 --- a/pkg/controller/api/resource_quota.go +++ b/pkg/controller/api/resource_quota.go @@ -47,7 +47,7 @@ func (ctrl *resourceQuotaController) GetResourceQuotaList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/role.go b/pkg/controller/api/role.go index 7496001..c7c3368 100644 --- a/pkg/controller/api/role.go +++ b/pkg/controller/api/role.go @@ -47,7 +47,7 @@ func (ctrl *roleController) GetRoleList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/role_binding.go b/pkg/controller/api/role_binding.go index f4450b0..61d1c75 100644 --- a/pkg/controller/api/role_binding.go +++ b/pkg/controller/api/role_binding.go @@ -47,7 +47,7 @@ func (ctrl *roleBindingController) GetRoleBindingList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/sa.go b/pkg/controller/api/sa.go index bc9e224..020ca10 100644 --- a/pkg/controller/api/sa.go +++ b/pkg/controller/api/sa.go @@ -47,7 +47,7 @@ func (ctrl *serviceAccountController) GetServiceAccountList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/secret.go b/pkg/controller/api/secret.go index 8fa1eb8..62846a0 100644 --- a/pkg/controller/api/secret.go +++ b/pkg/controller/api/secret.go @@ -47,7 +47,7 @@ func (ctrl *secretController) GetSecretList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/statefulset.go b/pkg/controller/api/statefulset.go index 4d41079..af6d0d6 100644 --- a/pkg/controller/api/statefulset.go +++ b/pkg/controller/api/statefulset.go @@ -49,7 +49,7 @@ func (ctrl *statefulSetController) GetStatefulSetList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } @@ -194,7 +194,7 @@ func (ctrl *statefulSetController) GetStatefulSetStats(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } @@ -240,7 +240,7 @@ func (ctrl *statefulSetController) GetStatefulSetPodList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/storage_class.go b/pkg/controller/api/storage_class.go index 6bfa628..f01012d 100644 --- a/pkg/controller/api/storage_class.go +++ b/pkg/controller/api/storage_class.go @@ -36,7 +36,7 @@ func (ctrl *storageClassController) GetStorageClassList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/svc.go b/pkg/controller/api/svc.go index 9bf61d7..eb459dc 100644 --- a/pkg/controller/api/svc.go +++ b/pkg/controller/api/svc.go @@ -47,7 +47,7 @@ func (ctrl *svcController) GetSvcList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/virtual_service.go b/pkg/controller/api/virtual_service.go index edfe84d..731006a 100644 --- a/pkg/controller/api/virtual_service.go +++ b/pkg/controller/api/virtual_service.go @@ -47,7 +47,7 @@ func (ctrl *virtualServiceController) GetVirtualServiceList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/volume_snapshot.go b/pkg/controller/api/volume_snapshot.go index 2c85881..0b6a3bf 100644 --- a/pkg/controller/api/volume_snapshot.go +++ b/pkg/controller/api/volume_snapshot.go @@ -45,7 +45,7 @@ func (ctrl *volumeSnapshotController) GetVolumeSnapshotList(ctx *gin.Context) { jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/volume_snapshot_class.go b/pkg/controller/api/volume_snapshot_class.go index 1e65bfc..a50b7b2 100644 --- a/pkg/controller/api/volume_snapshot_class.go +++ b/pkg/controller/api/volume_snapshot_class.go @@ -33,7 +33,7 @@ func (ctrl *volumeSnapshotClassController) GetVolumeSnapshotClassList(ctx *gin.C jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/controller/api/volume_snapshot_content.go b/pkg/controller/api/volume_snapshot_content.go index 6f94008..c3c52d1 100644 --- a/pkg/controller/api/volume_snapshot_content.go +++ b/pkg/controller/api/volume_snapshot_content.go @@ -33,7 +33,7 @@ func (ctrl *volumeSnapshotContentController) GetVolumeSnapshotContentList(ctx *g jsonLabel := []byte(queryLabel) queryLabelMap := map[string]string{} - err := json.Unmarshal([]byte(jsonLabel), &queryLabelMap) + err := json.Unmarshal(jsonLabel, &queryLabelMap) if err != nil { log.Logger.Error("query labels unmarshal error ", "err", err.Error()) } diff --git a/pkg/k8s/deployment.go b/pkg/k8s/deployment.go index 07240aa..206960d 100644 --- a/pkg/k8s/deployment.go +++ b/pkg/k8s/deployment.go @@ -362,7 +362,8 @@ func (p *GetDeploymentStatsInputParams) Process(c context.Context) error { p.output.Ready += int(obj.Status.ReadyReplicas) podMetricsList, err := cfg.GetMetricsClientSet().MetricsV1beta1().PodMetricses(p.NamespaceName).List(context.TODO(), metav1.ListOptions{LabelSelector: fmt.Sprintf("app=%s", obj.Labels["app"])}) if err != nil { - panic(err.Error()) + log.Logger.Errorw("Failed to get pod metrics", "err", err.Error()) + return err } for _, podMetrics := range podMetricsList.Items { for _, container := range podMetrics.Containers { @@ -385,7 +386,8 @@ func (p *GetDeploymentStatsInputParams) Process(c context.Context) error { podMetricsList, err := cfg.GetMetricsClientSet().MetricsV1beta1().PodMetricses(p.NamespaceName).List(context.TODO(), metav1.ListOptions{LabelSelector: fmt.Sprintf("app=%s", obj.Labels["app"])}) if err != nil { - panic(err.Error()) + log.Logger.Errorw("Failed to get pod metrics", "err", err.Error()) + return err } for _, podMetrics := range podMetricsList.Items { for _, container := range podMetrics.Containers { @@ -478,7 +480,8 @@ func (p *GetDeploymentPodListInputParams) Process(c context.Context) error { p.output.PodList[idx].ManagedFields = nil podMetrics, err := cfg.GetMetricsClientSet().MetricsV1beta1().PodMetricses(p.NamespaceName).Get(context.TODO(), pod.Name, metav1.GetOptions{}) if err != nil { - panic(err.Error()) + log.Logger.Errorw("Failed to get pod metrics", "err", err.Error()) + return err } for _, container := range podMetrics.Containers { totalCPU += float64(container.Usage.Cpu().MilliValue()) / 1000.0 diff --git a/pkg/k8s/statefulset.go b/pkg/k8s/statefulset.go index 63f9082..0ce8f45 100644 --- a/pkg/k8s/statefulset.go +++ b/pkg/k8s/statefulset.go @@ -344,7 +344,8 @@ func (p *GetStatefulSetStatsInputParams) Process(c context.Context) error { p.output.Ready += int(obj.Status.ReadyReplicas) podMetricsList, err := cfg.GetMetricsClientSet().MetricsV1beta1().PodMetricses(p.NamespaceName).List(context.TODO(), metav1.ListOptions{LabelSelector: fmt.Sprintf("controller-revision-hash=%s", obj.Status.CurrentRevision)}) if err != nil { - panic(err.Error()) + log.Logger.Errorw("Failed to get pod metrics", "err", err.Error()) + return err } for _, podMetrics := range podMetricsList.Items { for _, container := range podMetrics.Containers { @@ -367,7 +368,8 @@ func (p *GetStatefulSetStatsInputParams) Process(c context.Context) error { p.output.Ready += int(obj.Status.ReadyReplicas) podMetricsList, err := cfg.GetMetricsClientSet().MetricsV1beta1().PodMetricses(p.NamespaceName).List(context.TODO(), metav1.ListOptions{LabelSelector: fmt.Sprintf("controller-revision-hash=%s", obj.Status.CurrentRevision)}) if err != nil { - panic(err.Error()) + log.Logger.Errorw("Failed to get pod metrics", "err", err.Error()) + return err } for _, podMetrics := range podMetricsList.Items { for _, container := range podMetrics.Containers { @@ -465,7 +467,8 @@ func (p *GetStatefulSetPodListInputParams) Process(c context.Context) error { p.output.PodList[idx].ManagedFields = nil podMetrics, err := cfg.GetMetricsClientSet().MetricsV1beta1().PodMetricses(p.NamespaceName).Get(context.TODO(), pod.Name, metav1.GetOptions{}) if err != nil { - panic(err.Error()) + log.Logger.Errorw("Failed to get pod metrics", "err", err.Error()) + return err } for _, container := range podMetrics.Containers { totalCPU += float64(container.Usage.Cpu().MilliValue()) / 1000.0 From bb26ef109fc15ecddfebb63b489cfc7a2d42a96f Mon Sep 17 00:00:00 2001 From: Nahid Date: Sun, 2 Feb 2025 17:09:40 +0600 Subject: [PATCH 34/64] chore: update user json response --- pkg/auth/models/cluster.go | 4 ++-- pkg/auth/models/user.go | 28 +++++++++++++++------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/pkg/auth/models/cluster.go b/pkg/auth/models/cluster.go index 2941fe0..bfcf6c8 100644 --- a/pkg/auth/models/cluster.go +++ b/pkg/auth/models/cluster.go @@ -9,7 +9,7 @@ import ( ) type Cluster struct { - ID primitive.ObjectID `json:"_id" bson:"_id,omitempty"` + ID primitive.ObjectID `json:"id" bson:"_id,omitempty"` Name string `json:"name" bson:"name"` ClusterType enum.ClusterType `json:"cluster_type" bson:"cluster_type"` // e.g., "MASTER", "AGENT" Token string `json:"-" bson:"token"` @@ -20,7 +20,7 @@ type Cluster struct { } type TokenValidation struct { - ID primitive.ObjectID `json:"_id" bson:"_id,omitempty"` + ID primitive.ObjectID `json:"id" bson:"_id,omitempty"` ClusterID primitive.ObjectID `json:"cluster_id" bson:"cluster_id"` Token string `json:"token" bson:"token"` IsValid bool `json:"is_valid" bson:"is_valid"` diff --git a/pkg/auth/models/user.go b/pkg/auth/models/user.go index a8bf2f5..cbd773e 100644 --- a/pkg/auth/models/user.go +++ b/pkg/auth/models/user.go @@ -2,6 +2,7 @@ package models import ( "github.com/go-playground/validator/v10" + "go.mongodb.org/mongo-driver/bson/primitive" "time" ) @@ -15,19 +16,20 @@ const ( // User represents user information and implements user validation and account states. type User struct { - CreatedAt time.Time `json:"created_at" bson:"created_at"` - UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` - Username string `json:"username" bson:"username" validate:"required,email"` - FirstName string `json:"first_name" bson:"first_name"` - LastName string `json:"last_name" bson:"last_name"` - Password string `json:"-" bson:"password" validate:"required,min=6,max=15"` - UserType UserType `json:"user_type" bson:"user_type" validate:"required,oneof=ADMIN USER"` - Roles []Role `json:"roles" bson:"roles"` - ClusterIdList []string `json:"clusterIdList" bson:"clusterIdList"` - UserIsActive bool `json:"user_is_active" bson:"user_is_active" validate:"required"` - IsVerified bool `json:"is_verified" bson:"is_verified" validate:"required"` - ForgotPasswordToken string `json:"forgot_password_token,omitempty" bson:"forgot_password_token"` - Phone string `json:"phone,omitempty" bson:"phone"` + ID primitive.ObjectID `json:"id" bson:"_id,omitempty"` + CreatedAt time.Time `json:"created_at" bson:"created_at"` + UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` + Username string `json:"username" bson:"username" validate:"required,email"` + FirstName string `json:"first_name" bson:"first_name"` + LastName string `json:"last_name" bson:"last_name"` + Password string `json:"-" bson:"password" validate:"required,min=6,max=15"` + UserType UserType `json:"user_type" bson:"user_type" validate:"required,oneof=ADMIN USER"` + Roles []Role `json:"roles" bson:"roles"` + ClusterIdList []string `json:"clusterIdList" bson:"clusterIdList"` + UserIsActive bool `json:"user_is_active" bson:"user_is_active" validate:"required"` + IsVerified bool `json:"is_verified" bson:"is_verified" validate:"required"` + ForgotPasswordToken string `json:"forgot_password_token,omitempty" bson:"forgot_password_token"` + Phone string `json:"phone,omitempty" bson:"phone"` } // Validate validates the UserInfo fields using the validator package. From 42a8e7d621b8749a1ea68da632a0e4d582bd34f3 Mon Sep 17 00:00:00 2001 From: Nahid Hasan <52489202+nahidhasan94@users.noreply.github.com> Date: Mon, 3 Feb 2025 11:24:51 +0600 Subject: [PATCH 35/64] chore: Add checking in API --- pkg/auth/services/user_service.go | 78 +++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 19 deletions(-) diff --git a/pkg/auth/services/user_service.go b/pkg/auth/services/user_service.go index 0c24685..a1d1d02 100644 --- a/pkg/auth/services/user_service.go +++ b/pkg/auth/services/user_service.go @@ -125,29 +125,69 @@ func (s *UserService) UpdateUser(userID string, updatedUser *models.User) error return fmt.Errorf("invalid user ID format: %w", err) } + // First fetch the existing user + var existingUser models.User filter := bson.M{"_id": objectID} - update := bson.M{ - "$set": bson.M{ - "firstname": updatedUser.FirstName, - "lastname": updatedUser.LastName, - "username": updatedUser.Username, - "password": utils.HashPassword(updatedUser.Password), - "usertype": updatedUser.UserType, - "roles": updatedUser.Roles, - "isactive": updatedUser.UserIsActive, - "isverified": updatedUser.IsVerified, - "phone": updatedUser.Phone, - "updatedat": time.Now(), - }, - } - - result, err := db.UserCollection.UpdateOne(context.Background(), filter, update) + err = db.UserCollection.FindOne(context.Background(), filter).Decode(&existingUser) if err != nil { - return fmt.Errorf("failed to update user: %w", err) + if err == mongo.ErrNoDocuments { + return errors.New("user not found") + } + return fmt.Errorf("failed to fetch existing user: %w", err) } - if result.MatchedCount == 0 { - return errors.New("user not found") + // Create update map with only non-empty fields + updateFields := bson.M{} + + if updatedUser.FirstName != "" { + updateFields["first_name"] = updatedUser.FirstName + } + if updatedUser.LastName != "" { + updateFields["last_name"] = updatedUser.LastName + } + if updatedUser.Username != "" { + updateFields["username"] = updatedUser.Username + } + if updatedUser.Password != "" { + updateFields["password"] = utils.HashPassword(updatedUser.Password) + } + if updatedUser.UserType != "" { + updateFields["user_type"] = updatedUser.UserType + } + if len(updatedUser.Roles) > 0 { + updateFields["roles"] = updatedUser.Roles + } + if len(updatedUser.ClusterIdList) > 0 { + updateFields["clusterIdList"] = updatedUser.ClusterIdList + } + // For boolean fields, we need to check if they were explicitly set in the update + if updatedUser.UserIsActive != existingUser.UserIsActive { + updateFields["user_is_active"] = updatedUser.UserIsActive + } + if updatedUser.IsVerified != existingUser.IsVerified { + updateFields["is_verified"] = updatedUser.IsVerified + } + if updatedUser.Phone != "" { + updateFields["phone"] = updatedUser.Phone + } + if updatedUser.ForgotPasswordToken != "" { + updateFields["forgot_password_token"] = updatedUser.ForgotPasswordToken + } + + // Always update the UpdatedAt timestamp + updateFields["updated_at"] = time.Now() + + // Only perform update if there are fields to update + if len(updateFields) > 0 { + update := bson.M{"$set": updateFields} + result, err := db.UserCollection.UpdateOne(context.Background(), filter, update) + if err != nil { + return fmt.Errorf("failed to update user: %w", err) + } + + if result.MatchedCount == 0 { + return errors.New("user not found") + } } return nil From 10a8d34027c7e5c655f8b4b7d7fc8826b6468d57 Mon Sep 17 00:00:00 2001 From: Toha Date: Mon, 3 Feb 2025 16:39:02 +0600 Subject: [PATCH 36/64] job, relplication controller tasks error and deployment, sts stats removed --- pkg/k8s/deployment.go | 80 +++--------------------- pkg/k8s/statefulset.go | 101 +++---------------------------- pkg/tasks/agent_task_selector.go | 61 +++++++++++++++++++ pkg/tasks/register_tasks.go | 2 +- 4 files changed, 78 insertions(+), 166 deletions(-) diff --git a/pkg/k8s/deployment.go b/pkg/k8s/deployment.go index 206960d..8ec5b7a 100644 --- a/pkg/k8s/deployment.go +++ b/pkg/k8s/deployment.go @@ -3,7 +3,6 @@ package k8s import ( "context" "errors" - "fmt" cfg "github.com/krack8/lighthouse/pkg/config" "github.com/krack8/lighthouse/pkg/log" appsv1 "k8s.io/api/apps/v1" @@ -307,11 +306,9 @@ func (svc *deploymentService) DeleteDeployment(c context.Context, p DeleteDeploy } type StatsDeployment struct { - Total int - Ready int - NotReady int - TotalCPU float64 - TotalMemory float64 + Total int + Ready int + NotReady int } func (s *StatsDeployment) New() *StatsDeployment { @@ -343,9 +340,6 @@ func (p *GetDeploymentStatsInputParams) Process(c context.Context) error { return err } - totalCPU := float64(0) - totalMemory := float64(0) - if p.Search != "" { listOptions.FieldSelector = fields.OneTermEqualSelector("metadata.name", p.Search).String() filteredDeployments := []appsv1.Deployment{} @@ -360,22 +354,9 @@ func (p *GetDeploymentStatsInputParams) Process(c context.Context) error { for _, obj := range filteredDeployments { p.output.Total += int(obj.Status.Replicas) p.output.Ready += int(obj.Status.ReadyReplicas) - podMetricsList, err := cfg.GetMetricsClientSet().MetricsV1beta1().PodMetricses(p.NamespaceName).List(context.TODO(), metav1.ListOptions{LabelSelector: fmt.Sprintf("app=%s", obj.Labels["app"])}) - if err != nil { - log.Logger.Errorw("Failed to get pod metrics", "err", err.Error()) - return err - } - for _, podMetrics := range podMetricsList.Items { - for _, container := range podMetrics.Containers { - totalCPU += float64(container.Usage.Cpu().MilliValue()) / 1000.0 - totalMemory += float64(container.Usage.Memory().Value()) / (1024 * 1024 * 1024) - } - } } p.output.NotReady = p.output.Total - p.output.Ready - p.output.TotalCPU = totalCPU - p.output.TotalMemory = totalMemory return nil } @@ -383,22 +364,8 @@ func (p *GetDeploymentStatsInputParams) Process(c context.Context) error { for _, obj := range deploymentList.Items { p.output.Total += int(obj.Status.Replicas) p.output.Ready += int(obj.Status.ReadyReplicas) - - podMetricsList, err := cfg.GetMetricsClientSet().MetricsV1beta1().PodMetricses(p.NamespaceName).List(context.TODO(), metav1.ListOptions{LabelSelector: fmt.Sprintf("app=%s", obj.Labels["app"])}) - if err != nil { - log.Logger.Errorw("Failed to get pod metrics", "err", err.Error()) - return err - } - for _, podMetrics := range podMetricsList.Items { - for _, container := range podMetrics.Containers { - totalCPU += float64(container.Usage.Cpu().MilliValue()) / 1000.0 - totalMemory += float64(container.Usage.Memory().Value()) / (1024 * 1024 * 1024) - } - } } p.output.NotReady = p.output.Total - p.output.Ready - p.output.TotalCPU = totalCPU - p.output.TotalMemory = totalMemory return nil } @@ -415,11 +382,9 @@ func (svc *deploymentService) GetDeploymentStats(c context.Context, p GetDeploym } type DeploymentPodOutput struct { - PodList []corev1.Pod - Resource string - Remaining int64 - TotalCPU float64 - TotalMemory float64 + PodList []corev1.Pod + Resource string + Remaining int64 } type GetDeploymentPodListInputParams struct { @@ -467,29 +432,15 @@ func (p *GetDeploymentPodListInputParams) Process(c context.Context) error { if p.Search != "" { listOptions.FieldSelector = fields.OneTermEqualSelector("metadata.name", p.Search).String() } - //FieldSelector: fmt.Sprintf("spec.ports[0].nodePort=%s", port), podList, err := podClient.List(context.Background(), listOptions) if err != nil { log.Logger.Errorw("Failed to get pod list", "err", err.Error()) return err } p.output.PodList = podList.Items - totalCPU := float64(0) - totalMemory := float64(0) - for idx, pod := range p.output.PodList { + for idx, _ := range p.output.PodList { p.output.PodList[idx].ManagedFields = nil - podMetrics, err := cfg.GetMetricsClientSet().MetricsV1beta1().PodMetricses(p.NamespaceName).Get(context.TODO(), pod.Name, metav1.GetOptions{}) - if err != nil { - log.Logger.Errorw("Failed to get pod metrics", "err", err.Error()) - return err - } - for _, container := range podMetrics.Containers { - totalCPU += float64(container.Usage.Cpu().MilliValue()) / 1000.0 - totalMemory += float64(container.Usage.Memory().Value()) / (1024 * 1024 * 1024) - } } - p.output.TotalCPU = totalCPU - p.output.TotalMemory = totalMemory remaining := podList.RemainingItemCount if remaining != nil { @@ -502,23 +453,6 @@ func (p *GetDeploymentPodListInputParams) Process(c context.Context) error { } else { return errors.New("unable to fetch pod list") } - ///// - //var replicasets []string - //for _, i := range output.Status.Conditions { - // if i.Type == "Progressing" { - // content := i.Message - // re := regexp.MustCompile(`\"(.*)\"`) - // match := re.FindStringSubmatch(content) - // if len(match) > 1 { - // fmt.Println("match found -", match[1]) - // replicasets = append(replicasets, match[1]) - // } else { - // fmt.Println("match not found") - // } - // } - //} - //fmt.Println(replicasets) - //// return nil } diff --git a/pkg/k8s/statefulset.go b/pkg/k8s/statefulset.go index 0ce8f45..6aad1ac 100644 --- a/pkg/k8s/statefulset.go +++ b/pkg/k8s/statefulset.go @@ -2,7 +2,6 @@ package k8s import ( "context" - "fmt" cfg "github.com/krack8/lighthouse/pkg/config" "github.com/krack8/lighthouse/pkg/log" appsv1 "k8s.io/api/apps/v1" @@ -290,11 +289,9 @@ func (svc *statefulSetService) DeleteStatefulSet(c context.Context, p DeleteStat } type Stats struct { - Total int - Ready int - NotReady int - TotalCPU float64 - TotalMemory float64 + Total int + Ready int + NotReady int } func (s *Stats) New() *Stats { @@ -319,8 +316,6 @@ func (p *GetStatefulSetStatsInputParams) Process(c context.Context) error { LabelSelector: labels.Set(labelSelector.MatchLabels).String(), } } - totalCPU := float64(0) - totalMemory := float64(0) statefulSetList, err := statefulSetClient.List(context.Background(), listOptions) if err != nil { @@ -342,22 +337,9 @@ func (p *GetStatefulSetStatsInputParams) Process(c context.Context) error { for _, obj := range filteredStatefulSet { p.output.Total += int(obj.Status.Replicas) p.output.Ready += int(obj.Status.ReadyReplicas) - podMetricsList, err := cfg.GetMetricsClientSet().MetricsV1beta1().PodMetricses(p.NamespaceName).List(context.TODO(), metav1.ListOptions{LabelSelector: fmt.Sprintf("controller-revision-hash=%s", obj.Status.CurrentRevision)}) - if err != nil { - log.Logger.Errorw("Failed to get pod metrics", "err", err.Error()) - return err - } - for _, podMetrics := range podMetricsList.Items { - for _, container := range podMetrics.Containers { - totalCPU += float64(container.Usage.Cpu().MilliValue()) / 1000.0 - totalMemory += float64(container.Usage.Memory().Value()) / (1024 * 1024 * 1024) - } - } } p.output.NotReady = p.output.Total - p.output.Ready - p.output.TotalCPU = totalCPU - p.output.TotalMemory = totalMemory return nil } @@ -366,22 +348,9 @@ func (p *GetStatefulSetStatsInputParams) Process(c context.Context) error { for _, obj := range statefulSetList.Items { p.output.Total += int(obj.Status.Replicas) p.output.Ready += int(obj.Status.ReadyReplicas) - podMetricsList, err := cfg.GetMetricsClientSet().MetricsV1beta1().PodMetricses(p.NamespaceName).List(context.TODO(), metav1.ListOptions{LabelSelector: fmt.Sprintf("controller-revision-hash=%s", obj.Status.CurrentRevision)}) - if err != nil { - log.Logger.Errorw("Failed to get pod metrics", "err", err.Error()) - return err - } - for _, podMetrics := range podMetricsList.Items { - for _, container := range podMetrics.Containers { - totalCPU += float64(container.Usage.Cpu().MilliValue()) / 1000.0 - totalMemory += float64(container.Usage.Memory().Value()) / (1024 * 1024 * 1024) - } - } } p.output.NotReady = p.output.Total - p.output.Ready - p.output.TotalCPU = totalCPU - p.output.TotalMemory = totalMemory return nil } @@ -398,22 +367,16 @@ func (svc *statefulSetService) GetStatefulSetStats(c context.Context, p GetState } type StatefulSetPodOutput struct { - PodList []corev1.Pod - Resource string - Remaining int64 - TotalCPU float64 - TotalMemory float64 + PodList []corev1.Pod + Resource string + Remaining int64 } type GetStatefulSetPodListInputParams struct { NamespaceName string StatefulSetName string - //Limit string - Labels map[string]string - //Search string - //CtrReHash string - //Continue string - output StatefulSetPodOutput + Labels map[string]string + output StatefulSetPodOutput } const ( @@ -430,11 +393,6 @@ func (p *GetStatefulSetPodListInputParams) Process(c context.Context) error { return err } podClient := cfg.GetKubeClientSet().CoreV1().Pods(p.NamespaceName) - //limit := cfg.PageLimit - //if p.Limit != "" { - // limit, _ = strconv.ParseInt(p.Limit, 10, 64) - //} - //listOptions := metav1.ListOptions{Limit: limit, Continue: p.Continue} listOptions := metav1.ListOptions{} if p.Labels == nil { p.Labels = make(map[string]string) @@ -443,59 +401,18 @@ func (p *GetStatefulSetPodListInputParams) Process(c context.Context) error { p.Labels[PodLabelKey] = statefulSet.Status.CurrentRevision labelSelector := metav1.LabelSelector{MatchLabels: p.Labels} - //if p.Labels != nil { - // listOptions = metav1.ListOptions{ - // LabelSelector: labels.Set(labelSelector.MatchLabels).String(), - // } - //} listOptions = metav1.ListOptions{ LabelSelector: labels.Set(labelSelector.MatchLabels).String(), } - //if p.Search != "" { - // listOptions.FieldSelector = fields.OneTermEqualSelector("metadata.name", p.Search).String() - //} - //FieldSelector: fmt.Sprintf("spec.ports[0].nodePort=%s", port), podList, err := podClient.List(context.Background(), listOptions) if err != nil { log.Logger.Errorw("Failed to get pod list", "err", err.Error()) return err } - totalCPU := float64(0) - totalMemory := float64(0) p.output.PodList = podList.Items - for idx, pod := range p.output.PodList { + for idx, _ := range p.output.PodList { p.output.PodList[idx].ManagedFields = nil - podMetrics, err := cfg.GetMetricsClientSet().MetricsV1beta1().PodMetricses(p.NamespaceName).Get(context.TODO(), pod.Name, metav1.GetOptions{}) - if err != nil { - log.Logger.Errorw("Failed to get pod metrics", "err", err.Error()) - return err - } - for _, container := range podMetrics.Containers { - totalCPU += float64(container.Usage.Cpu().MilliValue()) / 1000.0 - totalMemory += float64(container.Usage.Memory().Value()) / (1024 * 1024 * 1024) - } } - p.output.TotalCPU = totalCPU - p.output.TotalMemory = totalMemory - //var filteredPodList []corev1.Pod - //for idx, pod := range p.output.PodList { - // for _, ref := range pod.OwnerReferences { - // if ref.Kind == StatefulSetKind && ref.Name == p.StatefulSetName { - // p.output.PodList[idx].ManagedFields = nil - // filteredPodList = append(filteredPodList, p.output.PodList[idx]) - // } - // } - //} - //remaining := podList.RemainingItemCount - // - //if remaining != nil && len(filteredPodList) > 0 { - // p.output.Remaining = *remaining - //} else { - // p.output.Remaining = 0 - //} - // - //p.output.Resource = podList.Continue - //p.output.PodList = filteredPodList return nil } diff --git a/pkg/tasks/agent_task_selector.go b/pkg/tasks/agent_task_selector.go index dd290a9..a67f05f 100644 --- a/pkg/tasks/agent_task_selector.go +++ b/pkg/tasks/agent_task_selector.go @@ -1061,6 +1061,67 @@ func TaskSelector(task *pb.Task) (interface{}, error) { return nil, err } return res, nil + //job + case k8s.GetJobListInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetJobListInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.GetJobInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.GetJobInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeployJobInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeployJobInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil + case k8s.DeleteJobInputParams: + logTaskStarted(task) + err = json.Unmarshal([]byte(task.Input), &input) + if err != nil { + return nil, err + } + execute, exists := newTask.TaskFunc.(func(context.Context, k8s.DeleteJobInputParams) (interface{}, error)) + if !exists { + return nil, ErrTaskNotFound + } + res, err = execute(context.Background(), input) + if err != nil { + return nil, err + } + return res, nil //loadBalancer case k8s.GetLoadBalancerListInputParams: logTaskStarted(task) diff --git a/pkg/tasks/register_tasks.go b/pkg/tasks/register_tasks.go index bca00c0..49f0987 100644 --- a/pkg/tasks/register_tasks.go +++ b/pkg/tasks/register_tasks.go @@ -168,7 +168,7 @@ func InitTaskRegistry() { //replicationController RegisterTask(k8s.ReplicationControllerService().GetReplicationControllerList, k8s.GetReplicationControllerListInputParams{}) - RegisterTask(k8s.ReplicationControllerService().GetReplicationControllerList, k8s.GetReplicationControllerDetailsInputParams{}) + RegisterTask(k8s.ReplicationControllerService().GetReplicationControllerDetails, k8s.GetReplicationControllerDetailsInputParams{}) RegisterTask(k8s.ReplicationControllerService().DeployReplicationController, k8s.DeployReplicationControllerInputParams{}) RegisterTask(k8s.ReplicationControllerService().DeleteReplicationController, k8s.DeleteReplicationControllerInputParams{}) From bf570cf54efd88936320d874bef4ad2546a25acd Mon Sep 17 00:00:00 2001 From: Nahid Date: Mon, 3 Feb 2025 16:47:54 +0600 Subject: [PATCH 37/64] feat: Implement RBAC APIs --- pkg/auth/config/db.go | 44 ++- pkg/auth/config/permission_initializer.go | 120 +++++++ .../controllers/role_permission_controller.go | 122 ++++++- pkg/auth/enum/category.go | 9 - pkg/auth/enum/cluster_type.go | 8 - pkg/auth/enum/constrants.go | 17 + pkg/auth/enum/permision_constants.go | 33 ++ pkg/auth/enum/permission_mapping.go | 36 +++ pkg/auth/middlewares/auth.go | 10 +- pkg/auth/models/cluster.go | 10 +- pkg/auth/models/rbac.go | 27 +- pkg/auth/models/user.go | 10 +- pkg/auth/services/rbac_service.go | 151 ++++++++- pkg/auth/services/user_service.go | 2 + pkg/auth/utils/endpoints.go | 298 ++++++++++++++++++ pkg/auth/utils/jwt.go | 3 +- pkg/server/router/routes.go | 12 +- 17 files changed, 856 insertions(+), 56 deletions(-) create mode 100644 pkg/auth/config/permission_initializer.go delete mode 100644 pkg/auth/enum/category.go delete mode 100644 pkg/auth/enum/cluster_type.go create mode 100644 pkg/auth/enum/constrants.go create mode 100644 pkg/auth/enum/permision_constants.go create mode 100644 pkg/auth/enum/permission_mapping.go create mode 100644 pkg/auth/utils/endpoints.go diff --git a/pkg/auth/config/db.go b/pkg/auth/config/db.go index b31e98c..ccc8b7e 100644 --- a/pkg/auth/config/db.go +++ b/pkg/auth/config/db.go @@ -100,6 +100,12 @@ func InitializeDefaultUser() { } func InitRBAC() { + // Initialize permissions + initializer := NewPermissionInitializer(PermissionCollection) + if err := initializer.InitializePermissions(context.Background()); err != nil { + log.Fatal(err) + } + permissionCount, err := PermissionCollection.CountDocuments(context.Background(), bson.M{}) if err != nil { log.Fatalf("Error counting documents in users collection: %v", err) @@ -113,27 +119,43 @@ func InitRBAC() { var defaultPermissions []models.Permission if permissionCount == 0 { - // Example permissions + // Default permissions defaultPermissions = []models.Permission{ { ID: primitive.NewObjectID(), Name: "Create User", Description: "Permission to create a user", - Route: "/users", - Category: enum.DEFAULT, - Method: "POST", - CreatedAt: time.Now(), - UpdatedAt: time.Now(), + EndpointList: []models.Endpoint{ + { + Route: "/users", + Method: "POST", + }, + { + Route: "/users", + Method: "GET", + }, + }, + Category: enum.DEFAULT, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), }, { ID: primitive.NewObjectID(), Name: "Create Roles", Description: "Create Role", - Route: "/roles", - Method: "POST", - Category: enum.DEFAULT, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), + EndpointList: []models.Endpoint{ + { + Route: "/roles", + Method: "POST", + }, + { + Route: "/roles", + Method: "GET", + }, + }, + Category: enum.DEFAULT, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), }, } diff --git a/pkg/auth/config/permission_initializer.go b/pkg/auth/config/permission_initializer.go new file mode 100644 index 0000000..f943bc8 --- /dev/null +++ b/pkg/auth/config/permission_initializer.go @@ -0,0 +1,120 @@ +package config + +import ( + "context" + "fmt" + "github.com/krack8/lighthouse/pkg/auth/enum" + "github.com/krack8/lighthouse/pkg/auth/models" + "github.com/krack8/lighthouse/pkg/auth/utils" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "sync" + "time" +) + +// PermissionInitializer manages permission initialization +type PermissionInitializer struct { + permissionCollection *mongo.Collection + endpointRegistry map[enum.PermissionName]func() []models.Endpoint + mu sync.RWMutex +} + +// NewPermissionInitializer creates a new initializer instance +func NewPermissionInitializer(collection *mongo.Collection) *PermissionInitializer { + pi := &PermissionInitializer{ + permissionCollection: collection, + endpointRegistry: make(map[enum.PermissionName]func() []models.Endpoint), + } + pi.registerEndpoints() + return pi +} + +// registerEndpoints maps permission names to their endpoint functions +func (pi *PermissionInitializer) registerEndpoints() { + pi.endpointRegistry = map[enum.PermissionName]func() []models.Endpoint{ + enum.VIEW_NAMESPACE: utils.GetViewNamespaceEndpoints, + enum.MANAGE_NAMESPACE: utils.GetManageEndpointsEndpoints, + // Add more mappings + } +} + +// InitializePermissions initializes all permissions +func (pi *PermissionInitializer) InitializePermissions(ctx context.Context) error { + for permName, def := range enum.PermissionDefinitions { + endpointFunc, exists := pi.endpointRegistry[permName] + if !exists { + return fmt.Errorf("no endpoint function registered for permission: %s", permName) + } + + err := pi.initializePermission(ctx, models.Permission{ + Name: string(permName), + Description: string(def.Description), + Category: def.Category, + EndpointList: endpointFunc(), + CreatedBy: "SYSTEM", + UpdatedBy: "SYSTEM", + }) + if err != nil { + return fmt.Errorf("failed to initialize permission %s: %v", permName, err) + } + } + return nil +} + +// initializePermission handles initialization of a single permission +func (pi *PermissionInitializer) initializePermission(ctx context.Context, perm models.Permission) error { + pi.mu.Lock() + defer pi.mu.Unlock() + + exists, err := pi.permissionExists(ctx, perm.Name) + if err != nil { + return err + } + + if !exists { + perm.ID = primitive.NewObjectID() + perm.CreatedAt = time.Now() + perm.UpdatedAt = time.Now() + + _, err = pi.permissionCollection.InsertOne(ctx, perm) + return err + } + + return pi.updatePermissionEndpoints(ctx, perm.Name, perm.EndpointList) +} + +// permissionExists checks if a permission already exists +func (pi *PermissionInitializer) permissionExists(ctx context.Context, name string) (bool, error) { + count, err := pi.permissionCollection.CountDocuments(ctx, bson.M{"name": name}) + if err != nil { + return false, err + } + return count > 0, nil +} + +// updatePermissionEndpoints updates endpoints for an existing permission +func (pi *PermissionInitializer) updatePermissionEndpoints(ctx context.Context, name string, endpoints []models.Endpoint) error { + filter := bson.M{"name": name} + update := bson.M{ + "$set": bson.M{ + "endpoint-list": endpoints, + "updated_at": time.Now(), + "updated_by": "SYSTEM", + }, + } + _, err := pi.permissionCollection.UpdateOne(ctx, filter, update) + return err +} + +// GetPermissions returns all initialized permissions +func (pi *PermissionInitializer) GetPermissions(ctx context.Context) ([]models.Permission, error) { + var permissions []models.Permission + cursor, err := pi.permissionCollection.Find(ctx, bson.M{}) + if err != nil { + return nil, err + } + defer cursor.Close(ctx) + + return permissions, cursor.All(ctx, &permissions) +} diff --git a/pkg/auth/controllers/role_permission_controller.go b/pkg/auth/controllers/role_permission_controller.go index 17306b6..1f9b7f5 100644 --- a/pkg/auth/controllers/role_permission_controller.go +++ b/pkg/auth/controllers/role_permission_controller.go @@ -6,6 +6,7 @@ import ( "github.com/krack8/lighthouse/pkg/auth/models" "github.com/krack8/lighthouse/pkg/auth/services" "net/http" + "strings" ) type RbacController struct { @@ -60,7 +61,7 @@ func (rbac *RbacController) CreateRoleHandler(c *gin.Context) { func (rbac *RbacController) AssignRolesHandler(c *gin.Context) { var request struct { Username string `json:"username"` - Roles []string `json:"roles"` + RoleIds []string `json:"roleIds"` } // Parse the JSON request body @@ -70,11 +71,126 @@ func (rbac *RbacController) AssignRolesHandler(c *gin.Context) { } // Call the service to assign the roles - err := rbac.RbacService.AssignRole(request.Username, request.Roles) + err := rbac.RbacService.AssignRole(request.Username, request.RoleIds) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } - c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("Roles %v assigned to user '%s'", request.Roles, request.Username)}) + c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("Roles %v assigned to user '%s'", request.RoleIds, request.Username)}) +} + +// GetAllRolesHandler retrieves all roles +func (rbac *RbacController) GetAllRolesHandler(c *gin.Context) { + // Call the service to get all roles + roles, err := rbac.RbacService.GetAllRoles() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Error retrieving roles"}) + return + } + + c.JSON(http.StatusOK, gin.H{"roles": roles}) +} + +// GetRoleByIDHandler retrieves a specific role by its ID +func (rbac *RbacController) GetRoleByIDHandler(c *gin.Context) { + roleID := c.Param("id") + if roleID == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "Role ID is required"}) + return + } + + // Call the service to get the role by ID + role, err := rbac.RbacService.GetRoleByID(roleID) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Error retrieving role"}) + return + } + + if role == nil { + c.JSON(http.StatusNotFound, gin.H{"error": "Role not found"}) + return + } + + c.JSON(http.StatusOK, gin.H{"role": role}) +} + +// DeleteRoleHandler handles the deletion of a role by its ID +func (rbac *RbacController) DeleteRoleHandler(c *gin.Context) { + roleID := c.Param("id") + if roleID == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "Role ID is required"}) + return + } + + // Call the service to delete the role + err := rbac.RbacService.DeleteRoleByID(roleID) + if err != nil { + if strings.Contains(err.Error(), "no role found") { + c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusInternalServerError, gin.H{"error": "Error deleting role"}) + return + } + + c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("Role %s deleted successfully", roleID)}) +} + +// GetAllPermissionsHandler retrieves all permissions +func (rbac *RbacController) GetAllPermissionsHandler(c *gin.Context) { + // Call the service to get all permissions + permissions, err := rbac.RbacService.GetAllPermissions() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Error retrieving permissions"}) + return + } + + c.JSON(http.StatusOK, gin.H{"permissions": permissions}) +} + +// GetPermissionByIDHandler retrieves a specific permission by its ID +func (rbac *RbacController) GetPermissionByIDHandler(c *gin.Context) { + permissionID := c.Param("id") + if permissionID == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "Permission ID is required"}) + return + } + + // Call the service to get the permission by ID + permission, err := rbac.RbacService.GetPermissionByID(permissionID) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Error retrieving permission"}) + return + } + + if permission == nil { + c.JSON(http.StatusNotFound, gin.H{"error": "Permission not found"}) + return + } + + c.JSON(http.StatusOK, gin.H{"permission": permission}) +} + +// GetPermissionsByCategoryHandler retrieves permissions by their category +func (rbac *RbacController) GetPermissionsByCategoryHandler(c *gin.Context) { + category := c.Query("category") + if category == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "Category is required"}) + return + } + + // Call the service to get permissions by category + permissions, err := rbac.RbacService.GetPermissionsByCategory(category) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Error retrieving permissions"}) + return + } + + if len(permissions) == 0 { + c.JSON(http.StatusNotFound, gin.H{"error": "No permissions found for the given category"}) + return + } + + c.JSON(http.StatusOK, gin.H{"permissions": permissions}) } diff --git a/pkg/auth/enum/category.go b/pkg/auth/enum/category.go deleted file mode 100644 index b9bd935..0000000 --- a/pkg/auth/enum/category.go +++ /dev/null @@ -1,9 +0,0 @@ -package enum - -type PermissionCategory string - -const ( - DEFAULT PermissionCategory = "DEFAULT" - CLUSTER PermissionCategory = "CLUSTER" - HELM PermissionCategory = "HELM" -) diff --git a/pkg/auth/enum/cluster_type.go b/pkg/auth/enum/cluster_type.go deleted file mode 100644 index 4b7bc51..0000000 --- a/pkg/auth/enum/cluster_type.go +++ /dev/null @@ -1,8 +0,0 @@ -package enum - -type ClusterType string - -const ( - MASTER ClusterType = "MASTER" - AGENT ClusterType = "AGENT" -) diff --git a/pkg/auth/enum/constrants.go b/pkg/auth/enum/constrants.go new file mode 100644 index 0000000..dfd4e2f --- /dev/null +++ b/pkg/auth/enum/constrants.go @@ -0,0 +1,17 @@ +package enum + +// ClusterType represents different types of clusters +type ClusterType string + +// Status represents +type Status string + +const ( + MASTER ClusterType = "MASTER" + AGENT ClusterType = "AGENT" +) + +const ( + VALID Status = "V" + DELETED Status = "D" +) diff --git a/pkg/auth/enum/permision_constants.go b/pkg/auth/enum/permision_constants.go new file mode 100644 index 0000000..051ec70 --- /dev/null +++ b/pkg/auth/enum/permision_constants.go @@ -0,0 +1,33 @@ +package enum + +// PermissionCategory represents different types of permissions +type PermissionCategory string + +// PermissionName represents unique permission identifiers +type PermissionName string + +// PermissionDescription represents permission descriptions +type PermissionDescription string + +const ( + // Permission categories + DEFAULT PermissionCategory = "DEFAULT" + CLUSTER PermissionCategory = "CLUSTER" + HELM PermissionCategory = "HELM" + + // Permission names + VIEW_NAMESPACE PermissionName = "VIEW_NAMESPACE_ENDPOINTS" + MANAGE_NAMESPACE PermissionName = "MANAGE_NAMESPACE_ENDPOINTS" + VIEW_ENDPOINT_SLICE PermissionName = "VIEW_ENDPOINT_SLICE" + MANAGE_ENDPOINT_SLICE PermissionName = "MANAGE_ENDPOINT_SLICE" + VIEW_PDB PermissionName = "VIEW_PDB" + MANAGE_PDB PermissionName = "MANAGE_PDB" + + // Permission descriptions + VIEW_NAMESPACE_DESCRIPTION PermissionDescription = "Permission to view namespace endpoints" + MANAGE_NAMESPACE_DESCRIPTION PermissionDescription = "Permission to manage namespace endpoints" + VIEW_ENDPOINT_SLICE_DESCRIPTION PermissionDescription = "Permission to view endpoint slices" + MANAGE_ENDPOINT_SLICE_DESCRIPTION PermissionDescription = "Permission to manage endpoint slices" + VIEW_PDB_DESCRIPTION PermissionDescription = "Permission to view PDBs" + MANAGE_PDB_DESCRIPTION PermissionDescription = "Permission to manage PDBs" +) diff --git a/pkg/auth/enum/permission_mapping.go b/pkg/auth/enum/permission_mapping.go new file mode 100644 index 0000000..4404612 --- /dev/null +++ b/pkg/auth/enum/permission_mapping.go @@ -0,0 +1,36 @@ +package enum + +// PermissionDefinition represents a permission's metadata +type PermissionDefinition struct { + Description PermissionDescription + Category PermissionCategory +} + +// PermissionDefinitions maps permission names to their definitions +var PermissionDefinitions = map[PermissionName]PermissionDefinition{ + VIEW_NAMESPACE: { + Description: VIEW_NAMESPACE_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_NAMESPACE: { + Description: MANAGE_NAMESPACE_DESCRIPTION, + Category: CLUSTER, + }, + /* VIEW_ENDPOINT_SLICE: { + Description: VIEW_ENDPOINT_SLICE_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_ENDPOINT_SLICE: { + Description: MANAGE_ENDPOINT_SLICE_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_PDB: { + Description: VIEW_PDB_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_PDB: { + Description: MANAGE_PDB_DESCRIPTION, + Category: CLUSTER, + },*/ + // Add more permission definitions here +} diff --git a/pkg/auth/middlewares/auth.go b/pkg/auth/middlewares/auth.go index ba56e6c..fdc2be5 100644 --- a/pkg/auth/middlewares/auth.go +++ b/pkg/auth/middlewares/auth.go @@ -69,15 +69,19 @@ func AuthMiddleware() gin.HandlerFunc { c.Set("username", claims.Username) if user.UserType == models.RegularUser { // Collect all permissions of the user's roles - var permissions []string + var permissionEndpoints []string for _, role := range user.Roles { for _, perm := range role.Permissions { - permissions = append(permissions, perm.Route+":"+perm.Method) + // Iterate through each endpoint in the EndpointList + for _, endpoint := range perm.EndpointList { + permissionEndpoints = append(permissionEndpoints, + endpoint.Route+":"+endpoint.Method) + } } } // Check if user has permission for the requested route and method - if !services.CheckPermission(permissions, c.FullPath(), c.Request.Method) { + if !services.CheckPermission(permissionEndpoints, c.FullPath(), c.Request.Method) { c.JSON(http.StatusForbidden, gin.H{"error": "Permission denied"}) c.Abort() return diff --git a/pkg/auth/models/cluster.go b/pkg/auth/models/cluster.go index bfcf6c8..dbb6e54 100644 --- a/pkg/auth/models/cluster.go +++ b/pkg/auth/models/cluster.go @@ -11,12 +11,15 @@ import ( type Cluster struct { ID primitive.ObjectID `json:"id" bson:"_id,omitempty"` Name string `json:"name" bson:"name"` - ClusterType enum.ClusterType `json:"cluster_type" bson:"cluster_type"` // e.g., "MASTER", "AGENT" + ClusterType enum.ClusterType `json:"cluster_type" bson:"cluster_type"` // "MASTER", "AGENT" Token string `json:"-" bson:"token"` MasterClusterId string `json:"masterClusterId" bson:"masterClusterId"` + IsActive bool `json:"is_active" bson:"is_active"` + Status enum.Status `json:"status" bson:"status"` CreatedAt time.Time `json:"created_at" bson:"created_at"` UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` - IsActive bool `json:"is_active" bson:"is_active"` + CreatedBy string `json:"created_by" bson:"created_by"` + UpdatedBy string `json:"updated_by" bson:"updated_by"` } type TokenValidation struct { @@ -25,8 +28,11 @@ type TokenValidation struct { Token string `json:"token" bson:"token"` IsValid bool `json:"is_valid" bson:"is_valid"` ExpiresAt time.Time `json:"expires_at" bson:"expires_at"` + Status enum.Status `json:"status" bson:"status"` CreatedAt time.Time `json:"created_at" bson:"created_at"` UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` + CreatedBy string `json:"created_by" bson:"created_by"` + UpdatedBy string `json:"updated_by" bson:"updated_by"` } // Generate secure token diff --git a/pkg/auth/models/rbac.go b/pkg/auth/models/rbac.go index ed15e67..ae6aba7 100644 --- a/pkg/auth/models/rbac.go +++ b/pkg/auth/models/rbac.go @@ -8,14 +8,22 @@ import ( // Permission represents a specific action that can be performed on a resource type Permission struct { - ID primitive.ObjectID `json:"id" bson:"_id,omitempty"` - Name string `json:"name" bson:"name"` - Description string `json:"description" bson:"description"` - Route string `json:"route" bson:"route"` // URL path - Method string `json:"method" bson:"method"` // HTTP method (GET, POST, etc.) - Category enum.PermissionCategory `json:"category" bson:"category"` - CreatedAt time.Time `json:"created_at" bson:"created_at"` - UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` + ID primitive.ObjectID `json:"id" bson:"_id,omitempty"` + Name string `json:"name" bson:"name"` + Description string `json:"description" bson:"description"` + EndpointList []Endpoint `json:"endpoint_list" bson:"endpoint_list"` + Category enum.PermissionCategory `json:"category" bson:"category"` + Status enum.Status `json:"status" bson:"status"` + UserType UserType `json:"user_type" bson:"user_type" validate:"required,oneof=ADMIN USER"` + CreatedAt time.Time `json:"created_at" bson:"created_at"` + UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` + CreatedBy string `json:"created_by" bson:"created_by"` + UpdatedBy string `json:"updated_by" bson:"updated_by"` +} + +type Endpoint struct { + Route string `json:"route" bson:"route"` // URL path + Method string `json:"method" bson:"method"` // HTTP method (GET, POST, etc.) } // Role represents a user role with associated permissions @@ -24,6 +32,9 @@ type Role struct { Name string `json:"name" bson:"name"` Description string `json:"description" bson:"description"` Permissions []Permission `json:"permissions" bson:"permissions"` + Status enum.Status `json:"status" bson:"status"` CreatedAt time.Time `json:"created_at" bson:"created_at"` UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` + CreatedBy string `json:"created_by" bson:"created_by"` + UpdatedBy string `json:"updated_by" bson:"updated_by"` } diff --git a/pkg/auth/models/user.go b/pkg/auth/models/user.go index cbd773e..4e11783 100644 --- a/pkg/auth/models/user.go +++ b/pkg/auth/models/user.go @@ -2,6 +2,7 @@ package models import ( "github.com/go-playground/validator/v10" + "github.com/krack8/lighthouse/pkg/auth/enum" "go.mongodb.org/mongo-driver/bson/primitive" "time" ) @@ -17,19 +18,22 @@ const ( // User represents user information and implements user validation and account states. type User struct { ID primitive.ObjectID `json:"id" bson:"_id,omitempty"` - CreatedAt time.Time `json:"created_at" bson:"created_at"` - UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` Username string `json:"username" bson:"username" validate:"required,email"` FirstName string `json:"first_name" bson:"first_name"` LastName string `json:"last_name" bson:"last_name"` Password string `json:"-" bson:"password" validate:"required,min=6,max=15"` UserType UserType `json:"user_type" bson:"user_type" validate:"required,oneof=ADMIN USER"` Roles []Role `json:"roles" bson:"roles"` - ClusterIdList []string `json:"clusterIdList" bson:"clusterIdList"` + ClusterIdList []string `json:"cluster_ids" bson:"cluster_ids"` UserIsActive bool `json:"user_is_active" bson:"user_is_active" validate:"required"` IsVerified bool `json:"is_verified" bson:"is_verified" validate:"required"` ForgotPasswordToken string `json:"forgot_password_token,omitempty" bson:"forgot_password_token"` Phone string `json:"phone,omitempty" bson:"phone"` + Status enum.Status `json:"status" bson:"status"` + CreatedAt time.Time `json:"created_at" bson:"created_at"` + UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` + CreatedBy string `json:"created_by" bson:"created_by"` + UpdatedBy string `json:"updated_by" bson:"updated_by"` } // Validate validates the UserInfo fields using the validator package. diff --git a/pkg/auth/services/rbac_service.go b/pkg/auth/services/rbac_service.go index 58dcd1c..65badb3 100644 --- a/pkg/auth/services/rbac_service.go +++ b/pkg/auth/services/rbac_service.go @@ -49,7 +49,7 @@ func (r *RbacService) CreateRole(role models.Role) (primitive.ObjectID, error) { } // AssignRole assigns roles to a user. -func (r *RbacService) AssignRole(username string, roleNames []string) error { +func (r *RbacService) AssignRole(username string, roleIds []string) error { // Find user by username var user models.User err := db.UserCollection.FindOne(context.Background(), bson.M{"username": username}).Decode(&user) @@ -59,11 +59,12 @@ func (r *RbacService) AssignRole(username string, roleNames []string) error { // Loop through roleNames and add roles var roles []models.Role - for _, roleName := range roleNames { + for _, roleId := range roleIds { + objectID, err := primitive.ObjectIDFromHex(roleId) var role models.Role - err := db.RoleCollection.FindOne(context.Background(), bson.M{"name": roleName}).Decode(&role) + err = db.RoleCollection.FindOne(context.Background(), bson.M{"_id": objectID}).Decode(&role) if err != nil { - return fmt.Errorf("role '%s' not found", roleName) + return fmt.Errorf("role '%s' not found with Id", objectID) } roles = append(roles, role) } @@ -83,11 +84,153 @@ func (r *RbacService) AssignRole(username string, roleNames []string) error { // CheckPermission checks if a user has a specific permission for a route and method func CheckPermission(permissions []string, route, method string) bool { + // Normalize the input + method = strings.ToUpper(method) permissionKey := route + ":" + method + + // Check for exact matches first for _, perm := range permissions { if strings.EqualFold(perm, permissionKey) { return true } } + return false } + +// GetAllRoles retrieves all roles +func (r *RbacService) GetAllRoles() ([]models.Role, error) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + // Find all roles + cursor, err := db.RoleCollection.Find(ctx, bson.M{}) + if err != nil { + return nil, fmt.Errorf("failed to retrieve roles: %v", err) + } + defer cursor.Close(ctx) + + // Slice to store roles + var roles []models.Role + + // Decode all roles + if err = cursor.All(ctx, &roles); err != nil { + return nil, fmt.Errorf("failed to decode roles: %v", err) + } + + return roles, nil +} + +// GetRoleByID retrieves a specific role by its ID +func (r *RbacService) GetRoleByID(roleID string) (*models.Role, error) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + // Convert string ID to ObjectID + objectID, err := primitive.ObjectIDFromHex(roleID) + if err != nil { + return nil, fmt.Errorf("invalid role ID format: %v", err) + } + + // Find the role by ID + var role models.Role + err = db.RoleCollection.FindOne(ctx, bson.M{"_id": objectID}).Decode(&role) + if err != nil { + return nil, fmt.Errorf("failed to retrieve role: %v", err) + } + + return &role, nil +} + +// DeleteRoleByID deletes a role by its ID +func (r *RbacService) DeleteRoleByID(roleID string) error { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + // Convert string ID to ObjectID + objectID, err := primitive.ObjectIDFromHex(roleID) + if err != nil { + return fmt.Errorf("invalid role ID format: %v", err) + } + + // Delete the role + result, err := db.RoleCollection.DeleteOne(ctx, bson.M{"_id": objectID}) + if err != nil { + return fmt.Errorf("failed to delete role: %v", err) + } + + // Check if a role was actually deleted + if result.DeletedCount == 0 { + return fmt.Errorf("no role found with ID: %s", roleID) + } + + return nil +} + +// GetAllPermissions retrieves all permissions +func (r *RbacService) GetAllPermissions() ([]models.Permission, error) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + // Find all permissions + cursor, err := db.PermissionCollection.Find(ctx, bson.M{}) + if err != nil { + return nil, fmt.Errorf("failed to retrieve permissions: %v", err) + } + defer cursor.Close(ctx) + + // Slice to store permissions + var permissions []models.Permission + + // Decode all permissions + if err = cursor.All(ctx, &permissions); err != nil { + return nil, fmt.Errorf("failed to decode permissions: %v", err) + } + + return permissions, nil +} + +// GetPermissionByID retrieves a specific permission by its ID +func (r *RbacService) GetPermissionByID(permissionID string) (*models.Permission, error) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + // Convert string ID to ObjectID + objectID, err := primitive.ObjectIDFromHex(permissionID) + if err != nil { + return nil, fmt.Errorf("invalid permission ID format: %v", err) + } + + // Find the permission by ID + var permission models.Permission + err = db.PermissionCollection.FindOne(ctx, bson.M{"_id": objectID}).Decode(&permission) + if err != nil { + + return nil, fmt.Errorf("failed to retrieve permission: %v", err) + } + + return &permission, nil +} + +// GetPermissionsByCategory retrieves permissions by their category +func (r *RbacService) GetPermissionsByCategory(category string) ([]models.Permission, error) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + // Find permissions by category + cursor, err := db.PermissionCollection.Find(ctx, bson.M{"category": category}) + if err != nil { + return nil, fmt.Errorf("failed to retrieve permissions by category: %v", err) + } + defer cursor.Close(ctx) + + // Slice to store permissions + var permissions []models.Permission + + // Decode all permissions + if err = cursor.All(ctx, &permissions); err != nil { + return nil, fmt.Errorf("failed to decode permissions: %v", err) + } + + return permissions, nil +} diff --git a/pkg/auth/services/user_service.go b/pkg/auth/services/user_service.go index a1d1d02..292f2af 100644 --- a/pkg/auth/services/user_service.go +++ b/pkg/auth/services/user_service.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" db "github.com/krack8/lighthouse/pkg/auth/config" + "github.com/krack8/lighthouse/pkg/auth/enum" "github.com/krack8/lighthouse/pkg/auth/utils" "time" @@ -52,6 +53,7 @@ func (s *UserService) CreateUser(user *models.User) (*models.User, error) { user.CreatedAt = time.Now() user.UpdatedAt = time.Now() + user.Status = enum.VALID _, err := db.UserCollection.InsertOne(context.Background(), user) if err != nil { diff --git a/pkg/auth/utils/endpoints.go b/pkg/auth/utils/endpoints.go new file mode 100644 index 0000000..0d00bd7 --- /dev/null +++ b/pkg/auth/utils/endpoints.go @@ -0,0 +1,298 @@ +package utils + +import "github.com/krack8/lighthouse/pkg/auth/models" + +// GetCreateNamespaceEndpoints returns endpoints for creating K8s namespaces +func GetCreateNamespaceEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/namespace"}, + {Method: "GET", Route: "/api/v1/namespace"}, + {Method: "GET", Route: "/api/v1/namespace/@"}, + } +} + +// GetViewNamespaceEndpoints returns endpoints for viewing K8s namespaces +func GetViewNamespaceEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/namespace"}, + {Method: "GET", Route: "/api/v1/namespace/names"}, + {Method: "GET", Route: "/api/v1/namespace/@"}, + {Method: "GET", Route: "/api/v1/event"}, + } +} + +// GetUpdateNamespaceEndpoint returns endpoints for updating K8s namespace operations +func GetUpdateNamespaceEndpoint() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/namespace"}, + } +} + +// GetDeleteNamespaceEndpoint returns endpoints for deleting K8s namespace operations +func GetDeleteNamespaceEndpoint() []models.Endpoint { + return []models.Endpoint{ + {Method: "DELETE", Route: "/api/v1/namespace/@"}, + } +} + +// ViewDeploymentEndpoints returns a slice of endpoints for viewing deployments +func ViewDeploymentEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/deployment"}, + {Method: "GET", Route: "/api/v1/deployment/stats"}, + {Method: "GET", Route: "/api/v1/deployment/@"}, + {Method: "GET", Route: "/api/v1/deployment/@/pods"}, + } +} + +// ManageDeploymentEndpoints returns a slice of endpoints for managing deployments +func ManageDeploymentEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/deployment"}, + {Method: "DELETE", Route: "/api/v1/deployment/@"}, + } +} + +// ViewPodEndpoints returns a slice of endpoints for viewing pods +func ViewPodEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/pod"}, + {Method: "GET", Route: "/api/v1/pod/@"}, + {Method: "GET", Route: "/api/v1/pod/stats"}, + } +} + +// ManagePodEndpoints returns a slice of endpoints for managing pods +func ManagePodEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/pod"}, + {Method: "DELETE", Route: "/api/v1/pod/@"}, + } +} + +// ViewReplicaSetEndpoints returns a slice of endpoints for viewing replica sets +func ViewReplicaSetEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/replicaset"}, + {Method: "GET", Route: "/api/v1/replicaset/@"}, + } +} + +// ManageReplicaSetEndpoints returns a slice of endpoints for managing replica sets +func ManageReplicaSetEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/replicaset"}, + {Method: "DELETE", Route: "/api/v1/replicaset/@"}, + } +} + +// ViewStatefulSetEndpoints returns a slice of endpoints for viewing stateful sets +func ViewStatefulSetEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/statefulset"}, + {Method: "GET", Route: "/api/v1/statefulset/@"}, + {Method: "GET", Route: "/api/v1/statefulset/@/pods"}, + {Method: "GET", Route: "/api/v1/statefulset/stats"}, + } +} + +// ManageStatefulSetEndpoints returns a slice of endpoints for managing stateful sets +func ManageStatefulSetEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/statefulset"}, + {Method: "DELETE", Route: "/api/v1/statefulset/@"}, + } +} + +// ViewDaemonSetEndpoints returns a slice of endpoints for viewing daemon sets +func ViewDaemonSetEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/daemonset"}, + {Method: "GET", Route: "/api/v1/daemonset/stats"}, + {Method: "GET", Route: "/api/v1/daemonset/@"}, + } +} + +// ManageDaemonSetEndpoints returns a slice of endpoints for managing daemon sets +func ManageDaemonSetEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/daemonset"}, + {Method: "DELETE", Route: "/api/v1/daemonset/@"}, + } +} + +// ViewSecretEndpoints returns a slice of endpoints for viewing secrets +func ViewSecretEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/secret"}, + {Method: "GET", Route: "/api/v1/secret/@"}, + } +} + +// ManageSecretEndpoints returns a slice of endpoints for managing secrets +func ManageSecretEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/secret"}, + {Method: "DELETE", Route: "/api/v1/secret/@"}, + } +} + +// ViewConfigMapEndpoints returns a slice of endpoints for viewing config maps +func ViewConfigMapEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/config-map"}, + {Method: "GET", Route: "/api/v1/config-map/@"}, + } +} + +// ManageConfigMapEndpoints returns a slice of endpoints for managing config maps +func ManageConfigMapEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/config-map"}, + {Method: "DELETE", Route: "/api/v1/config-map/@"}, + } +} + +// ViewServiceAccountEndpoints returns a slice of endpoints for viewing service accounts +func ViewServiceAccountEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/service-account"}, + {Method: "GET", Route: "/api/v1/service-account/@"}, + } +} + +// ManageServiceAccountEndpoints returns a slice of endpoints for managing service accounts +func ManageServiceAccountEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/service-account"}, + {Method: "GET", Route: "/api/v1/service-account/@"}, + } +} + +// ViewServiceEndpoints returns a slice of endpoints for viewing services +func ViewServiceEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/service"}, + {Method: "GET", Route: "/api/v1/service/@"}, + } +} + +// ManageServiceEndpoints returns a slice of endpoints for managing services +func ManageServiceEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/service"}, + {Method: "DELETE", Route: "/api/v1/service/@"}, + } +} + +// ManageIngressEndpoints returns a slice of endpoints for managing ingress +func ManageIngressEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/ingress"}, + {Method: "DELETE", Route: "/api/v1/ingress/@"}, + } +} + +// ManageCertificateEndpoints returns a slice of endpoints for managing certificates +func ManageCertificateEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/certificate"}, + {Method: "DELETE", Route: "/api/v1/certificate/@"}, + } +} + +// ManageRoleEndpoints returns a slice of endpoints for managing roles +func ManageRoleEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/role"}, + {Method: "DELETE", Route: "/api/v1/role/@"}, + } +} + +// ManageRoleBindingEndpoints returns a slice of endpoints for managing role bindings +func ManageRoleBindingEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/role-binding"}, + {Method: "DELETE", Route: "/api/v1/role-binding/@"}, + } +} + +// ManageJobEndpoints returns a slice of endpoints for managing jobs +func ManageJobEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/job"}, + {Method: "DELETE", Route: "/api/v1/job/@"}, + } +} + +// ManageCronJobEndpoints returns a slice of endpoints for managing cron jobs +func ManageCronJobEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/cronjob"}, + {Method: "DELETE", Route: "/api/v1/cronjob/@"}, + } +} + +// GetManageEndpointsEndpoints returns endpoints for managing endpoints +func GetManageEndpointsEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/endpoints"}, + {Method: "DELETE", Route: "/api/v1/endpoints/@"}, + } +} + +// GetViewEndpointSliceEndpoints returns endpoints for viewing endpoint slices +func GetViewEndpointSliceEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/endpoint-slice"}, + {Method: "GET", Route: "/api/v1/endpoint-slice/@"}, + } +} + +// ViewNamespacePDB returns endpoints for viewing PDBs +func ViewNamespacePDB() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/PDB"}, + {Method: "GET", Route: "/api/v1/PDB/@"}, + } +} + +// ManageNamespacePDB returns endpoints for managing PDBs +func ManageNamespacePDB() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/PDB"}, + {Method: "DELETE", Route: "/api/v1/PDB/@"}, + } +} + +// ViewNamespaceControllerRevision returns endpoints for viewing controller revisions +func ViewNamespaceControllerRevision() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/controller-revision"}, + {Method: "GET", Route: "/api/v1/controller-revision/@"}, + } +} + +// ManageNamespaceControllerRevision returns endpoints for managing controller revisions +func ManageNamespaceControllerRevision() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/controller-revision"}, + {Method: "DELETE", Route: "/api/v1/controller-revision/@"}, + } +} + +// ViewNamespaceReplicationController returns endpoints for viewing replication controllers +func ViewNamespaceReplicationController() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/replication-controller"}, + {Method: "GET", Route: "/api/v1/replication-controller/@"}, + } +} + +// ManageNamespaceReplicationController returns endpoints for managing replication controllers +func ManageNamespaceReplicationController() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/replication-controller"}, + {Method: "DELETE", Route: "/api/v1/replication-controller/@"}, + } +} diff --git a/pkg/auth/utils/jwt.go b/pkg/auth/utils/jwt.go index 5bc0a19..556c50b 100644 --- a/pkg/auth/utils/jwt.go +++ b/pkg/auth/utils/jwt.go @@ -7,8 +7,7 @@ import ( ) type Claims struct { - Username string `json:"username"` - Permissions []string `json:"permissions"` + Username string `json:"username"` jwt.RegisteredClaims } diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index 08a2963..72c397b 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -27,9 +27,15 @@ func AddApiRoutes(httpRg *gin.RouterGroup) { httpRg.GET("/clusters/:id", authApi.ClusterController.GetClusterHandler) // RBAC routes - httpRg.POST("/rbac/permissions", authApi.RbacController.CreatePermissionHandler) - httpRg.POST("/rbac/roles", authApi.RbacController.CreateRoleHandler) - httpRg.POST("/rbac/assign-roles", authApi.RbacController.AssignRolesHandler) + //httpRg.POST("/permissions", authApi.RbacController.CreatePermissionHandler) /test-api to create permission for dev + httpRg.POST("/roles", authApi.RbacController.CreateRoleHandler) + httpRg.POST("/assign-roles", authApi.RbacController.AssignRolesHandler) + httpRg.GET("/permissions", authApi.RbacController.GetAllPermissionsHandler) + httpRg.GET("/permissions/:id", authApi.RbacController.GetPermissionByIDHandler) + httpRg.GET("/permissions/:category", authApi.RbacController.GetPermissionsByCategoryHandler) + httpRg.GET("/roles", authApi.RbacController.GetAllRolesHandler) + httpRg.GET("/roles/:id", authApi.RbacController.GetRoleByIDHandler) + httpRg.DELETE("/roles/:id", authApi.RbacController.DeleteRoleHandler) // Namespace httpRg.GET("/namespace", api.NamespaceController().GetNamespaceList) From a1d23ac7c1cefe5648aa53bbba9df335449952bd Mon Sep 17 00:00:00 2001 From: Nahid Date: Mon, 3 Feb 2025 16:52:02 +0600 Subject: [PATCH 38/64] chore:minor route fix --- pkg/server/router/routes.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index 72c397b..db8da8d 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -32,7 +32,6 @@ func AddApiRoutes(httpRg *gin.RouterGroup) { httpRg.POST("/assign-roles", authApi.RbacController.AssignRolesHandler) httpRg.GET("/permissions", authApi.RbacController.GetAllPermissionsHandler) httpRg.GET("/permissions/:id", authApi.RbacController.GetPermissionByIDHandler) - httpRg.GET("/permissions/:category", authApi.RbacController.GetPermissionsByCategoryHandler) httpRg.GET("/roles", authApi.RbacController.GetAllRolesHandler) httpRg.GET("/roles/:id", authApi.RbacController.GetRoleByIDHandler) httpRg.DELETE("/roles/:id", authApi.RbacController.DeleteRoleHandler) From a1cc54883e58c5efbf2b37429df48a4837bea481 Mon Sep 17 00:00:00 2001 From: Nahid Date: Mon, 3 Feb 2025 19:41:41 +0600 Subject: [PATCH 39/64] feat: category based permission implementation --- pkg/auth/config/db.go | 82 ++++++------------ pkg/auth/config/permission_initializer.go | 14 +-- .../controllers/role_permission_controller.go | 20 +++++ pkg/auth/dto/permission_response_dto.go | 17 ++++ pkg/auth/enum/constrants.go | 2 + pkg/auth/enum/permision_constants.go | 2 + pkg/auth/enum/permission_mapping.go | 4 + pkg/auth/models/rbac.go | 1 - pkg/auth/services/rbac_service.go | 86 ++++++++++++++++++- pkg/auth/utils/endpoints.go | 7 ++ pkg/server/router/routes.go | 1 + 11 files changed, 170 insertions(+), 66 deletions(-) create mode 100644 pkg/auth/dto/permission_response_dto.go diff --git a/pkg/auth/config/db.go b/pkg/auth/config/db.go index ccc8b7e..57df95a 100644 --- a/pkg/auth/config/db.go +++ b/pkg/auth/config/db.go @@ -84,6 +84,9 @@ func InitializeDefaultUser() { UserIsActive: true, IsVerified: true, Phone: "1234567890", + Status: enum.VALID, + CreatedBy: string(enum.SYSTEM), + UpdatedBy: string(enum.SYSTEM), CreatedAt: time.Now(), UpdatedAt: time.Now(), } @@ -106,9 +109,11 @@ func InitRBAC() { log.Fatal(err) } - permissionCount, err := PermissionCollection.CountDocuments(context.Background(), bson.M{}) + var defaultPermission models.Permission + // Find permissions by name + err := PermissionCollection.FindOne(context.Background(), bson.M{"name": string(enum.DEFAULT_PERMISSION)}).Decode(&defaultPermission) if err != nil { - log.Fatalf("Error counting documents in users collection: %v", err) + log.Fatalf("Default permission not found: %v", err) } roleCount, err := RoleCollection.CountDocuments(context.Background(), bson.M{}) @@ -118,67 +123,18 @@ func InitRBAC() { var defaultPermissions []models.Permission - if permissionCount == 0 { - // Default permissions - defaultPermissions = []models.Permission{ - { - ID: primitive.NewObjectID(), - Name: "Create User", - Description: "Permission to create a user", - EndpointList: []models.Endpoint{ - { - Route: "/users", - Method: "POST", - }, - { - Route: "/users", - Method: "GET", - }, - }, - Category: enum.DEFAULT, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - }, - { - ID: primitive.NewObjectID(), - Name: "Create Roles", - Description: "Create Role", - EndpointList: []models.Endpoint{ - { - Route: "/roles", - Method: "POST", - }, - { - Route: "/roles", - Method: "GET", - }, - }, - Category: enum.DEFAULT, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - }, - } - - // Convert the []models.Permission to []interface{} - var permissionsInterface []interface{} - for _, perm := range defaultPermissions { - permissionsInterface = append(permissionsInterface, perm) - } - - // Insert the Default Permissions into the collection - _, err := PermissionCollection.InsertMany(context.Background(), permissionsInterface) - if err != nil { - log.Printf("Error inserting permissions: %v", err) - } - } + defaultPermissions = append(defaultPermissions, defaultPermission) if roleCount == 0 { // Example role with permissions defaultRole := models.Role{ ID: primitive.NewObjectID(), - Name: "Admin", - Description: "Administrator role with all permissions", + Name: "DEFAULT_ROLE", + Description: "Basic API Permissions", Permissions: defaultPermissions, + Status: enum.VALID, + CreatedBy: string(enum.SYSTEM), + UpdatedBy: string(enum.SYSTEM), CreatedAt: time.Now(), UpdatedAt: time.Now(), } @@ -206,6 +162,9 @@ func InitializeClusters() { Name: "master-cluster", ClusterType: enum.MASTER, Token: masterToken, + Status: enum.VALID, + CreatedBy: string(enum.SYSTEM), + UpdatedBy: string(enum.SYSTEM), CreatedAt: time.Now(), UpdatedAt: time.Now(), IsActive: true, @@ -218,6 +177,9 @@ func InitializeClusters() { Name: "agent-cluster", ClusterType: enum.AGENT, Token: agentToken, + Status: enum.VALID, + CreatedBy: string(enum.SYSTEM), + UpdatedBy: string(enum.SYSTEM), CreatedAt: time.Now(), UpdatedAt: time.Now(), IsActive: true, @@ -239,6 +201,9 @@ func InitializeClusters() { Token: masterToken, IsValid: true, ExpiresAt: time.Now().AddDate(1, 0, 0), // Token valid for 1 year + Status: enum.VALID, + CreatedBy: string(enum.SYSTEM), + UpdatedBy: string(enum.SYSTEM), CreatedAt: time.Now(), UpdatedAt: time.Now(), } @@ -249,6 +214,9 @@ func InitializeClusters() { Token: agentToken, IsValid: true, ExpiresAt: time.Now().AddDate(1, 0, 0), // Token valid for 1 year + Status: enum.VALID, + CreatedBy: string(enum.SYSTEM), + UpdatedBy: string(enum.SYSTEM), CreatedAt: time.Now(), UpdatedAt: time.Now(), } diff --git a/pkg/auth/config/permission_initializer.go b/pkg/auth/config/permission_initializer.go index f943bc8..6acb23a 100644 --- a/pkg/auth/config/permission_initializer.go +++ b/pkg/auth/config/permission_initializer.go @@ -30,11 +30,12 @@ func NewPermissionInitializer(collection *mongo.Collection) *PermissionInitializ return pi } -// registerEndpoints maps permission names to their endpoint functions +// registerEndpoints maps permission names to their endpoint functions. register addational func (pi *PermissionInitializer) registerEndpoints() { pi.endpointRegistry = map[enum.PermissionName]func() []models.Endpoint{ - enum.VIEW_NAMESPACE: utils.GetViewNamespaceEndpoints, - enum.MANAGE_NAMESPACE: utils.GetManageEndpointsEndpoints, + enum.DEFAULT_PERMISSION: utils.GetDefaultEndpoints, + enum.VIEW_NAMESPACE: utils.GetViewNamespaceEndpoints, + enum.MANAGE_NAMESPACE: utils.GetManageEndpointsEndpoints, // Add more mappings } } @@ -52,8 +53,11 @@ func (pi *PermissionInitializer) InitializePermissions(ctx context.Context) erro Description: string(def.Description), Category: def.Category, EndpointList: endpointFunc(), - CreatedBy: "SYSTEM", - UpdatedBy: "SYSTEM", + Status: enum.VALID, + CreatedBy: string(enum.SYSTEM), + UpdatedBy: string(enum.SYSTEM), + CreatedAt: time.Now(), + UpdatedAt: time.Now(), }) if err != nil { return fmt.Errorf("failed to initialize permission %s: %v", permName, err) diff --git a/pkg/auth/controllers/role_permission_controller.go b/pkg/auth/controllers/role_permission_controller.go index 1f9b7f5..c410c5a 100644 --- a/pkg/auth/controllers/role_permission_controller.go +++ b/pkg/auth/controllers/role_permission_controller.go @@ -194,3 +194,23 @@ func (rbac *RbacController) GetPermissionsByCategoryHandler(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"permissions": permissions}) } + +// GetUserPermissionsHandler handles the permission request for a user +func (rbac *RbacController) GetUserPermissionsHandler(c *gin.Context) { + username, exists := c.Get("username") + if !exists { + c.JSON(http.StatusBadRequest, gin.H{"error": "Username not found in context.Please Enable AUTH"}) + return + } + // username is of type interface{}, so cast it to string + usernameStr := username.(string) + // Get permissions + permissions, err := rbac.RbacService.GetPermissionsByUserType(usernameStr) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Error retrieving permissions"}) + return + } + + // Return permissions directly without the "data" wrapper + c.JSON(http.StatusOK, permissions) +} diff --git a/pkg/auth/dto/permission_response_dto.go b/pkg/auth/dto/permission_response_dto.go new file mode 100644 index 0000000..2443648 --- /dev/null +++ b/pkg/auth/dto/permission_response_dto.go @@ -0,0 +1,17 @@ +package dto + +import "go.mongodb.org/mongo-driver/bson/primitive" + +// PermissionResponse represents the formatted API response +type PermissionResponse struct { + DEFAULT []PermissionDTO `json:"DEFAULT"` + CLUSTER []PermissionDTO `json:"CLUSTER"` + HelmApps []PermissionDTO `json:"HELM_APPS"` +} + +// PermissionDTO represents the simplified permission response +type PermissionDTO struct { + ID primitive.ObjectID `json:"id"` + Name string `json:"name"` + Description string `json:"description"` +} diff --git a/pkg/auth/enum/constrants.go b/pkg/auth/enum/constrants.go index dfd4e2f..63cfadb 100644 --- a/pkg/auth/enum/constrants.go +++ b/pkg/auth/enum/constrants.go @@ -14,4 +14,6 @@ const ( const ( VALID Status = "V" DELETED Status = "D" + HIDDEN Status = "H" + SYSTEM Status = "SYSTEM" ) diff --git a/pkg/auth/enum/permision_constants.go b/pkg/auth/enum/permision_constants.go index 051ec70..2e4a82f 100644 --- a/pkg/auth/enum/permision_constants.go +++ b/pkg/auth/enum/permision_constants.go @@ -16,6 +16,7 @@ const ( HELM PermissionCategory = "HELM" // Permission names + DEFAULT_PERMISSION PermissionName = "DEFAULT_PERMISSION" VIEW_NAMESPACE PermissionName = "VIEW_NAMESPACE_ENDPOINTS" MANAGE_NAMESPACE PermissionName = "MANAGE_NAMESPACE_ENDPOINTS" VIEW_ENDPOINT_SLICE PermissionName = "VIEW_ENDPOINT_SLICE" @@ -24,6 +25,7 @@ const ( MANAGE_PDB PermissionName = "MANAGE_PDB" // Permission descriptions + DEFAULT_PERMISSION_DESCRIPTION PermissionDescription = "DEFAULT_PERMISSION" VIEW_NAMESPACE_DESCRIPTION PermissionDescription = "Permission to view namespace endpoints" MANAGE_NAMESPACE_DESCRIPTION PermissionDescription = "Permission to manage namespace endpoints" VIEW_ENDPOINT_SLICE_DESCRIPTION PermissionDescription = "Permission to view endpoint slices" diff --git a/pkg/auth/enum/permission_mapping.go b/pkg/auth/enum/permission_mapping.go index 4404612..cafa7b9 100644 --- a/pkg/auth/enum/permission_mapping.go +++ b/pkg/auth/enum/permission_mapping.go @@ -8,6 +8,10 @@ type PermissionDefinition struct { // PermissionDefinitions maps permission names to their definitions var PermissionDefinitions = map[PermissionName]PermissionDefinition{ + DEFAULT_PERMISSION: { + Description: DEFAULT_PERMISSION_DESCRIPTION, + Category: DEFAULT, + }, VIEW_NAMESPACE: { Description: VIEW_NAMESPACE_DESCRIPTION, Category: CLUSTER, diff --git a/pkg/auth/models/rbac.go b/pkg/auth/models/rbac.go index ae6aba7..f47de9b 100644 --- a/pkg/auth/models/rbac.go +++ b/pkg/auth/models/rbac.go @@ -14,7 +14,6 @@ type Permission struct { EndpointList []Endpoint `json:"endpoint_list" bson:"endpoint_list"` Category enum.PermissionCategory `json:"category" bson:"category"` Status enum.Status `json:"status" bson:"status"` - UserType UserType `json:"user_type" bson:"user_type" validate:"required,oneof=ADMIN USER"` CreatedAt time.Time `json:"created_at" bson:"created_at"` UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` CreatedBy string `json:"created_by" bson:"created_by"` diff --git a/pkg/auth/services/rbac_service.go b/pkg/auth/services/rbac_service.go index 65badb3..24b452d 100644 --- a/pkg/auth/services/rbac_service.go +++ b/pkg/auth/services/rbac_service.go @@ -5,9 +5,12 @@ import ( "errors" "fmt" db "github.com/krack8/lighthouse/pkg/auth/config" + "github.com/krack8/lighthouse/pkg/auth/dto" + "github.com/krack8/lighthouse/pkg/auth/enum" "github.com/krack8/lighthouse/pkg/auth/models" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" "strings" "time" ) @@ -108,7 +111,12 @@ func (r *RbacService) GetAllRoles() ([]models.Role, error) { if err != nil { return nil, fmt.Errorf("failed to retrieve roles: %v", err) } - defer cursor.Close(ctx) + defer func(cursor *mongo.Cursor, ctx context.Context) { + err := cursor.Close(ctx) + if err != nil { + + } + }(cursor, ctx) // Slice to store roles var roles []models.Role @@ -177,7 +185,12 @@ func (r *RbacService) GetAllPermissions() ([]models.Permission, error) { if err != nil { return nil, fmt.Errorf("failed to retrieve permissions: %v", err) } - defer cursor.Close(ctx) + defer func(cursor *mongo.Cursor, ctx context.Context) { + err := cursor.Close(ctx) + if err != nil { + + } + }(cursor, ctx) // Slice to store permissions var permissions []models.Permission @@ -222,7 +235,12 @@ func (r *RbacService) GetPermissionsByCategory(category string) ([]models.Permis if err != nil { return nil, fmt.Errorf("failed to retrieve permissions by category: %v", err) } - defer cursor.Close(ctx) + defer func(cursor *mongo.Cursor, ctx context.Context) { + err := cursor.Close(ctx) + if err != nil { + + } + }(cursor, ctx) // Slice to store permissions var permissions []models.Permission @@ -234,3 +252,65 @@ func (r *RbacService) GetPermissionsByCategory(category string) ([]models.Permis return permissions, nil } + +func (r *RbacService) GetPermissionsByUserType(username string) (*dto.PermissionResponse, error) { + if username == "" { + return nil, errors.New("username cannot be empty") + } + user, _ := GetUserByUsername(username) + + if user == nil { + return nil, errors.New("user do not exists") + } + + // Initialize response + response := &dto.PermissionResponse{ + DEFAULT: make([]dto.PermissionDTO, 0), + CLUSTER: make([]dto.PermissionDTO, 0), + HelmApps: make([]dto.PermissionDTO, 0), + } + + // Create filter for Valid permissions + filter := bson.M{ + "status": "V", + } + + // Fetch permissions from database + cursor, err := db.PermissionCollection.Find(context.Background(), filter) + if err != nil { + return nil, err + } + defer func(cursor *mongo.Cursor, ctx context.Context) { + err := cursor.Close(ctx) + if err != nil { + + } + }(cursor, context.Background()) + + // Process permissions + var permissions []models.Permission + if err := cursor.All(context.Background(), &permissions); err != nil { + return nil, err + } + + // Group permissions by category + for _, perm := range permissions { + dto := dto.PermissionDTO{ + ID: perm.ID, + Name: perm.Name, + Description: perm.Description, + } + + switch perm.Category { + case enum.DEFAULT: + response.DEFAULT = append(response.DEFAULT, dto) + case enum.CLUSTER: + response.CLUSTER = append(response.CLUSTER, dto) + case enum.HELM: + response.HelmApps = append(response.HelmApps, dto) + } + //add category here + } + + return response, nil +} diff --git a/pkg/auth/utils/endpoints.go b/pkg/auth/utils/endpoints.go index 0d00bd7..b364435 100644 --- a/pkg/auth/utils/endpoints.go +++ b/pkg/auth/utils/endpoints.go @@ -2,6 +2,13 @@ package utils import "github.com/krack8/lighthouse/pkg/auth/models" +// GetDefaultEndpoints returns endpoints for creating K8s namespaces +func GetDefaultEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/clusters"}, + } +} + // GetCreateNamespaceEndpoints returns endpoints for creating K8s namespaces func GetCreateNamespaceEndpoints() []models.Endpoint { return []models.Endpoint{ diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index db8da8d..da39b31 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -32,6 +32,7 @@ func AddApiRoutes(httpRg *gin.RouterGroup) { httpRg.POST("/assign-roles", authApi.RbacController.AssignRolesHandler) httpRg.GET("/permissions", authApi.RbacController.GetAllPermissionsHandler) httpRg.GET("/permissions/:id", authApi.RbacController.GetPermissionByIDHandler) + httpRg.GET("/permissions/users", authApi.RbacController.GetUserPermissionsHandler) httpRg.GET("/roles", authApi.RbacController.GetAllRolesHandler) httpRg.GET("/roles/:id", authApi.RbacController.GetRoleByIDHandler) httpRg.DELETE("/roles/:id", authApi.RbacController.DeleteRoleHandler) From 6024ed13032f3ba520f0dd80c4feae5fa5c20c56 Mon Sep 17 00:00:00 2001 From: Nahid Hasan <52489202+nahidhasan94@users.noreply.github.com> Date: Tue, 4 Feb 2025 13:43:39 +0600 Subject: [PATCH 40/64] chore: Add Default Permissions and modify user payload --- .../controllers/role_permission_controller.go | 40 +++- pkg/auth/controllers/user_controller.go | 40 +++- pkg/auth/dto/role_dto.go | 13 ++ pkg/auth/dto/user_dto.go | 19 ++ pkg/auth/enum/permision_constants.go | 76 +++++++- pkg/auth/services/rbac_service.go | 12 ++ pkg/auth/services/user_service.go | 35 +++- pkg/auth/utils/endpoints.go | 171 +++++++++--------- 8 files changed, 310 insertions(+), 96 deletions(-) create mode 100644 pkg/auth/dto/role_dto.go create mode 100644 pkg/auth/dto/user_dto.go diff --git a/pkg/auth/controllers/role_permission_controller.go b/pkg/auth/controllers/role_permission_controller.go index c410c5a..bba1ad0 100644 --- a/pkg/auth/controllers/role_permission_controller.go +++ b/pkg/auth/controllers/role_permission_controller.go @@ -3,10 +3,12 @@ package controllers import ( "fmt" "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/auth/dto" "github.com/krack8/lighthouse/pkg/auth/models" "github.com/krack8/lighthouse/pkg/auth/services" "net/http" "strings" + "time" ) type RbacController struct { @@ -38,21 +40,53 @@ func (rbac *RbacController) CreatePermissionHandler(c *gin.Context) { c.JSON(http.StatusCreated, gin.H{"permission_id": permissionID}) } +// Helper function to convert string slice to Permission slice +func convertPermissionsToModels(permissions []string) []models.Permission { + permissionModels := make([]models.Permission, 0, len(permissions)) + + for _, p := range permissions { + if strings.TrimSpace(p) != "" { + permissionModels = append(permissionModels, models.Permission{ + Name: strings.TrimSpace(p), + }) + } + } + + return permissionModels +} + // CreateRoleHandler handles the creation of a new role func (rbac *RbacController) CreateRoleHandler(c *gin.Context) { - var role models.Role - if err := c.ShouldBindJSON(&role); err != nil { + var roleDTO dto.RoleDTO + if err := c.ShouldBindJSON(&roleDTO); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"}) return } + // Validate permissions slice + if len(roleDTO.Permissions) == 0 { + c.JSON(http.StatusBadRequest, gin.H{"error": "Permissions cannot be empty"}) + return + } + + // Convert DTO to model + role := models.Role{ + Name: roleDTO.Name, + Description: roleDTO.Description, + Permissions: convertPermissionsToModels(roleDTO.Permissions), + Status: roleDTO.Status, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + CreatedBy: roleDTO.CreatedBy, + UpdatedBy: roleDTO.UpdatedBy, + } + // Create Role roleID, err := rbac.RbacService.CreateRole(role) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Error creating role"}) return } - // Respond with the ID of the created role c.JSON(http.StatusCreated, gin.H{"role_id": roleID}) } diff --git a/pkg/auth/controllers/user_controller.go b/pkg/auth/controllers/user_controller.go index caf4d87..377f28a 100644 --- a/pkg/auth/controllers/user_controller.go +++ b/pkg/auth/controllers/user_controller.go @@ -1,7 +1,9 @@ package controllers import ( + "context" "github.com/gin-gonic/gin" + "github.com/krack8/lighthouse/pkg/auth/dto" "github.com/krack8/lighthouse/pkg/auth/models" "github.com/krack8/lighthouse/pkg/auth/services" "github.com/krack8/lighthouse/pkg/auth/utils" @@ -19,14 +21,22 @@ func NewUserController(userService *services.UserService) *UserController { } // CreateUserHandler handles the creation of a new user. + func (uc *UserController) CreateUserHandler(c *gin.Context) { - var user models.User - if err := c.ShouldBindJSON(&user); err != nil { + var userDTO dto.UserDTO + if err := c.ShouldBindJSON(&userDTO); err != nil { + utils.RespondWithError(c, http.StatusBadRequest, err.Error()) + return + } + + // Convert DTO to User model + user, err := uc.convertDTOToUser(c, userDTO) + if err != nil { utils.RespondWithError(c, http.StatusBadRequest, err.Error()) return } - createdUser, err := uc.UserService.CreateUser(&user) + createdUser, err := uc.UserService.CreateUser(user) if err != nil { utils.RespondWithError(c, http.StatusInternalServerError, err.Error()) return @@ -35,6 +45,30 @@ func (uc *UserController) CreateUserHandler(c *gin.Context) { utils.RespondWithJSON(c, http.StatusCreated, createdUser) } +func (uc *UserController) convertDTOToUser(ctx context.Context, userDTO dto.UserDTO) (*models.User, error) { + // Convert role IDs to Role objects + roles, err := uc.UserService.GetRolesByIds(ctx, userDTO.RoleIds) + if err != nil { + return nil, err + } + + return &models.User{ + Username: userDTO.Username, + FirstName: userDTO.FirstName, + LastName: userDTO.LastName, + Password: userDTO.Password, + UserType: models.UserType(userDTO.UserType), + Roles: roles, + ClusterIdList: userDTO.ClusterIdList, + UserIsActive: userDTO.UserIsActive, + IsVerified: userDTO.IsVerified, + Phone: userDTO.Phone, + Status: userDTO.Status, + CreatedBy: userDTO.CreatedBy, + UpdatedBy: userDTO.UpdatedBy, + }, nil +} + // GetUserHandler handles fetching a user by ID. func (uc *UserController) GetUserHandler(c *gin.Context) { id := c.Param("id") diff --git a/pkg/auth/dto/role_dto.go b/pkg/auth/dto/role_dto.go new file mode 100644 index 0000000..7808822 --- /dev/null +++ b/pkg/auth/dto/role_dto.go @@ -0,0 +1,13 @@ +package dto + +import "github.com/krack8/lighthouse/pkg/auth/enum" + +// RoleDTO with permissions as string slice +type RoleDTO struct { + Name string `json:"name" binding:"required"` + Description string `json:"description"` + Permissions []string `json:"permissions" binding:"required"` // String slice + Status enum.Status `json:"status"` + CreatedBy string `json:"created_by"` + UpdatedBy string `json:"updated_by"` +} diff --git a/pkg/auth/dto/user_dto.go b/pkg/auth/dto/user_dto.go new file mode 100644 index 0000000..2d116fd --- /dev/null +++ b/pkg/auth/dto/user_dto.go @@ -0,0 +1,19 @@ +package dto + +import "github.com/krack8/lighthouse/pkg/auth/enum" + +type UserDTO struct { + Username string `json:"username" binding:"required,email"` + FirstName string `json:"first_name"` + LastName string `json:"last_name"` + Password string `json:"password" binding:"required,min=6,max=15"` + UserType string `json:"user_type" binding:"required,oneof=ADMIN USER"` + RoleIds []string `json:"role_ids" binding:"required"` // Array of role IDs + ClusterIdList []string `json:"cluster_ids"` + UserIsActive bool `json:"user_is_active" binding:"required"` + IsVerified bool `json:"is_verified" binding:"required"` + Phone string `json:"phone,omitempty"` + Status enum.Status `json:"status"` + CreatedBy string `json:"created_by"` + UpdatedBy string `json:"updated_by"` +} diff --git a/pkg/auth/enum/permision_constants.go b/pkg/auth/enum/permision_constants.go index 2e4a82f..fc3e8df 100644 --- a/pkg/auth/enum/permision_constants.go +++ b/pkg/auth/enum/permision_constants.go @@ -16,9 +16,79 @@ const ( HELM PermissionCategory = "HELM" // Permission names - DEFAULT_PERMISSION PermissionName = "DEFAULT_PERMISSION" - VIEW_NAMESPACE PermissionName = "VIEW_NAMESPACE_ENDPOINTS" - MANAGE_NAMESPACE PermissionName = "MANAGE_NAMESPACE_ENDPOINTS" + DEFAULT_PERMISSION PermissionName = "DEFAULT_PERMISSION" + VIEW_NAMESPACE PermissionName = "VIEW_NAMESPACE_ENDPOINTS" + MANAGE_NAMESPACE PermissionName = "MANAGE_NAMESPACE_ENDPOINTS" + CREATE_K8S_NAMESPACE PermissionName = "CREATE_K8S_NAMESPACE" + VIEW_K8S_NAMESPACE PermissionName = "VIEW_K8S_NAMESPACE" + UPDATE_K8S_NAMESPACE PermissionName = "UPDATE_K8S_NAMESPACE" + DELETE_K8S_NAMESPACE PermissionName = "DELETE_K8S_NAMESPACE" + VIEW_NAMESPACE_DEPLOYMENT PermissionName = "VIEW_NAMESPACE_DEPLOYMENT" + VIEW_NAMESPACE_REPLICA_SET PermissionName = "VIEW_NAMESPACE_REPLICA_SET" + MANAGE_NAMESPACE_POD PermissionName = "MANAGE_NAMESPACE_POD" + VIEW_NAMESPACE_POD PermissionName = "VIEW_NAMESPACE_POD" + MANAGE_NAMESPACE_DEPLOYMENT PermissionName = "MANAGE_NAMESPACE_DEPLOYMENT" + MANAGE_NAMESPACE_REPLICA_SET PermissionName = "MANAGE_NAMESPACE_REPLICA_SET" + VIEW_NAMESPACE_STATEFUL_SET PermissionName = "VIEW_NAMESPACE_STATEFUL_SET" + MANAGE_NAMESPACE_STATEFUL_SET PermissionName = "MANAGE_NAMESPACE_STATEFUL_SET" + VIEW_NAMESPACE_DAEMON_SET PermissionName = "VIEW_NAMESPACE_DAEMON_SET" + MANAGE_NAMESPACE_DAEMON_SET PermissionName = "MANAGE_NAMESPACE_DAEMON_SET" + VIEW_NAMESPACE_SECRET PermissionName = "VIEW_NAMESPACE_SECRET" + MANAGE_NAMESPACE_SECRET PermissionName = "MANAGE_NAMESPACE_SECRET" + VIEW_NAMESPACE_CONFIG_MAP PermissionName = "VIEW_NAMESPACE_CONFIG_MAP" + MANAGE_NAMESPACE_CONFIG_MAP PermissionName = "MANAGE_NAMESPACE_CONFIG_MAP" + VIEW_NAMESPACE_SERVICE_ACCOUNT PermissionName = "VIEW_NAMESPACE_SERVICE_ACCOUNT" + MANAGE_NAMESPACE_SERVICE_ACCOUNT PermissionName = "MANAGE_NAMESPACE_SERVICE_ACCOUNT" + VIEW_NAMESPACE_SERVICE PermissionName = "VIEW_NAMESPACE_SERVICE" + MANAGE_NAMESPACE_SERVICE PermissionName = "MANAGE_NAMESPACE_SERVICE" + VIEW_NAMESPACE_INGRESS PermissionName = "VIEW_NAMESPACE_INGRESS" + MANAGE_NAMESPACE_INGRESS PermissionName = "MANAGE_NAMESPACE_INGRESS" + VIEW_NAMESPACE_CERTIFICATE PermissionName = "VIEW_NAMESPACE_CERTIFICATE" + MANAGE_NAMESPACE_CERTIFICATE PermissionName = "MANAGE_NAMESPACE_CERTIFICATE" + VIEW_NAMESPACE_ROLE PermissionName = "VIEW_NAMESPACE_ROLE" + MANAGE_NAMESPACE_ROLE PermissionName = "MANAGE_NAMESPACE_ROLE" + VIEW_NAMESPACE_ROLE_BINDING PermissionName = "VIEW_NAMESPACE_ROLE_BINDING" + MANAGE_NAMESPACE_ROLE_BINDING PermissionName = "MANAGE_NAMESPACE_ROLE_BINDING" + VIEW_NAMESPACE_JOB PermissionName = "VIEW_NAMESPACE_JOB" + MANAGE_NAMESPACE_JOB PermissionName = "MANAGE_NAMESPACE_JOB" + VIEW_NAMESPACE_CRON_JOB PermissionName = "VIEW_NAMESPACE_CRON_JOB" + MANAGE_NAMESPACE_CRON_JOB PermissionName = "MANAGE_NAMESPACE_CRON_JOB" + VIEW_NAMESPACE_NETWORK_POLICY PermissionName = "VIEW_NAMESPACE_NETWORK_POLICY" + MANAGE_NAMESPACE_NETWORK_POLICY PermissionName = "MANAGE_NAMESPACE_NETWORK_POLICY" + VIEW_NAMESPACE_RESOURCE_QUOTA PermissionName = "VIEW_NAMESPACE_RESOURCE_QUOTA" + MANAGE_NAMESPACE_RESOURCE_QUOTA PermissionName = "MANAGE_NAMESPACE_RESOURCE_QUOTA" + VIEW_NAMESPACE_PERSISTENT_VOLUME PermissionName = "VIEW_NAMESPACE_PERSISTENT_VOLUME" + MANAGE_NAMESPACE_PERSISTENT_VOLUME PermissionName = "MANAGE_NAMESPACE_PERSISTENT_VOLUME" + VIEW_NAMESPACE_GATEWAY PermissionName = "VIEW_NAMESPACE_GATEWAY" + MANAGE_NAMESPACE_GATEWAY PermissionName = "MANAGE_NAMESPACE_GATEWAY" + VIEW_NAMESPACE_VIRTUAL_SERVICE PermissionName = "VIEW_NAMESPACE_VIRTUAL_SERVICE" + MANAGE_NAMESPACE_VIRTUAL_SERVICE PermissionName = "MANAGE_NAMESPACE_VIRTUAL_SERVICE" + VIEW_K8S_NODES PermissionName = "VIEW_K8S_NODES" + MANAGE_K8S_NODE_TAINT PermissionName = "MANAGE_K8S_NODE_TAINT" + DRAIN_K8S_NODE PermissionName = "DRAIN_K8S_NODE" + VIEW_K8S_PERSISTENT_VOLUME PermissionName = "VIEW_K8S_PERSISTENT_VOLUME" + MANAGE_K8S_PERSISTENT_VOLUME PermissionName = "MANAGE_K8S_PERSISTENT_VOLUME" + VIEW_K8S_CLUSTER_ROLE PermissionName = "VIEW_K8S_CLUSTER_ROLE" + MANAGE_K8S_CLUSTER_ROLE PermissionName = "MANAGE_K8S_CLUSTER_ROLE" + VIEW_K8S_CLUSTER_ROLE_BINDING PermissionName = "VIEW_K8S_CLUSTER_ROLE_BINDING" + MANAGE_K8S_CLUSTER_ROLE_BINDING PermissionName = "MANAGE_K8S_CLUSTER_ROLE_BINDING" + VIEW_K8S_STORAGE_CLASS PermissionName = "VIEW_K8S_STORAGE_CLASS" + MANAGE_K8S_STORAGE_CLASS PermissionName = "MANAGE_K8S_STORAGE_CLASS" + VIEW_K8S_CUSTOM_RESOURCES PermissionName = "VIEW_K8S_CUSTOM_RESOURCES" + MANAGE_K8S_CUSTOM_RESOURCES PermissionName = "MANAGE_K8S_CUSTOM_RESOURCES" + VIEW_K8S_CUSTOM_RESOURCE_DEFINATION PermissionName = "VIEW_K8S_CUSTOM_RESOURCE_DEFINATION" + MANAGE_K8S_CUSTOM_RESOURCE_DEFINATION PermissionName = "MANAGE_K8S_CUSTOM_RESOURCE_DEFINATION" + VIEW_LOGS PermissionName = "VIEW_LOGS" + VIEW_NAMESPACE_ENDPOINTS PermissionName = "VIEW_NAMESPACE_ENDPOINTS" + MANAGE_NAMESPACE_ENDPOINTS PermissionName = "MANAGE_NAMESPACE_ENDPOINTS" + VIEW_NAMESPACE_ENDPOINT_SLICE PermissionName = "VIEW_NAMESPACE_ENDPOINT_SLICE" + VIEW_NAMESPACE_PDB PermissionName = "VIEW_NAMESPACE_PDB" + MANAGE_NAMESPACE_PDB PermissionName = "MANAGE_NAMESPACE_PDB" + VIEW_NAMESPACE_CONTROLLER_REVISION PermissionName = "VIEW_NAMESPACE_CONTROLLER_REVISION" + MANAGE_NAMESPACE_CONTROLLER_REVISION PermissionName = "MANAGE_NAMESPACE_CONTROLLER_REVISION" + VIEW_NAMESPACE_REPLICATION_CONTROLLER PermissionName = "VIEW_NAMESPACE_REPLICATION_CONTROLLER" + MANAGE_NAMESPACE_REPLICATION_CONTROLLER PermissionName = "MANAGE_NAMESPACE_REPLICATION_CONTROLLER" + VIEW_ENDPOINT_SLICE PermissionName = "VIEW_ENDPOINT_SLICE" MANAGE_ENDPOINT_SLICE PermissionName = "MANAGE_ENDPOINT_SLICE" VIEW_PDB PermissionName = "VIEW_PDB" diff --git a/pkg/auth/services/rbac_service.go b/pkg/auth/services/rbac_service.go index 24b452d..949133c 100644 --- a/pkg/auth/services/rbac_service.go +++ b/pkg/auth/services/rbac_service.go @@ -44,6 +44,18 @@ func (r *RbacService) CreateRole(role models.Role) (primitive.ObjectID, error) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() + // Additional validation if needed + if len(role.Permissions) == 0 { + return primitive.NilObjectID, errors.New("permissions cannot be empty") + } + + // Validate each permission + for _, perm := range role.Permissions { + if strings.TrimSpace(perm.Name) == "" { + return primitive.NilObjectID, errors.New("invalid permission name") + } + } + result, err := db.RoleCollection.InsertOne(ctx, role) if err != nil { return primitive.NilObjectID, err diff --git a/pkg/auth/services/user_service.go b/pkg/auth/services/user_service.go index 292f2af..cb18f67 100644 --- a/pkg/auth/services/user_service.go +++ b/pkg/auth/services/user_service.go @@ -36,7 +36,6 @@ func NewUserService(collection Collection) *UserService { } } -// CreateUser creates a new user func (s *UserService) CreateUser(user *models.User) (*models.User, error) { if user == nil { return nil, errors.New("user cannot be nil") @@ -45,8 +44,9 @@ func (s *UserService) CreateUser(user *models.User) (*models.User, error) { if user.Username == "" { return nil, errors.New("username cannot be empty") } - data, _ := GetUserByUsername(user.Username) + // Check if user exists + data, _ := GetUserByUsername(user.Username) if data != nil { return nil, errors.New("user already exists") } @@ -245,3 +245,34 @@ func (s *UserService) GetUserProfileInfo(username string) (*models.User, error) } return user, nil } + +func (s *UserService) GetRolesByIds(ctx context.Context, roleIds []string) ([]models.Role, error) { + var roles []models.Role + + // Convert string IDs to ObjectIDs + objectIds := make([]primitive.ObjectID, 0, len(roleIds)) + for _, id := range roleIds { + objID, err := primitive.ObjectIDFromHex(id) + if err != nil { + return nil, err + } + objectIds = append(objectIds, objID) + } + + // Find roles by IDs + cursor, err := db.RoleCollection.Find(ctx, bson.M{ + "_id": bson.M{ + "$in": objectIds, + }, + }) + if err != nil { + return nil, err + } + defer cursor.Close(ctx) + + if err = cursor.All(ctx, &roles); err != nil { + return nil, err + } + + return roles, nil +} diff --git a/pkg/auth/utils/endpoints.go b/pkg/auth/utils/endpoints.go index b364435..9b56a5f 100644 --- a/pkg/auth/utils/endpoints.go +++ b/pkg/auth/utils/endpoints.go @@ -28,22 +28,41 @@ func GetViewNamespaceEndpoints() []models.Endpoint { } } -// GetUpdateNamespaceEndpoint returns endpoints for updating K8s namespace operations -func GetUpdateNamespaceEndpoint() []models.Endpoint { +// GetK8sNamespaceCreateEndpoints returns endpoints for creating K8s namespaces +func GetK8sNamespaceCreateEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/namespace"}, + {Method: "GET", Route: "/api/v1/namespace"}, + {Method: "GET", Route: "/api/v1/namespace/@"}, + } +} + +// GetViewK8sNamespaceEndpoints returns endpoints for viewing K8s namespaces +func GetViewK8sNamespaceEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/namespace"}, + {Method: "GET", Route: "api/v1/namespace/names"}, + {Method: "GET", Route: "/api/v1/namespace/@"}, + {Method: "GET", Route: "/api/v1/event"}, } } -// GetDeleteNamespaceEndpoint returns endpoints for deleting K8s namespace operations -func GetDeleteNamespaceEndpoint() []models.Endpoint { +// GetK8sNamespaceUpdateEndpoints returns endpoints for updating K8s namespaces +func GetK8sNamespaceUpdateEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/namespace"}, + } +} + +// GetK8sNamespaceDeleteEndpoints returns endpoints for deleting K8s namespaces +func GetK8sNamespaceDeleteEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "DELETE", Route: "/api/v1/namespace/@"}, } } -// ViewDeploymentEndpoints returns a slice of endpoints for viewing deployments -func ViewDeploymentEndpoints() []models.Endpoint { +// GetViewK8sNamespaceDeploymentEndpoints returns endpoints for viewing K8s namespace deployments +func GetViewK8sNamespaceDeploymentEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/deployment"}, {Method: "GET", Route: "/api/v1/deployment/stats"}, @@ -52,16 +71,16 @@ func ViewDeploymentEndpoints() []models.Endpoint { } } -// ManageDeploymentEndpoints returns a slice of endpoints for managing deployments -func ManageDeploymentEndpoints() []models.Endpoint { +// GetK8sNamespaceManageDeploymentEndpoints returns endpoints for managing K8s namespace deployments +func GetK8sNamespaceManageDeploymentEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/deployment"}, {Method: "DELETE", Route: "/api/v1/deployment/@"}, } } -// ViewPodEndpoints returns a slice of endpoints for viewing pods -func ViewPodEndpoints() []models.Endpoint { +// GetViewK8sNamespacePodEndpoints returns endpoints for viewing K8s namespace pods +func GetViewK8sNamespacePodEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/pod"}, {Method: "GET", Route: "/api/v1/pod/@"}, @@ -69,32 +88,32 @@ func ViewPodEndpoints() []models.Endpoint { } } -// ManagePodEndpoints returns a slice of endpoints for managing pods -func ManagePodEndpoints() []models.Endpoint { +// GetK8sNamespaceManagePodEndpoints returns endpoints for managing K8s namespace pods +func GetK8sNamespaceManagePodEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/pod"}, {Method: "DELETE", Route: "/api/v1/pod/@"}, } } -// ViewReplicaSetEndpoints returns a slice of endpoints for viewing replica sets -func ViewReplicaSetEndpoints() []models.Endpoint { +// GetViewK8sNamespaceReplicaSetEndpoints returns endpoints for viewing K8s namespace replica sets +func GetViewK8sNamespaceReplicaSetEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/replicaset"}, {Method: "GET", Route: "/api/v1/replicaset/@"}, } } -// ManageReplicaSetEndpoints returns a slice of endpoints for managing replica sets -func ManageReplicaSetEndpoints() []models.Endpoint { +// GetK8sNamespaceManageReplicaSetEndpoints returns endpoints for managing K8s namespace replica sets +func GetK8sNamespaceManageReplicaSetEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/replicaset"}, {Method: "DELETE", Route: "/api/v1/replicaset/@"}, } } -// ViewStatefulSetEndpoints returns a slice of endpoints for viewing stateful sets -func ViewStatefulSetEndpoints() []models.Endpoint { +// GetViewK8sNamespaceStatefulSetEndpoints returns endpoints for viewing K8s namespace stateful sets +func GetViewK8sNamespaceStatefulSetEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/statefulset"}, {Method: "GET", Route: "/api/v1/statefulset/@"}, @@ -103,140 +122,122 @@ func ViewStatefulSetEndpoints() []models.Endpoint { } } -// ManageStatefulSetEndpoints returns a slice of endpoints for managing stateful sets -func ManageStatefulSetEndpoints() []models.Endpoint { +// GetK8sNamespaceManageStatefulSetEndpoints returns endpoints for managing K8s namespace stateful sets +func GetK8sNamespaceManageStatefulSetEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/statefulset"}, {Method: "DELETE", Route: "/api/v1/statefulset/@"}, } } -// ViewDaemonSetEndpoints returns a slice of endpoints for viewing daemon sets -func ViewDaemonSetEndpoints() []models.Endpoint { - return []models.Endpoint{ - {Method: "GET", Route: "/api/v1/daemonset"}, - {Method: "GET", Route: "/api/v1/daemonset/stats"}, - {Method: "GET", Route: "/api/v1/daemonset/@"}, - } -} - -// ManageDaemonSetEndpoints returns a slice of endpoints for managing daemon sets -func ManageDaemonSetEndpoints() []models.Endpoint { - return []models.Endpoint{ - {Method: "POST", Route: "/api/v1/daemonset"}, - {Method: "DELETE", Route: "/api/v1/daemonset/@"}, - } -} - -// ViewSecretEndpoints returns a slice of endpoints for viewing secrets -func ViewSecretEndpoints() []models.Endpoint { +// GetViewK8sNamespaceSecretEndpoints returns endpoints for viewing K8s namespace secrets +func GetViewK8sNamespaceSecretEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/secret"}, {Method: "GET", Route: "/api/v1/secret/@"}, } } -// ManageSecretEndpoints returns a slice of endpoints for managing secrets -func ManageSecretEndpoints() []models.Endpoint { +// GetK8sNamespaceManageSecretEndpoints returns endpoints for managing K8s namespace secrets +func GetK8sNamespaceManageSecretEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/secret"}, {Method: "DELETE", Route: "/api/v1/secret/@"}, } } -// ViewConfigMapEndpoints returns a slice of endpoints for viewing config maps -func ViewConfigMapEndpoints() []models.Endpoint { +// GetViewK8sNamespaceConfigMapEndpoints returns endpoints for viewing K8s namespace config maps +func GetViewK8sNamespaceConfigMapEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/config-map"}, {Method: "GET", Route: "/api/v1/config-map/@"}, } } -// ManageConfigMapEndpoints returns a slice of endpoints for managing config maps -func ManageConfigMapEndpoints() []models.Endpoint { +// GetK8sNamespaceManageConfigMapEndpoints returns endpoints for managing K8s namespace config maps +func GetK8sNamespaceManageConfigMapEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/config-map"}, {Method: "DELETE", Route: "/api/v1/config-map/@"}, } } -// ViewServiceAccountEndpoints returns a slice of endpoints for viewing service accounts -func ViewServiceAccountEndpoints() []models.Endpoint { +// GetViewK8sNamespaceServiceEndpoints returns endpoints for viewing K8s namespace services +func GetViewK8sNamespaceServiceEndpoints() []models.Endpoint { return []models.Endpoint{ - {Method: "GET", Route: "/api/v1/service-account"}, - {Method: "GET", Route: "/api/v1/service-account/@"}, + {Method: "GET", Route: "/api/v1/service"}, + {Method: "GET", Route: "/api/v1/service/@"}, } } -// ManageServiceAccountEndpoints returns a slice of endpoints for managing service accounts -func ManageServiceAccountEndpoints() []models.Endpoint { +// GetK8sNamespaceManageServiceEndpoints returns endpoints for managing K8s namespace services +func GetK8sNamespaceManageServiceEndpoints() []models.Endpoint { return []models.Endpoint{ - {Method: "POST", Route: "/api/v1/service-account"}, - {Method: "GET", Route: "/api/v1/service-account/@"}, + {Method: "POST", Route: "/api/v1/service"}, + {Method: "DELETE", Route: "/api/v1/service/@"}, } } -// ViewServiceEndpoints returns a slice of endpoints for viewing services -func ViewServiceEndpoints() []models.Endpoint { +// GetViewK8sNamespaceServiceAccountEndpoints returns endpoints for viewing K8s namespace service accounts +func GetViewK8sNamespaceServiceAccountEndpoints() []models.Endpoint { return []models.Endpoint{ - {Method: "GET", Route: "/api/v1/service"}, - {Method: "GET", Route: "/api/v1/service/@"}, + {Method: "GET", Route: "/api/v1/service-account"}, + {Method: "GET", Route: "/api/v1/service-account/@"}, } } -// ManageServiceEndpoints returns a slice of endpoints for managing services -func ManageServiceEndpoints() []models.Endpoint { +// GetK8sNamespaceManageServiceAccountEndpoints returns endpoints for managing K8s namespace service accounts +func GetK8sNamespaceManageServiceAccountEndpoints() []models.Endpoint { return []models.Endpoint{ - {Method: "POST", Route: "/api/v1/service"}, - {Method: "DELETE", Route: "/api/v1/service/@"}, + {Method: "POST", Route: "/api/v1/service-account"}, + {Method: "GET", Route: "/api/v1/service-account/@"}, } } -// ManageIngressEndpoints returns a slice of endpoints for managing ingress -func ManageIngressEndpoints() []models.Endpoint { +// GetViewK8sNodeEndpoints returns endpoints for viewing K8s nodes +func GetViewK8sNodeEndpoints() []models.Endpoint { return []models.Endpoint{ - {Method: "POST", Route: "/api/v1/ingress"}, - {Method: "DELETE", Route: "/api/v1/ingress/@"}, + {Method: "GET", Route: "/api/v1/node"}, + {Method: "GET", Route: "/api/v1/node/@"}, } } -// ManageCertificateEndpoints returns a slice of endpoints for managing certificates -func ManageCertificateEndpoints() []models.Endpoint { +// GetManageK8sNodeTaintEndpoints returns endpoints for managing K8s node taints +func GetManageK8sNodeTaintEndpoints() []models.Endpoint { return []models.Endpoint{ - {Method: "POST", Route: "/api/v1/certificate"}, - {Method: "DELETE", Route: "/api/v1/certificate/@"}, + {Method: "POST", Route: "api/v1/node/taint/@"}, + {Method: "POST", Route: "api/v1/node/untaint/@"}, } } -// ManageRoleEndpoints returns a slice of endpoints for managing roles -func ManageRoleEndpoints() []models.Endpoint { +// GetViewK8sCustomResourceEndpoints returns endpoints for viewing K8s custom resources +func GetViewK8sCustomResourceEndpoints() []models.Endpoint { return []models.Endpoint{ - {Method: "POST", Route: "/api/v1/role"}, - {Method: "DELETE", Route: "/api/v1/role/@"}, + {Method: "GET", Route: "/api/v1/custom-resource"}, + {Method: "GET", Route: "/api/v1/custom-resource/@"}, } } -// ManageRoleBindingEndpoints returns a slice of endpoints for managing role bindings -func ManageRoleBindingEndpoints() []models.Endpoint { +// GetManageK8sCustomResourceEndpoints returns endpoints for managing K8s custom resources +func GetManageK8sCustomResourceEndpoints() []models.Endpoint { return []models.Endpoint{ - {Method: "POST", Route: "/api/v1/role-binding"}, - {Method: "DELETE", Route: "/api/v1/role-binding/@"}, + {Method: "POST", Route: "/api/v1/custom-resource"}, + {Method: "DELETE", Route: "/api/v1/custom-resource/@"}, } } -// ManageJobEndpoints returns a slice of endpoints for managing jobs -func ManageJobEndpoints() []models.Endpoint { +// GetViewK8sNamespaceLogsEndpoints returns endpoints for viewing K8s namespace logs +func GetViewK8sNamespaceLogsEndpoints() []models.Endpoint { return []models.Endpoint{ - {Method: "POST", Route: "/api/v1/job"}, - {Method: "DELETE", Route: "/api/v1/job/@"}, + {Method: "GET", Route: "/api/v1/pod/logs/"}, } } -// ManageCronJobEndpoints returns a slice of endpoints for managing cron jobs -func ManageCronJobEndpoints() []models.Endpoint { +// GetManageNamespaceEndpoints returns endpoints for managing K8s namespace endpoints +func GetManageNamespaceEndpoints() []models.Endpoint { return []models.Endpoint{ - {Method: "POST", Route: "/api/v1/cronjob"}, - {Method: "DELETE", Route: "/api/v1/cronjob/@"}, + {Method: "POST", Route: "api/v1/endpoints"}, + {Method: "DELETE", Route: "api/v1/endpoints/@"}, } } From 7c39bfb277a10ce978df590c4fde4ca9259ea500 Mon Sep 17 00:00:00 2001 From: Nahid Date: Tue, 4 Feb 2025 14:32:30 +0600 Subject: [PATCH 41/64] fix: Fix Model Data Convert function --- .../controllers/role_permission_controller.go | 79 ++++++++++++++++--- pkg/auth/controllers/user_controller.go | 21 +++-- pkg/auth/dto/role_dto.go | 11 +-- pkg/auth/dto/user_dto.go | 25 +++--- pkg/auth/services/user_service.go | 7 +- 5 files changed, 101 insertions(+), 42 deletions(-) diff --git a/pkg/auth/controllers/role_permission_controller.go b/pkg/auth/controllers/role_permission_controller.go index bba1ad0..e288aeb 100644 --- a/pkg/auth/controllers/role_permission_controller.go +++ b/pkg/auth/controllers/role_permission_controller.go @@ -1,11 +1,17 @@ package controllers import ( + "context" "fmt" "github.com/gin-gonic/gin" + db "github.com/krack8/lighthouse/pkg/auth/config" "github.com/krack8/lighthouse/pkg/auth/dto" + "github.com/krack8/lighthouse/pkg/auth/enum" "github.com/krack8/lighthouse/pkg/auth/models" "github.com/krack8/lighthouse/pkg/auth/services" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" "net/http" "strings" "time" @@ -40,23 +46,63 @@ func (rbac *RbacController) CreatePermissionHandler(c *gin.Context) { c.JSON(http.StatusCreated, gin.H{"permission_id": permissionID}) } -// Helper function to convert string slice to Permission slice -func convertPermissionsToModels(permissions []string) []models.Permission { - permissionModels := make([]models.Permission, 0, len(permissions)) +// Helper function to convert permission ID strings to Permission slice +func convertPermissionsToModels(permissionIDs []string) ([]models.Permission, error) { + // Create a slice to store ObjectIDs + objectIDs := make([]primitive.ObjectID, 0, len(permissionIDs)) - for _, p := range permissions { - if strings.TrimSpace(p) != "" { - permissionModels = append(permissionModels, models.Permission{ - Name: strings.TrimSpace(p), - }) + // Convert string IDs to ObjectIDs + for _, idStr := range permissionIDs { + if strings.TrimSpace(idStr) == "" { + continue } + objID, err := primitive.ObjectIDFromHex(strings.TrimSpace(idStr)) + if err != nil { + return nil, fmt.Errorf("invalid permission ID: %s - %v", idStr, err) + } + objectIDs = append(objectIDs, objID) + } + + // If no valid IDs, return empty result + if len(objectIDs) == 0 { + return []models.Permission{}, nil + } + + // Create filter for MongoDB query + filter := bson.M{ + "_id": bson.M{"$in": objectIDs}, + "status": enum.VALID, // Assuming you want only active permissions + } + + // Find permissions + cursor, err := db.PermissionCollection.Find(context.Background(), filter) + if err != nil { + return nil, fmt.Errorf("error fetching permissions: %v", err) + } + defer func(cursor *mongo.Cursor, ctx context.Context) { + err := cursor.Close(ctx) + if err != nil { + + } + }(cursor, context.Background()) + + // Decode results into Permission models + var permissions []models.Permission + if err := cursor.All(context.Background(), &permissions); err != nil { + return nil, fmt.Errorf("error decoding permissions: %v", err) } - return permissionModels + return permissions, nil } // CreateRoleHandler handles the creation of a new role func (rbac *RbacController) CreateRoleHandler(c *gin.Context) { + username, exists := c.Get("username") + if !exists { + c.JSON(http.StatusBadRequest, gin.H{"error": "Username not found in context.Please Enable AUTH"}) + return + } + requester := username.(string) var roleDTO dto.RoleDTO if err := c.ShouldBindJSON(&roleDTO); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"}) @@ -69,16 +115,23 @@ func (rbac *RbacController) CreateRoleHandler(c *gin.Context) { return } + PermissionList, e := convertPermissionsToModels(roleDTO.Permissions) + if e != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Unable to Convert Permission Model"}) + return + } + // Convert DTO to model role := models.Role{ + ID: primitive.NewObjectID(), Name: roleDTO.Name, Description: roleDTO.Description, - Permissions: convertPermissionsToModels(roleDTO.Permissions), - Status: roleDTO.Status, + Permissions: PermissionList, + Status: enum.VALID, CreatedAt: time.Now(), UpdatedAt: time.Now(), - CreatedBy: roleDTO.CreatedBy, - UpdatedBy: roleDTO.UpdatedBy, + CreatedBy: requester, + UpdatedBy: requester, } // Create Role diff --git a/pkg/auth/controllers/user_controller.go b/pkg/auth/controllers/user_controller.go index 377f28a..1391f44 100644 --- a/pkg/auth/controllers/user_controller.go +++ b/pkg/auth/controllers/user_controller.go @@ -4,9 +4,11 @@ import ( "context" "github.com/gin-gonic/gin" "github.com/krack8/lighthouse/pkg/auth/dto" + "github.com/krack8/lighthouse/pkg/auth/enum" "github.com/krack8/lighthouse/pkg/auth/models" "github.com/krack8/lighthouse/pkg/auth/services" "github.com/krack8/lighthouse/pkg/auth/utils" + "go.mongodb.org/mongo-driver/bson/primitive" "net/http" ) @@ -23,6 +25,13 @@ func NewUserController(userService *services.UserService) *UserController { // CreateUserHandler handles the creation of a new user. func (uc *UserController) CreateUserHandler(c *gin.Context) { + username, exists := c.Get("username") + if !exists { + c.JSON(http.StatusBadRequest, gin.H{"error": "Username not found in context.Please Enable AUTH"}) + return + } + requester := username.(string) + var userDTO dto.UserDTO if err := c.ShouldBindJSON(&userDTO); err != nil { utils.RespondWithError(c, http.StatusBadRequest, err.Error()) @@ -30,7 +39,7 @@ func (uc *UserController) CreateUserHandler(c *gin.Context) { } // Convert DTO to User model - user, err := uc.convertDTOToUser(c, userDTO) + user, err := uc.convertDTOToUser(c, userDTO, requester) if err != nil { utils.RespondWithError(c, http.StatusBadRequest, err.Error()) return @@ -45,7 +54,8 @@ func (uc *UserController) CreateUserHandler(c *gin.Context) { utils.RespondWithJSON(c, http.StatusCreated, createdUser) } -func (uc *UserController) convertDTOToUser(ctx context.Context, userDTO dto.UserDTO) (*models.User, error) { +func (uc *UserController) convertDTOToUser(ctx context.Context, userDTO dto.UserDTO, requester string) (*models.User, error) { + // Convert role IDs to Role objects roles, err := uc.UserService.GetRolesByIds(ctx, userDTO.RoleIds) if err != nil { @@ -53,6 +63,7 @@ func (uc *UserController) convertDTOToUser(ctx context.Context, userDTO dto.User } return &models.User{ + ID: primitive.NewObjectID(), Username: userDTO.Username, FirstName: userDTO.FirstName, LastName: userDTO.LastName, @@ -63,9 +74,9 @@ func (uc *UserController) convertDTOToUser(ctx context.Context, userDTO dto.User UserIsActive: userDTO.UserIsActive, IsVerified: userDTO.IsVerified, Phone: userDTO.Phone, - Status: userDTO.Status, - CreatedBy: userDTO.CreatedBy, - UpdatedBy: userDTO.UpdatedBy, + Status: enum.VALID, + CreatedBy: requester, + UpdatedBy: requester, }, nil } diff --git a/pkg/auth/dto/role_dto.go b/pkg/auth/dto/role_dto.go index 7808822..9115ed8 100644 --- a/pkg/auth/dto/role_dto.go +++ b/pkg/auth/dto/role_dto.go @@ -1,13 +1,8 @@ package dto -import "github.com/krack8/lighthouse/pkg/auth/enum" - // RoleDTO with permissions as string slice type RoleDTO struct { - Name string `json:"name" binding:"required"` - Description string `json:"description"` - Permissions []string `json:"permissions" binding:"required"` // String slice - Status enum.Status `json:"status"` - CreatedBy string `json:"created_by"` - UpdatedBy string `json:"updated_by"` + Name string `json:"name" binding:"required"` + Description string `json:"description"` + Permissions []string `json:"permissions" binding:"required"` } diff --git a/pkg/auth/dto/user_dto.go b/pkg/auth/dto/user_dto.go index 2d116fd..93f8b5c 100644 --- a/pkg/auth/dto/user_dto.go +++ b/pkg/auth/dto/user_dto.go @@ -1,19 +1,14 @@ package dto -import "github.com/krack8/lighthouse/pkg/auth/enum" - type UserDTO struct { - Username string `json:"username" binding:"required,email"` - FirstName string `json:"first_name"` - LastName string `json:"last_name"` - Password string `json:"password" binding:"required,min=6,max=15"` - UserType string `json:"user_type" binding:"required,oneof=ADMIN USER"` - RoleIds []string `json:"role_ids" binding:"required"` // Array of role IDs - ClusterIdList []string `json:"cluster_ids"` - UserIsActive bool `json:"user_is_active" binding:"required"` - IsVerified bool `json:"is_verified" binding:"required"` - Phone string `json:"phone,omitempty"` - Status enum.Status `json:"status"` - CreatedBy string `json:"created_by"` - UpdatedBy string `json:"updated_by"` + Username string `json:"username" binding:"required,email"` + FirstName string `json:"first_name"` + LastName string `json:"last_name"` + Password string `json:"password" binding:"required,min=6,max=15"` + UserType string `json:"user_type" binding:"required,oneof=ADMIN USER"` + RoleIds []string `json:"role_ids"` // Array of role IDs + ClusterIdList []string `json:"cluster_ids"` + UserIsActive bool `json:"user_is_active" binding:"required"` + IsVerified bool `json:"is_verified"` + Phone string `json:"phone,omitempty"` } diff --git a/pkg/auth/services/user_service.go b/pkg/auth/services/user_service.go index cb18f67..353a2eb 100644 --- a/pkg/auth/services/user_service.go +++ b/pkg/auth/services/user_service.go @@ -268,7 +268,12 @@ func (s *UserService) GetRolesByIds(ctx context.Context, roleIds []string) ([]mo if err != nil { return nil, err } - defer cursor.Close(ctx) + defer func(cursor *mongo.Cursor, ctx context.Context) { + err := cursor.Close(ctx) + if err != nil { + + } + }(cursor, ctx) if err = cursor.All(ctx, &roles); err != nil { return nil, err From 13c98add8220253b1a257d336ac56e201859b760 Mon Sep 17 00:00:00 2001 From: Nahid Date: Tue, 4 Feb 2025 14:52:47 +0600 Subject: [PATCH 42/64] feat: Implement Role Update and get users by Role API --- .../controllers/role_permission_controller.go | 135 ++++++++++++++++++ pkg/auth/services/rbac_service.go | 107 ++++++++++++++ pkg/server/router/routes.go | 2 + 3 files changed, 244 insertions(+) diff --git a/pkg/auth/controllers/role_permission_controller.go b/pkg/auth/controllers/role_permission_controller.go index e288aeb..badc65a 100644 --- a/pkg/auth/controllers/role_permission_controller.go +++ b/pkg/auth/controllers/role_permission_controller.go @@ -13,6 +13,7 @@ import ( "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "net/http" + "strconv" "strings" "time" ) @@ -301,3 +302,137 @@ func (rbac *RbacController) GetUserPermissionsHandler(c *gin.Context) { // Return permissions directly without the "data" wrapper c.JSON(http.StatusOK, permissions) } + +func (rbac *RbacController) UpdateRoleHandler(c *gin.Context) { + // Get role ID from URL parameter + roleID := c.Param("id") + if roleID == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "Role ID is required"}) + return + } + + // Get username from context + username, exists := c.Get("username") + if !exists { + c.JSON(http.StatusBadRequest, gin.H{"error": "Username not found in context. Please Enable AUTH"}) + return + } + requester := username.(string) + + // Bind input data + var roleDTO dto.RoleDTO + if err := c.ShouldBindJSON(&roleDTO); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"}) + return + } + + // Validate permissions + if len(roleDTO.Permissions) == 0 { + c.JSON(http.StatusBadRequest, gin.H{"error": "Permissions cannot be empty"}) + return + } + + // Convert permission IDs to models + permissionList, err := convertPermissionsToModels(roleDTO.Permissions) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Unable to Convert Permission Model"}) + return + } + + // Convert ID string to ObjectID + objectID, err := primitive.ObjectIDFromHex(roleID) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid role ID format"}) + return + } + + // Create update model + updateRole := models.Role{ + ID: objectID, + Name: roleDTO.Name, + Description: roleDTO.Description, + Permissions: permissionList, + Status: enum.VALID, + UpdatedAt: time.Now(), + UpdatedBy: requester, + } + + // Call service to update + err = rbac.RbacService.UpdateRole(updateRole) + if err != nil { + if err == mongo.ErrNoDocuments { + c.JSON(http.StatusNotFound, gin.H{"error": "Role not found"}) + return + } + c.JSON(http.StatusInternalServerError, gin.H{"error": "Error updating role"}) + return + } + + c.JSON(http.StatusOK, gin.H{"message": "Role updated successfully"}) +} + +func (rbac *RbacController) GetUsersByRoleIDHandler(c *gin.Context) { + // Get role ID from URL parameter + roleID := c.Param("id") + if roleID == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "Role ID is required"}) + return + } + + // Convert ID string to ObjectID + objectID, err := primitive.ObjectIDFromHex(roleID) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid role ID format"}) + return + } + + // Default values + const ( + defaultPage = 1 + defaultLimit = 10 + maxLimit = 100 + ) + + // Get page parameter with default value + page := defaultPage + pageStr := c.Query("page") + if pageStr != "" { + parsedPage, err := strconv.Atoi(pageStr) + if err != nil || parsedPage < 1 { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid page number"}) + return + } + page = parsedPage + } + + // Get limit parameter with default value + limit := defaultLimit + limitStr := c.Query("limit") + if limitStr != "" { + parsedLimit, err := strconv.Atoi(limitStr) + if err != nil || parsedLimit < 1 { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid limit value"}) + return + } + limit = parsedLimit + } + + // Enforce maximum limit + if limit > maxLimit { + limit = maxLimit + } + + // Call service to get users + users, total, err := rbac.RbacService.GetUsersByRoleID(objectID, page, limit) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Error fetching users"}) + return + } + + c.JSON(http.StatusOK, gin.H{ + "users": users, + "total": total, + "page": page, + "limit": limit, + }) +} diff --git a/pkg/auth/services/rbac_service.go b/pkg/auth/services/rbac_service.go index 949133c..1dbb513 100644 --- a/pkg/auth/services/rbac_service.go +++ b/pkg/auth/services/rbac_service.go @@ -326,3 +326,110 @@ func (r *RbacService) GetPermissionsByUserType(username string) (*dto.Permission return response, nil } + +func (r *RbacService) UpdateRole(role models.Role) error { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + // Validate permissions + if len(role.Permissions) == 0 { + return errors.New("permissions cannot be empty") + } + + // Create update filter + filter := bson.M{ + "_id": role.ID, + "status": enum.VALID, + } + + // Create update document + update := bson.M{ + "$set": bson.M{ + "name": role.Name, + "description": role.Description, + "permissions": role.Permissions, + "updated_at": role.UpdatedAt, + "updated_by": role.UpdatedBy, + }, + } + + // Perform update + result, err := db.RoleCollection.UpdateOne(ctx, filter, update) + if err != nil { + return err + } + + // Check if document was found and updated + if result.MatchedCount == 0 { + return mongo.ErrNoDocuments + } + + return nil +} + +func (r *RbacService) GetUsersByRoleID(roleID primitive.ObjectID, page, limit int) ([]models.User, int64, error) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + // Calculate skip value for pagination + skip := (page - 1) * limit + + // Create match stage for aggregation + matchStage := bson.D{ + {"$match", bson.D{ + {"roles._id", roleID}, + {"status", enum.VALID}, + {"user_is_active", true}, + }}, + } + + // Create pagination stages + paginationStage := bson.D{ + {"$skip", skip}, + } + limitStage := bson.D{ + {"$limit", limit}, + } + + // Execute count query + countPipeline := mongo.Pipeline{matchStage} + countCursor, err := db.UserCollection.Aggregate(ctx, append(countPipeline, bson.D{ + {"$count", "total"}, + })) + if err != nil { + return nil, 0, err + } + defer countCursor.Close(ctx) + + // Get total count + var countResult []bson.M + if err := countCursor.All(ctx, &countResult); err != nil { + return nil, 0, err + } + + total := int64(0) + if len(countResult) > 0 { + total = countResult[0]["total"].(int64) + } + + // Execute main query + pipeline := mongo.Pipeline{ + matchStage, + paginationStage, + limitStage, + } + + cursor, err := db.UserCollection.Aggregate(ctx, pipeline) + if err != nil { + return nil, 0, err + } + defer cursor.Close(ctx) + + // Decode results + var users []models.User + if err = cursor.All(ctx, &users); err != nil { + return nil, 0, err + } + + return users, total, nil +} diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index da39b31..ffb42f8 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -35,7 +35,9 @@ func AddApiRoutes(httpRg *gin.RouterGroup) { httpRg.GET("/permissions/users", authApi.RbacController.GetUserPermissionsHandler) httpRg.GET("/roles", authApi.RbacController.GetAllRolesHandler) httpRg.GET("/roles/:id", authApi.RbacController.GetRoleByIDHandler) + httpRg.PUT("/roles/:id", authApi.RbacController.UpdateRoleHandler) httpRg.DELETE("/roles/:id", authApi.RbacController.DeleteRoleHandler) + httpRg.GET("/roles/:id/users", authApi.RbacController.DeleteRoleHandler) // Namespace httpRg.GET("/namespace", api.NamespaceController().GetNamespaceList) From 8f6e45f56c2dc7efa8df4127ea16d117bef6bbce Mon Sep 17 00:00:00 2001 From: Nahid Date: Tue, 4 Feb 2025 14:55:41 +0600 Subject: [PATCH 43/64] chore: replace route function name --- pkg/server/router/routes.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index ffb42f8..c87d549 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -37,7 +37,7 @@ func AddApiRoutes(httpRg *gin.RouterGroup) { httpRg.GET("/roles/:id", authApi.RbacController.GetRoleByIDHandler) httpRg.PUT("/roles/:id", authApi.RbacController.UpdateRoleHandler) httpRg.DELETE("/roles/:id", authApi.RbacController.DeleteRoleHandler) - httpRg.GET("/roles/:id/users", authApi.RbacController.DeleteRoleHandler) + httpRg.GET("/roles/:id/users", authApi.RbacController.GetUsersByRoleIDHandler) // Namespace httpRg.GET("/namespace", api.NamespaceController().GetNamespaceList) From 1d6c71eee2762cf5b5e5b9b7007c63530b2587ee Mon Sep 17 00:00:00 2001 From: Md Sajal Mia Date: Tue, 4 Feb 2025 18:25:27 +0600 Subject: [PATCH 44/64] Frontend --- .gitignore | 6 +- frontend/.browserslistrc | 12 + frontend/.dockerignore | 1 + frontend/.prettierignore | 5 + frontend/.prettierrc | 14 + frontend/Dockerfile | 41 + frontend/Dockerfile2 | 22 + frontend/README.md | 30 + frontend/angular.json | 349 + frontend/dashboard.json | 0 frontend/e2e/protractor.conf.js | 30 + frontend/e2e/src/app.e2e-spec.ts | 25 + frontend/e2e/src/app.po.ts | 11 + frontend/e2e/tsconfig.json | 9 + frontend/karma.conf.js | 32 + frontend/nginx/default.conf | 30 + frontend/nginx/nginx.conf | 31 + frontend/package-lock.json | 16745 ++++++++++++++++ frontend/package.json | 93 + frontend/projects/cdk-ui/README.md | 25 + frontend/projects/cdk-ui/index.ts | 4 + frontend/projects/cdk-ui/karma.conf.js | 41 + frontend/projects/cdk-ui/ng-package.json | 15 + frontend/projects/cdk-ui/package.json | 15 + .../cdk-ui/src/clipboard/DOCUMENTATION.md | 13 + .../src/clipboard/clipboard.component.ts | 44 + .../cdk-ui/src/clipboard/clipboard.module.ts | 12 + .../projects/cdk-ui/src/clipboard/index.ts | 1 + .../cdk-ui/src/clipboard/ng-package.json | 5 + .../cdk-ui/src/clipboard/public-api.ts | 2 + .../projects/cdk-ui/src/hint/DOCUMENTATION.md | 13 + .../cdk-ui/src/hint/hint.component.ts | 96 + .../projects/cdk-ui/src/hint/hint.module.ts | 11 + frontend/projects/cdk-ui/src/hint/index.ts | 1 + .../projects/cdk-ui/src/hint/ng-package.json | 5 + .../projects/cdk-ui/src/hint/public-api.ts | 2 + .../horizontal-stepper.component.html | 28 + .../horizontal-stepper.component.ts | 15 + .../horizontal-stepper.module.ts | 13 + .../cdk-ui/src/horizontal-stepper/index.ts | 1 + .../src/horizontal-stepper/ng-package.json | 5 + .../src/horizontal-stepper/public-api.ts | 2 + .../projects/cdk-ui/src/icon/DOCUMENTATION.md | 21 + .../cdk-ui/src/icon/icon.component.ts | 41 + .../cdk-ui/src/icon/icon.interfaces.ts | 1 + .../projects/cdk-ui/src/icon/icon.module.ts | 10 + frontend/projects/cdk-ui/src/icon/index.ts | 1 + .../projects/cdk-ui/src/icon/ng-package.json | 5 + .../projects/cdk-ui/src/icon/public-api.ts | 3 + frontend/projects/cdk-ui/src/test.ts | 25 + .../cdk-ui/src/tooltip/DOCUMENTATION.md | 18 + frontend/projects/cdk-ui/src/tooltip/index.ts | 1 + .../cdk-ui/src/tooltip/ng-package.json | 5 + .../projects/cdk-ui/src/tooltip/public-api.ts | 3 + .../src/tooltip/tooltip-content.component.ts | 40 + .../cdk-ui/src/tooltip/tooltip.directive.ts | 88 + .../cdk-ui/src/tooltip/tooltip.module.ts | 9 + .../cdk-ui/styles/all-components.scss | 5 + .../projects/cdk-ui/styles/clipboard.scss | 54 + frontend/projects/cdk-ui/styles/hint.scss | 15 + .../cdk-ui/styles/horizontal-stepper.scss | 183 + frontend/projects/cdk-ui/styles/icon.scss | 22 + frontend/projects/cdk-ui/styles/tooltip.scss | 23 + frontend/projects/cdk-ui/tsconfig.lib.json | 12 + .../projects/cdk-ui/tsconfig.lib.prod.json | 10 + frontend/projects/cdk-ui/tsconfig.spec.json | 10 + frontend/projects/core-ui/README.md | 25 + frontend/projects/core-ui/index.ts | 4 + frontend/projects/core-ui/karma.conf.js | 41 + frontend/projects/core-ui/ng-package.json | 8 + frontend/projects/core-ui/package.json | 13 + .../constants/constants.injection-token.ts | 1 + .../projects/core-ui/src/constants/index.ts | 1 + .../core-ui/src/constants/ng-package.json | 5 + .../directives/has-any-authority.directive.ts | 39 + .../projects/core-ui/src/directives/index.ts | 1 + .../core-ui/src/directives/ng-package.json | 5 + .../core-ui/src/guards/admin.guard.ts | 76 + .../projects/core-ui/src/guards/auth.guard.ts | 54 + frontend/projects/core-ui/src/guards/index.ts | 4 + .../core-ui/src/guards/ng-package.json | 5 + .../core-ui/src/guards/role-guard.service.ts | 102 + .../projects/core-ui/src/guards/role.guard.ts | 61 + .../core-ui/src/initializer.module.ts | 18 + .../src/interceptors/auth.interceptor.ts | 68 + .../src/interceptors/errors.interceptor.ts | 72 + .../core-ui/src/interceptors/index.ts | 2 + .../core-ui/src/interceptors/ng-package.json | 5 + .../src/interfaces/deep-partial.type.ts | 7 + .../core-ui/src/interfaces/environment.ts | 5 + .../projects/core-ui/src/interfaces/index.ts | 2 + .../core-ui/src/interfaces/ng-package.json | 5 + frontend/projects/core-ui/src/models/index.ts | 1 + .../core-ui/src/models/ng-package.json | 5 + .../projects/core-ui/src/models/user-role.ts | 1 + .../core-config/core-config.interfaces.ts | 33 + .../core-config/core-config.service.ts | 45 + .../src/services/core-config/core-config.ts | 21 + .../core-ui/src/services/core-config/index.ts | 3 + .../core-ui/src/services/http.service.ts | 71 + .../projects/core-ui/src/services/index.ts | 1 + .../core-ui/src/services/ng-package.json | 5 + .../src/services/permission.service.ts | 68 + .../core-ui/src/services/public-api.ts | 7 + .../core-ui/src/services/requester.service.ts | 175 + frontend/projects/core-ui/src/test.ts | 25 + .../core-ui/src/utils/flatten-deep.ts | 3 + .../core-ui/src/utils/flatten-object.ts | 29 + frontend/projects/core-ui/src/utils/index.ts | 6 + .../projects/core-ui/src/utils/merge-deep.ts | 32 + .../core-ui/src/utils/ng-package.json | 5 + .../projects/core-ui/src/utils/to-params.ts | 11 + .../projects/core-ui/src/utils/to-query.ts | 13 + .../projects/core-ui/src/utils/track-by.ts | 25 + frontend/projects/core-ui/tsconfig.lib.json | 12 + .../projects/core-ui/tsconfig.lib.prod.json | 10 + frontend/projects/core-ui/tsconfig.spec.json | 10 + frontend/projects/sdk-ui/README.md | 25 + .../assets/images/favicon_klovercloud.ico | Bin 0 -> 1150 bytes .../assets/images/ic_klovercloud_logo.png | Bin 0 -> 6063 bytes .../sdk-ui/assets/images/logo-dark.svg | 16 + .../sdk-ui/assets/images/logo-favicon.ico | Bin 0 -> 93062 bytes .../sdk-ui/assets/images/logo-inverse.png | Bin 0 -> 1970 bytes .../assets/images/logo-klovercloud-01.png | Bin 0 -> 32419 bytes .../sdk-ui/assets/images/logo-light.svg | 16 + .../sdk-ui/assets/images/logo_klovercloud.png | Bin 0 -> 9539 bytes .../assets/images/toastr/icon-error.svg | 48 + .../images/toastr/icon-notification.svg | 2 + .../assets/images/toastr/icon-success.svg | 43 + .../sdk-ui/assets/images/toastr/icon-warn.svg | 48 + .../sdk-ui/assets/scss/argo/variables.scss | 43 + .../projects/sdk-ui/assets/styles/_base.scss | 54 + .../sdk-ui/assets/styles/_fonticon.scss | 351 + .../projects/sdk-ui/assets/styles/_root.scss | 504 + .../sdk-ui/assets/styles/_utilities.scss | 112 + .../projects/sdk-ui/assets/styles/_var.scss | 343 + .../sdk-ui/assets/styles/components/_btn.scss | 166 + .../assets/styles/components/_filter.scss | 272 + .../assets/styles/components/_form.scss | 12 + .../assets/styles/components/_icon.scss | 45 + .../assets/styles/components/_status.scss | 25 + .../assets/styles/components/index.scss | 6 + .../components/table/_table-accordion.scss | 143 + .../styles/components/table/_table-kc.scss | 36 + .../styles/components/table/_table-label.scss | 52 + .../styles/components/table/_table-ui.scss | 35 + .../assets/styles/components/table/index.scss | 4 + .../projects/sdk-ui/assets/styles/core.scss | 853 + .../assets/styles/partials/_horizontal.scss | 50 + .../assets/styles/partials/_mixins.scss | 107 + .../assets/styles/partials/_overrides.scss | 18 + .../sdk-ui/assets/styles/partials/_print.scss | 37 + .../assets/styles/partials/_scrollbar.scss | 22 + .../assets/styles/partials/_vertical.scss | 30 + .../partials/plugins/_angular-calendar.scss | 193 + .../partials/plugins/_angular-material.scss | 112 + .../styles/partials/plugins/_apexcharts.scss | 8 + .../styles/partials/styles/_style-dark.scss | 153 + .../partials/styles/_style-light-pink.scss | 147 + .../styles/partials/styles/_style-light.scss | 116 + .../assets/styles/plugins/_cdk-overlay.scss | 108 + .../sdk-ui/assets/styles/plugins/_charts.scss | 12 + .../sdk-ui/assets/styles/plugins/_owl-dt.scss | 770 + .../assets/styles/plugins/_snackbar.scss | 4 + .../assets/styles/plugins/_tooltip.scss | 15 + .../assets/styles/plugins/form/_checkbox.scss | 79 + .../assets/styles/plugins/form/_input.scss | 196 + .../styles/plugins/form/_select-panel.scss | 7 + .../assets/styles/plugins/form/index.scss | 3 + .../sdk-ui/assets/styles/plugins/index.scss | 6 + .../sdk-ui/assets/styles/tailwind.scss | 5 + .../assets/webfonts/klovercloud-icon.eot | Bin 0 -> 22312 bytes .../assets/webfonts/klovercloud-icon.svg | 67 + .../assets/webfonts/klovercloud-icon.ttf | Bin 0 -> 22112 bytes .../assets/webfonts/klovercloud-icon.woff | Bin 0 -> 22188 bytes frontend/projects/sdk-ui/index.ts | 1 + frontend/projects/sdk-ui/karma.conf.js | 41 + frontend/projects/sdk-ui/ng-package.json | 17 + frontend/projects/sdk-ui/package.json | 12 + .../src/animations/dropdown.animation.ts | 19 + .../src/animations/fade-in-right.animation.ts | 21 + .../src/animations/fade-in-up.animation.ts | 21 + .../projects/sdk-ui/src/animations/index.ts | 1 + .../sdk-ui/src/animations/ng-package.json | 5 + .../src/animations/popover.animation.ts | 35 + .../sdk-ui/src/animations/public-api.ts | 8 + .../src/animations/scale-fade-in.animation.ts | 21 + .../src/animations/scale-in-out.animation.ts | 30 + .../src/animations/scale-in.animation.ts | 19 + .../src/animations/stagger.animation.ts | 15 + .../base-route-pagination.component.ts | 78 + .../src/components/base-table.componenet.ts | 22 + .../projects/sdk-ui/src/components/index.ts | 2 + .../sdk-ui/src/components/ng-package.json | 5 + .../container/container.directive.spec.ts | 8 + .../container/container.directive.ts | 12 + .../directives/container/container.module.ts | 10 + .../sdk-ui/src/directives/container/index.ts | 2 + .../projects/sdk-ui/src/directives/index.ts | 1 + .../sdk-ui/src/directives/ng-package.json | 5 + .../sdk-ui/src/interfaces/config.interface.ts | 32 + .../src/interfaces/css-variable.enum.ts | 537 + .../projects/sdk-ui/src/interfaces/index.ts | 6 + .../src/interfaces/kc-route.interface.ts | 16 + .../interfaces/navigation-item.interface.ts | 40 + .../sdk-ui/src/interfaces/ng-package.json | 5 + .../src/interfaces/table-column.interface.ts | 7 + .../interfaces/toolbar-menu-item.interface.ts | 12 + frontend/projects/sdk-ui/src/layout/index.ts | 2 + .../sdk-ui/src/layout/layout.component.html | 35 + .../sdk-ui/src/layout/layout.component.scss | 98 + .../src/layout/layout.component.spec.ts | 24 + .../sdk-ui/src/layout/layout.component.ts | 209 + .../sdk-ui/src/layout/layout.module.ts | 27 + .../navigation-item.component.html | 124 + .../navigation-item.component.scss | 25 + .../navigation-item.component.spec.ts | 24 + .../navigation-item.component.ts | 59 + .../navigation-item/navigation-item.module.ts | 15 + .../navigation/navigation.component.html | 3 + .../navigation/navigation.component.scss | 11 + .../navigation/navigation.component.spec.ts | 24 + .../layout/navigation/navigation.component.ts | 15 + .../layout/navigation/navigation.module.ts | 28 + .../sdk-ui/src/layout/ng-package.json | 5 + .../sidenav-item/sidenav-item.component.html | 73 + .../sidenav-item/sidenav-item.component.scss | 108 + .../sidenav-item.component.spec.ts | 24 + .../sidenav-item/sidenav-item.component.ts | 140 + .../sidenav-item/sidenav-item.module.ts | 16 + .../src/layout/sidenav/sidenav.component.html | 60 + .../src/layout/sidenav/sidenav.component.scss | 105 + .../layout/sidenav/sidenav.component.spec.ts | 24 + .../src/layout/sidenav/sidenav.component.ts | 52 + .../src/layout/sidenav/sidenav.module.ts | 16 + .../toolbar-user-dropdown.component.html | 76 + .../toolbar-user-dropdown.component.scss | 131 + .../toolbar-user-dropdown.component.spec.ts | 24 + .../toolbar-user-dropdown.component.ts | 55 + .../toolbar-user/toolbar-user.component.html | 45 + .../toolbar-user/toolbar-user.component.scss | 41 + .../toolbar-user.component.spec.ts | 24 + .../toolbar-user/toolbar-user.component.ts | 56 + .../toolbar-user/toolbar-user.module.ts | 31 + .../src/layout/toolbar/toolbar.component.html | 83 + .../src/layout/toolbar/toolbar.component.scss | 147 + .../layout/toolbar/toolbar.component.spec.ts | 24 + .../src/layout/toolbar/toolbar.component.ts | 50 + .../src/layout/toolbar/toolbar.module.ts | 41 + frontend/projects/sdk-ui/src/pipes/index.ts | 5 + .../projects/sdk-ui/src/pipes/ng-package.json | 5 + .../src/pipes/safe-html/safe-html.module.ts | 10 + .../src/pipes/safe-html/safe-html.pipe.ts | 13 + .../src/pipes/safe-style/safe-style.module.ts | 10 + .../pipes/safe-style/safe-style.pipe.spec.ts | 8 + .../src/pipes/safe-style/safe-style.pipe.ts | 13 + frontend/projects/sdk-ui/src/sdk-ui.module.ts | 35 + .../sdk-ui/src/services/config.service.ts | 33 + .../projects/sdk-ui/src/services/index.ts | 1 + .../src/services/layout.service.spec.ts | 12 + .../sdk-ui/src/services/layout.service.ts | 101 + .../src/services/navigation.service.spec.ts | 12 + .../sdk-ui/src/services/navigation.service.ts | 40 + .../sdk-ui/src/services/ng-package.json | 5 + .../sdk-ui/src/services/public-api.ts | 8 + .../services/splash-screen.service.spec.ts | 12 + .../src/services/splash-screen.service.ts | 36 + .../sdk-ui/src/services/style.service.ts | 61 + .../sdk-ui/src/services/toolbar.service.ts | 18 + frontend/projects/sdk-ui/src/test-setup.ts | 7 + .../sdk-ui/src/ui/img/img.component.ts | 34 + .../projects/sdk-ui/src/ui/img/img.module.ts | 10 + frontend/projects/sdk-ui/src/ui/img/index.ts | 2 + frontend/projects/sdk-ui/src/ui/index.ts | 8 + .../sdk-ui/src/ui/loading-bar/index.ts | 2 + .../loading-bar/loading-bar-router.module.ts | 37 + .../src/ui/loading-bar/loading-bar.config.ts | 7 + .../src/ui/loading-bar/loading-bar.service.ts | 84 + .../src/ui/loading-bar/loading-bar.state.ts | 159 + frontend/projects/sdk-ui/src/ui/logo/index.ts | 2 + .../sdk-ui/src/ui/logo/logo.component.ts | 69 + .../sdk-ui/src/ui/logo/logo.module.ts | 10 + .../projects/sdk-ui/src/ui/ng-package.json | 5 + .../sdk-ui/src/ui/page-layout/index.ts | 4 + .../page-layout-content.directive.ts | 11 + .../page-layout-header.directive.ts | 11 + .../ui/page-layout/page-layout.component.scss | 50 + .../ui/page-layout/page-layout.component.ts | 24 + .../src/ui/page-layout/page-layout.module.ts | 12 + .../projects/sdk-ui/src/ui/popover/index.ts | 4 + .../sdk-ui/src/ui/popover/popover-ref.ts | 38 + .../src/ui/popover/popover.component.html | 11 + .../src/ui/popover/popover.component.scss | 0 .../src/ui/popover/popover.component.ts | 31 + .../sdk-ui/src/ui/popover/popover.module.ts | 10 + .../sdk-ui/src/ui/popover/popover.service.ts | 83 + .../sdk-ui/src/ui/progress-bar/index.ts | 2 + .../progress-bar/progress-bar.component.html | 7 + .../progress-bar/progress-bar.component.scss | 29 + .../progress-bar.component.spec.ts | 24 + .../ui/progress-bar/progress-bar.component.ts | 13 + .../ui/progress-bar/progress-bar.module.ts | 12 + .../sdk-ui/src/ui/secondary-toolbar/index.ts | 2 + .../secondary-toolbar.component.html | 10 + .../secondary-toolbar.component.scss | 8 + .../secondary-toolbar.component.spec.ts | 0 .../secondary-toolbar.component.ts | 11 + .../secondary-toolbar.module.ts | 16 + .../projects/sdk-ui/src/ui/toastr/index.ts | 5 + .../src/ui/toastr/toastr.component.html | 18 + .../src/ui/toastr/toastr.component.scss | 121 + .../sdk-ui/src/ui/toastr/toastr.component.ts | 19 + .../sdk-ui/src/ui/toastr/toastr.data.ts | 4 + .../sdk-ui/src/ui/toastr/toastr.directive.ts | 13 + .../sdk-ui/src/ui/toastr/toastr.interface.ts | 9 + .../sdk-ui/src/ui/toastr/toastr.module.ts | 12 + .../sdk-ui/src/ui/toastr/toastr.service.ts | 83 + .../src/utils/check-router-childs-data.ts | 13 + frontend/projects/sdk-ui/src/utils/index.ts | 1 + .../projects/sdk-ui/src/utils/ng-package.json | 5 + frontend/projects/sdk-ui/tsconfig.lib.json | 12 + .../projects/sdk-ui/tsconfig.lib.prod.json | 10 + frontend/projects/sdk-ui/tsconfig.spec.json | 10 + frontend/projects/shared-ui/README.md | 25 + frontend/projects/shared-ui/index.ts | 8 + frontend/projects/shared-ui/karma.conf.js | 41 + frontend/projects/shared-ui/ng-package.json | 7 + frontend/projects/shared-ui/package.json | 11 + frontend/projects/shared-ui/src/index.ts | 1 + .../projects/shared-ui/src/pipes/ago.pipe.ts | 32 + .../src/pipes/boolean-to-text.pipe.ts | 15 + .../shared-ui/src/pipes/duration.pipe.ts | 24 + .../shared-ui/src/pipes/enum-to-value.pipe.ts | 12 + .../shared-ui/src/pipes/format-cpu.pipe.ts | 18 + .../src/pipes/format-data-size.pipe.ts | 17 + .../src/pipes/format-empty-string.ts | 13 + .../shared-ui/src/pipes/format-memory.pipe.ts | 20 + .../projects/shared-ui/src/pipes/index.ts | 11 + .../projects/shared-ui/src/pipes/sort.pipe.ts | 16 + .../shared-ui/src/pipes/str-replace.pipe.ts | 11 + .../projects/shared-ui/src/shared.module.ts | 101 + frontend/projects/shared-ui/src/test.ts | 25 + .../config-dialog-static.interfaces.ts | 14 + .../confirm-dialog-static.component.html | 40 + .../confirm-dialog-static.component.scss | 48 + .../confirm-dialog-static.component.ts | 85 + .../confirm-dialog.component.html | 17 + .../confirm-dialog.component.scss | 30 + .../confirm-dialog.component.ts | 24 + .../delete-config-dialog.interfaces.ts | 4 + .../delete-confirm-dialog.component.html | 23 + .../delete-confirm-dialog.component.scss | 32 + .../delete-confirm-dialog.component.ts | 52 + frontend/projects/shared-ui/src/ui/index.ts | 9 + .../nothing-found.component.html | 4 + .../nothing-found.component.scss | 27 + .../nothing-found/nothing-found.component.ts | 14 + .../secure-delete-dialog.component.html | 26 + .../secure-delete-dialog.component.scss | 46 + .../secure-delete-dialog.component.ts | 76 + frontend/projects/shared-ui/src/utils/argo.ts | 59 + .../projects/shared-ui/src/utils/index.ts | 4 + .../src/utils/k8s-resources-short-name.ts | 37 + .../shared-ui/src/utils/k8s-routes.ts | 61 + .../projects/shared-ui/src/utils/utils.ts | 104 + .../src/validators/array.validators.ts | 155 + .../src/validators/custom.dns.validators.ts | 101 + .../database.password.validators.ts | 32 + .../src/validators/email.validator.ts | 57 + .../shared-ui/src/validators/index.ts | 12 + .../src/validators/inputs.validators.ts | 12 + .../src/validators/must-match.validator.ts | 22 + .../validators/no-white-space.validator.ts | 6 + .../src/validators/password.validator.ts | 42 + .../src/validators/space.validators.ts | 9 + .../src/validators/unique.validator.ts | 73 + .../src/validators/vpc.name.validators.ts | 12 + frontend/projects/shared-ui/tsconfig.lib.json | 12 + .../projects/shared-ui/tsconfig.lib.prod.json | 10 + .../projects/shared-ui/tsconfig.spec.json | 10 + frontend/run.sh | 13 + frontend/src/app/app.component.html | 1 + frontend/src/app/app.component.scss | 0 frontend/src/app/app.component.spec.ts | 31 + frontend/src/app/app.component.ts | 67 + frontend/src/app/app.module.ts | 57 + frontend/src/app/app.routes.ts | 94 + frontend/src/app/auth/auth-routing.module.ts | 29 + frontend/src/app/auth/auth.endpoints.ts | 2 + frontend/src/app/auth/auth.interface.ts | 9 + frontend/src/app/auth/auth.module.ts | 45 + frontend/src/app/auth/auth.service.ts | 64 + .../src/app/auth/login/login.component.html | 91 + .../src/app/auth/login/login.component.scss | 368 + .../app/auth/login/login.component.spec.ts | 24 + .../src/app/auth/login/login.component.ts | 143 + frontend/src/app/cluster/ClusterFormData.ts | 534 + .../cluster-details.component.html | 118 + .../cluster-details.component.scss | 35 + .../cluster-details.component.spec.ts | 24 + .../cluster-details.component.ts | 135 + .../cluster-details/logs/logs.component.html | 105 + .../cluster-details/logs/logs.component.scss | 491 + .../logs/logs.component.spec.ts | 22 + .../cluster-details/logs/logs.component.ts | 366 + ...cluster-release-note-dialog.component.html | 56 + ...cluster-release-note-dialog.component.scss | 63 + .../cluster-release-note-dialog.component.ts | 50 + .../overview/overview.component.html | 993 + .../overview/overview.component.scss | 132 + .../overview/overview.component.spec.ts | 24 + .../overview/overview.component.ts | 154 + .../cluster-update-form.component.html | 647 + .../cluster-update-form.component.scss | 68 + .../cluster-update-form.component.spec.ts | 24 + .../cluster-update-form.component.ts | 370 + .../confirm-delete-dialogue.component.html | 26 + .../confirm-delete-dialogue.component.scss | 46 + .../confirm-delete-dialogue.component.ts | 70 + .../settings/settings.component.html | 187 + .../settings/settings.component.scss | 169 + .../settings/settings.component.spec.ts | 24 + .../settings/settings.component.ts | 205 + .../cluster-intro.component.html | 314 + .../cluster-intro.component.scss | 83 + .../cluster-intro.component.spec.ts | 22 + .../cluster-intro/cluster-intro.component.ts | 12 + .../cluster-list/cluster-list.component.html | 40 + .../cluster-list/cluster-list.component.scss | 179 + .../cluster-list.component.spec.ts | 24 + .../cluster-list/cluster-list.component.ts | 59 + .../src/app/cluster/cluster-routing.module.ts | 86 + frontend/src/app/cluster/cluster.constants.ts | 6 + frontend/src/app/cluster/cluster.endpoint.ts | 26 + frontend/src/app/cluster/cluster.interface.ts | 5 + frontend/src/app/cluster/cluster.module.ts | 102 + frontend/src/app/cluster/cluster.resolver.ts | 28 + frontend/src/app/cluster/cluster.service.ts | 192 + .../existing-cluster-form.component.html | 1713 ++ .../existing-cluster-form.component.scss | 145 + .../existing-cluster-form.component.spec.ts | 24 + .../existing-cluster-form.component.ts | 478 + ...nboard-cluster-prerequisite.component.html | 454 + ...nboard-cluster-prerequisite.component.scss | 72 + ...ard-cluster-prerequisite.component.spec.ts | 22 + .../onboard-cluster-prerequisite.component.ts | 61 + .../error-403/error-403-routing.module.ts | 24 + .../errors/error-403/error-403.component.html | 12 + .../errors/error-403/error-403.component.scss | 0 .../errors/error-403/error-403.component.ts | 29 + .../app/errors/error-403/error-403.module.ts | 14 + .../error-404/error-404-routing.module.ts | 25 + .../errors/error-404/error-404.component.html | 6 + .../errors/error-404/error-404.component.scss | 0 .../error-404/error-404.component.spec.ts | 24 + .../errors/error-404/error-404.component.ts | 25 + .../app/errors/error-404/error-404.module.ts | 13 + .../error-500/error-500-routing.module.ts | 21 + .../errors/error-500/error-500.component.html | 20 + .../errors/error-500/error-500.component.scss | 0 .../error-500/error-500.component.spec.ts | 24 + .../errors/error-500/error-500.component.ts | 15 + .../app/errors/error-500/error-500.module.ts | 13 + ...ansion-data-viewer-template.component.html | 11 + ...ansion-data-viewer-template.component.scss | 36 + ...xpansion-data-viewer-template.component.ts | 33 + .../json-data-viewer-template.component.html | 30 + .../json-data-viewer-template.component.scss | 16 + .../json-data-viewer-template.component.ts | 26 + .../json-data-viewer.component.html | 34 + .../json-data-viewer.component.scss | 16 + .../json-data-viewer.component.ts | 32 + .../k8s-events-template.component.html | 47 + .../k8s-events-template.component.scss | 0 .../k8s-events-template.component.ts | 44 + .../metadata-template.component.html | 70 + .../metadata-template.component.scss | 0 .../metadata-template.component.spec.ts | 22 + .../metadata-template.component.ts | 20 + ...esources-defination-details.component.html | 133 + ...esources-defination-details.component.scss | 0 ...-resources-defination-details.component.ts | 55 + ...m-resources-defination-list.component.html | 126 + ...m-resources-defination-list.component.scss | 13 + ...tom-resources-defination-list.component.ts | 332 + .../custom-resources-details.component.html | 122 + .../custom-resources-details.component.scss | 0 .../custom-resources-details.component.ts | 168 + .../custom-resources-list.component.html | 154 + .../custom-resources-list.component.scss | 12 + .../custom-resources-list.component.ts | 314 + ...cluster-custom-resources-routing.module.ts | 49 + .../k8s-cluster-custom-resources.endpoints.ts | 2 + .../k8s-cluster-custom-resources.module.ts | 57 + .../k8s-cluster-custom-resources.service.ts | 93 + ...luster-role-binding-details.component.html | 131 + ...luster-role-binding-details.component.scss | 3 + ...-cluster-role-binding-details.component.ts | 149 + ...s-cluster-role-binding-list.component.html | 135 + ...s-cluster-role-binding-list.component.scss | 4 + ...k8s-cluster-role-binding-list.component.ts | 302 + ...k8s-cluster-role-binding-routing.module.ts | 37 + .../k8s-cluster-role-binding.endpoints.ts | 1 + .../k8s-cluster-role-binding.module.ts | 50 + .../k8s-cluster-role-binding.service.ts | 56 + .../k8s-cluster-role-details.component.html | 122 + .../k8s-cluster-role-details.component.scss | 0 .../k8s-cluster-role-details.component.ts | 147 + .../k8s-cluster-role-list.component.html | 135 + .../k8s-cluster-role-list.component.scss | 4 + .../k8s-cluster-role-list.component.ts | 303 + .../k8s-cluster-role-routing.module.ts | 37 + .../k8s-cluster-role.endpoints.ts | 1 + .../k8s-cluster-role.module.ts | 52 + .../k8s-cluster-role.service.ts | 54 + .../k8s-certificates-details.component.html | 143 + .../k8s-certificates-details.component.scss | 0 .../k8s-certificates-details.component.ts | 149 + .../k8s-certificates.component.html | 127 + .../k8s-certificates.component.scss | 4 + .../k8s-certificates.component.ts | 276 + .../k8s-config-maps-details.component.html | 65 + .../k8s-config-maps-details.component.spec.ts | 24 + .../k8s-config-maps-details.component.ts | 139 + .../k8s-config-maps.component.html | 126 + .../k8s-config-maps.component.scss | 4 + .../k8s-config-maps.component.ts | 287 + ...controller-revision-details.component.html | 48 + ...controller-revision-details.component.scss | 0 ...s-controller-revision-details.component.ts | 139 + .../k8s-controller-revision.component.html | 126 + .../k8s-controller-revision.component.scss | 0 .../k8s-controller-revision.component.spec.ts | 22 + .../k8s-controller-revision.component.ts | 271 + .../k8s-cron-job-details.component.html | 335 + .../k8s-cron-job-details.component.scss | 0 .../k8s-cron-job-details.component.ts | 148 + .../k8s-cron-job/k8s-cron-job.component.html | 126 + .../k8s-cron-job/k8s-cron-job.component.scss | 4 + .../k8s-cron-job.component.spec.ts | 24 + .../k8s-cron-job/k8s-cron-job.component.ts | 279 + .../k8s-daemon-sets-details.component.html | 437 + .../k8s-daemon-sets-details.component.scss | 43 + .../k8s-daemon-sets-details.component.ts | 175 + .../k8s-daemon-sets.component.html | 166 + .../k8s-daemon-sets.component.scss | 76 + .../k8s-daemon-sets.component.ts | 307 + .../k8s-deployment-pod-list.component.html | 124 + .../k8s-deployment-pod-list.component.scss | 0 .../k8s-deployment-pod-list.component.ts | 248 + .../k8s-deployments-details.component.html | 462 + .../k8s-deployments-details.component.scss | 59 + .../k8s-deployments-details.component.ts | 188 + .../k8s-deployments.component.html | 165 + .../k8s-deployments.component.scss | 88 + .../k8s-deployments.component.ts | 305 + .../k8s-endpoint-slice-details.component.html | 57 + .../k8s-endpoint-slice-details.component.scss | 0 .../k8s-endpoint-slice-details.component.ts | 139 + .../k8s-endpoint-slice.component.html | 126 + .../k8s-endpoint-slice.component.scss | 0 .../k8s-endpoint-slice.component.spec.ts | 22 + .../k8s-endpoint-slice.component.ts | 273 + .../k8s-endpoints-details.component.html | 50 + .../k8s-endpoints-details.component.scss | 0 .../k8s-endpoints-details.component.ts | 139 + .../k8s-endpoints.component.html | 126 + .../k8s-endpoints.component.scss | 0 .../k8s-endpoints.component.spec.ts | 22 + .../k8s-endpoints/k8s-endpoints.component.ts | 270 + .../k8s-gateway-details.component.html | 127 + .../k8s-gateway-details.component.scss | 0 .../k8s-gateway-details.component.ts | 147 + .../k8s-gateway/k8s-gateway.component.html | 118 + .../k8s-gateway/k8s-gateway.component.scss | 0 .../k8s-gateway/k8s-gateway.component.ts | 221 + .../k8s-ingresses-details.component.html | 73 + .../k8s-ingresses-details.component.scss | 0 .../k8s-ingresses-details.component.ts | 137 + .../k8s-ingresses.component.html | 131 + .../k8s-ingresses.component.scss | 4 + .../k8s-ingresses/k8s-ingresses.component.ts | 276 + .../k8s-job-details.component.html | 335 + .../k8s-job-details.component.scss | 0 .../k8s-job-details.component.spec.ts | 24 + .../k8s-job-details.component.ts | 148 + .../k8s-job/k8s-job.component.html | 126 + .../k8s-job/k8s-job.component.scss | 4 + .../k8s-job/k8s-job.component.ts | 278 + .../k8s-namespaces-details.component.html | 114 + .../k8s-namespaces-details.component.scss | 3 + .../k8s-namespaces-details.component.ts | 39 + .../k8s-namespaces-list.component.html | 132 + .../k8s-namespaces-list.component.scss | 62 + .../k8s-namespaces-list.component.ts | 372 + .../k8s-namespaces-routing.module.ts | 637 + .../k8s-namespaces.component.html | 135 + .../k8s-namespaces.component.scss | 91 + .../k8s-namespaces.component.ts | 102 + .../k8s-namespaces.endpoints.ts | 45 + .../k8s-namespaces/k8s-namespaces.module.ts | 183 + .../k8s-namespaces/k8s-namespaces.service.ts | 816 + .../k8s-network-policy-details.component.html | 98 + .../k8s-network-policy-details.component.scss | 0 .../k8s-network-policy-details.component.ts | 136 + .../k8s-network-policy.component.html | 126 + .../k8s-network-policy.component.scss | 4 + .../k8s-network-policy.component.ts | 276 + ...-disruption-budgets-details.component.html | 55 + ...-disruption-budgets-details.component.scss | 0 ...od-disruption-budgets-details.component.ts | 139 + .../k8s-pod-disruption-budgets.component.html | 126 + .../k8s-pod-disruption-budgets.component.scss | 0 ...s-pod-disruption-budgets.component.spec.ts | 22 + .../k8s-pod-disruption-budgets.component.ts | 269 + .../grafana-dashboard.component.html | 0 .../grafana-dashboard.component.scss | 18 + .../grafana-dashboard.component.spec.ts | 22 + .../grafana-dashboard.component.ts | 17 + .../k8s-pod-ws.service.ts | 58 + .../k8s-pods-container-log.component.html | 66 + .../k8s-pods-container-log.component.scss | 119 + .../k8s-pods-container-log.component.ts | 204 + .../k8s-pods-details.component.html | 536 + .../k8s-pods-details.component.scss | 99 + .../k8s-pods-details.component.ts | 244 + .../k8s-pods/k8s-pods.component.html | 257 + .../k8s-pods/k8s-pods.component.scss | 85 + .../k8s-pods/k8s-pods.component.ts | 416 + .../k8s-pvcs-details.component.html | 82 + .../k8s-pvcs-details.component.scss | 0 .../k8s-pvcs-details.component.ts | 137 + .../k8s-pvcs/k8s-pvcs.component.html | 139 + .../k8s-pvcs/k8s-pvcs.component.scss | 4 + .../k8s-pvcs/k8s-pvcs.component.ts | 277 + .../k8s-replica-sets-details.component.html | 383 + .../k8s-replica-sets-details.component.scss | 43 + .../k8s-replica-sets-details.component.ts | 158 + .../k8s-replica-sets.component.html | 139 + .../k8s-replica-sets.component.scss | 48 + .../k8s-replica-sets.component.ts | 276 + ...lication-controller-details.component.html | 41 + ...lication-controller-details.component.scss | 0 ...eplication-controller-details.component.ts | 139 + .../k8s-replication-controller.component.html | 126 + .../k8s-replication-controller.component.scss | 0 ...s-replication-controller.component.spec.ts | 22 + .../k8s-replication-controller.component.ts | 270 + .../k8s-resource-quota-details.component.html | 147 + .../k8s-resource-quota-details.component.scss | 0 .../k8s-resource-quota-details.component.ts | 136 + .../k8s-resource-quota.component.html | 126 + .../k8s-resource-quota.component.scss | 4 + .../k8s-resource-quota.component.ts | 277 + .../k8s-role-binding-details.component.html | 89 + .../k8s-role-binding-details.component.scss | 0 .../k8s-role-binding-details.component.ts | 140 + .../k8s-role-binding.component.html | 126 + .../k8s-role-binding.component.scss | 4 + .../k8s-role-binding.component.ts | 283 + .../k8s-role-details.component.html | 67 + .../k8s-role-details.component.scss | 0 .../k8s-role-details.component.ts | 140 + .../k8s-role/k8s-role.component.html | 127 + .../k8s-role/k8s-role.component.scss | 4 + .../k8s-role/k8s-role.component.ts | 279 + .../k8s-secrets-details.component.html | 74 + .../k8s-secrets-details.component.scss | 3 + .../k8s-secrets-details.component.spec.ts | 24 + .../k8s-secrets-details.component.ts | 139 + .../k8s-secrets/k8s-secrets.component.html | 133 + .../k8s-secrets/k8s-secrets.component.scss | 4 + .../k8s-secrets/k8s-secrets.component.ts | 280 + ...8s-service-accounts-details.component.html | 68 + ...service-accounts-details.component.spec.ts | 24 + .../k8s-service-accounts-details.component.ts | 138 + .../k8s-service-accounts.component.html | 125 + .../k8s-service-accounts.component.scss | 4 + .../k8s-service-accounts.component.ts | 279 + .../k8s-service-details.component.html | 155 + .../k8s-service-details.component.scss | 0 .../k8s-service-details.component.ts | 142 + .../k8s-service/k8s-service.component.html | 129 + .../k8s-service/k8s-service.component.scss | 4 + .../k8s-service/k8s-service.component.ts | 286 + .../k8s-stateful-sets-details.component.html | 454 + .../k8s-stateful-sets-details.component.scss | 59 + .../k8s-stateful-sets-details.component.ts | 174 + .../k8s-statefulset-pod-list.component.html | 124 + .../k8s-statefulset-pod-list.component.scss | 0 .../k8s-statefulset-pod-list.component.ts | 248 + .../k8s-stateful-sets.component.html | 168 + .../k8s-stateful-sets.component.scss | 77 + .../k8s-stateful-sets.component.spec.ts | 24 + .../k8s-stateful-sets.component.ts | 299 + ...k8s-virtual-service-details.component.html | 118 + ...k8s-virtual-service-details.component.scss | 0 .../k8s-virtual-service-details.component.ts | 146 + .../k8s-virtual-service.component.html | 130 + .../k8s-virtual-service.component.scss | 0 .../k8s-virtual-service.component.ts | 285 + .../k8s/k8s-nodes/k8s-nodes-routing.module.ts | 37 + .../app/k8s/k8s-nodes/k8s-nodes.endpoints.ts | 5 + .../src/app/k8s/k8s-nodes/k8s-nodes.module.ts | 59 + .../app/k8s/k8s-nodes/k8s-nodes.service.ts | 54 + .../node-details/node-details.component.html | 307 + .../node-details/node-details.component.scss | 74 + .../node-details/node-details.component.ts | 89 + .../node-list/node-list.component.html | 158 + .../node-list/node-list.component.scss | 84 + .../node-list/node-list.component.ts | 227 + .../node-taint-dialog.component.html | 127 + .../node-taint-dialog.component.scss | 0 .../node-taint-dialog.component.spec.ts | 22 + .../node-taint-dialog.component.ts | 169 + .../k8s-persistent-volume-routing.module.ts | 37 + .../k8s-persistent-volume.endpoints.ts | 1 + .../k8s-persistent-volume.module.ts | 50 + .../k8s-persistent-volume.service.ts | 56 + .../pv-details/pv-details.component.html | 214 + .../pv-details/pv-details.component.scss | 3 + .../pv-details/pv-details.component.ts | 140 + .../pv-list/pv-list.component.html | 136 + .../pv-list/pv-list.component.scss | 36 + .../pv-list/pv-list.component.ts | 300 + frontend/src/app/k8s/k8s-routing.module.ts | 81 + .../k8s-storage-class-details.component.html | 82 + .../k8s-storage-class-details.component.scss | 0 .../k8s-storage-class-details.component.ts | 156 + .../k8s-storage-class-list.component.html | 130 + .../k8s-storage-class-list.component.scss | 4 + .../k8s-storage-class-list.component.ts | 310 + .../k8s-storage-class-routing.module.ts | 37 + .../k8s-storage-class.component.scss | 0 .../k8s-storage-class.endpoints.ts | 1 + .../k8s-storage-class.module.ts | 52 + .../k8s-storage-class.service.ts | 56 + .../k8s-terminal-routing.module.ts | 22 + .../k8s/k8s-terminal/k8s-terminal.module.ts | 11 + .../pod-terminal/pod-terminal.component.html | 4 + .../pod-terminal/pod-terminal.component.scss | 0 .../pod-terminal/pod-terminal.component.ts | 120 + .../k8s/k8s-update/k8s-update.component.html | 54 + .../k8s/k8s-update/k8s-update.component.scss | 11 + .../k8s/k8s-update/k8s-update.component.ts | 222 + .../app/k8s/k8s-update/k8s-update.module.ts | 41 + frontend/src/app/k8s/k8s.component.html | 557 + frontend/src/app/k8s/k8s.component.scss | 302 + frontend/src/app/k8s/k8s.component.ts | 147 + frontend/src/app/k8s/k8s.endpoints.ts | 1 + frontend/src/app/k8s/k8s.module.ts | 55 + frontend/src/app/k8s/k8s.resolver.ts | 26 + frontend/src/app/k8s/k8s.service.ts | 44 + .../access-role/access-role-interface.ts | 33 + .../access-role/access-role-routing.module.ts | 45 + .../access-role/access-role.endpoints.ts | 4 + .../access-role/access-role.module.ts | 53 + .../access-role/access-role.service.ts | 40 + .../role-delete-conformation.component.html | 48 + .../role-delete-conformation.component.scss | 28 + ...role-delete-conformation.component.spec.ts | 24 + .../role-delete-conformation.component.ts | 56 + .../access-role-form.component.html | 145 + .../access-role-form.component.scss | 235 + .../access-role-form.component.ts | 178 + .../access-role-list.component.html | 110 + .../access-role-list.component.scss | 283 + .../access-role-list.component.ts | 70 + .../update-password.component.html | 83 + .../update-password.component.scss | 9 + .../update-password.component.spec.ts | 24 + .../update-password.component.ts | 99 + .../user-details/user-details.component.html | 70 + .../user-details/user-details.component.scss | 70 + .../user-details.component.spec.ts | 24 + .../user-details/user-details.component.ts | 60 + .../user-permission-item.component.html | 26 + .../user-permission-item.component.scss | 50 + .../user-permission-item.component.spec.ts | 22 + .../user-permission-item.component.ts | 35 + .../user-role-update-form.component.html | 63 + .../user-role-update-form.component.scss | 0 .../user-role-update-form.component.spec.ts | 22 + .../user-role-update-form.component.ts | 95 + .../user/user-form/user-form.component.html | 168 + .../user/user-form/user-form.component.scss | 9 + .../user-form/user-form.component.spec.ts | 24 + .../user/user-form/user-form.component.ts | 147 + .../user/user-list/user-list.component.html | 114 + .../user/user-list/user-list.component.scss | 69 + .../user-list/user-list.component.spec.ts | 24 + .../user/user-list/user-list.component.ts | 124 + .../management/user/user-routing.module.ts | 32 + .../src/app/management/user/user.endpoints.ts | 4 + .../app/management/user/user.interfaces.ts | 4 + .../src/app/management/user/user.module.ts | 71 + .../app/management/user/user.service.spec.ts | 12 + .../src/app/management/user/user.service.ts | 37 + frontend/src/app/management/user/user.ts | 15 + .../app/settings/settings-routing.module.ts | 47 + frontend/src/app/settings/settings.module.ts | 74 + .../theme-info/theme-info.component.html | 42 + .../theme-info/theme-info.component.scss | 80 + .../theme-info/theme-info.component.spec.ts | 24 + .../theme-info/theme-info.component.ts | 80 + .../system-settings.component.html | 4 + .../system-settings.component.scss | 0 .../system-settings.component.spec.ts | 24 + .../system-settings.component.ts | 30 + .../system-settings-routing.module.ts | 21 + .../system-settings.endpoints.ts | 3 + .../system-settings/system-settings.module.ts | 53 + .../system-settings.service.ts | 16 + .../change-password.component.html | 104 + .../change-password.component.scss | 6 + .../change-password.component.spec.ts | 22 + .../change-password.component.ts | 125 + .../user-profile-details.component.html | 31 + .../user-profile-details.component.scss | 71 + .../user-profile-details.component.spec.ts | 24 + .../user-profile-details.component.ts | 39 + .../user-profile-routing.module.ts | 24 + .../app/user-profile/user-profile.module.ts | 39 + frontend/src/assets/.gitkeep | 0 .../src/assets/img/Backed by AWS Route 53.svg | 4 + frontend/src/assets/img/CASSANDRA-2.svg | 9 + frontend/src/assets/img/CASSANDRA.svg | 23 + frontend/src/assets/img/Cloud.svg | 210 + frontend/src/assets/img/Grafana_logo.svg | 9 + frontend/src/assets/img/Highly Available.svg | 5 + .../src/assets/img/Integrated Security.svg | 6 + frontend/src/assets/img/KAFKA.svg | 3 + .../src/assets/img/Latency Based Routing.svg | 9 + frontend/src/assets/img/MONGODB.svg | 1 + frontend/src/assets/img/MSSQL.svg | 19 + frontend/src/assets/img/MYSQL.svg | 6 + frontend/src/assets/img/POSTGRESQL-2.svg | 1 + frontend/src/assets/img/POSTGRESQL.svg | 6 + frontend/src/assets/img/RABBITMQ.svg | 3 + frontend/src/assets/img/REDIS-2.svg | 9 + frontend/src/assets/img/REDIS.svg | 18 + .../src/assets/img/Support DNS Failover.svg | 12 + frontend/src/assets/img/access.svg | 14 + frontend/src/assets/img/apache-server.svg | 143 + frontend/src/assets/img/app-home.svg | 149 + frontend/src/assets/img/application.svg | 10 + frontend/src/assets/img/automatic.svg | 121 + .../src/assets/img/automatic_database.svg | 121 + frontend/src/assets/img/bin.svg | 5 + frontend/src/assets/img/bitnami/cassandra.svg | 23 + frontend/src/assets/img/bitnami/grafana.svg | 9 + frontend/src/assets/img/bitnami/kafka.svg | 3 + frontend/src/assets/img/bitnami/mongodb.svg | 1 + frontend/src/assets/img/bitnami/mysql.svg | 6 + .../src/assets/img/bitnami/postgresql.svg | 6 + frontend/src/assets/img/bitnami/rabbitmq.svg | 3 + frontend/src/assets/img/bitnami/redis.svg | 18 + frontend/src/assets/img/bitnami/wordpress.svg | 5 + frontend/src/assets/img/bucket-icon.svg | 10 + frontend/src/assets/img/bucket.svg | 2 + frontend/src/assets/img/cache.svg | 14 + frontend/src/assets/img/cassandra-custom.svg | 9 + frontend/src/assets/img/checked-2.svg | 4 + frontend/src/assets/img/checked.svg | 4 + frontend/src/assets/img/cloud-network.svg | 1 + frontend/src/assets/img/company-custom.svg | 15 + frontend/src/assets/img/cpu-custom.svg | 5 + frontend/src/assets/img/cpu-twotone.svg | 10 + frontend/src/assets/img/cpu.svg | 22 + frontend/src/assets/img/credit.svg | 164 + frontend/src/assets/img/current_alloc.svg | 5 + .../src/assets/img/data-storage-custom.svg | 15 + frontend/src/assets/img/data-storage.svg | 1 + frontend/src/assets/img/database-intro.svg | 1 + frontend/src/assets/img/database.svg | 23 + frontend/src/assets/img/debit.svg | 7 + frontend/src/assets/img/ellipsis.svg | 19 + frontend/src/assets/img/failed-bg.svg | 124 + frontend/src/assets/img/failed-icon.svg | 13 + frontend/src/assets/img/failed.svg | 10 + frontend/src/assets/img/fast.svg | 5 + frontend/src/assets/img/gateways/credit.svg | 164 + .../assets/img/gateways/local-gateway-bd.svg | 58 + .../src/assets/img/gateways/pay-offline.svg | 20 + frontend/src/assets/img/gateways/paypal.svg | 12 + .../src/assets/img/helm/resources/c-role.svg | 1 + frontend/src/assets/img/helm/resources/cm.svg | 1 + .../src/assets/img/helm/resources/crb.svg | 1 + .../src/assets/img/helm/resources/crd.svg | 1 + .../src/assets/img/helm/resources/cronjob.svg | 1 + .../src/assets/img/helm/resources/deploy.svg | 1 + frontend/src/assets/img/helm/resources/ds.svg | 1 + frontend/src/assets/img/helm/resources/ep.svg | 1 + .../src/assets/img/helm/resources/group.svg | 1 + .../src/assets/img/helm/resources/hpa.svg | 1 + .../src/assets/img/helm/resources/ing.svg | 1 + .../src/assets/img/helm/resources/job.svg | 1 + .../src/assets/img/helm/resources/limits.svg | 1 + .../src/assets/img/helm/resources/netpol.svg | 1 + frontend/src/assets/img/helm/resources/ns.svg | 1 + .../src/assets/img/helm/resources/pod.svg | 1 + .../src/assets/img/helm/resources/psp.svg | 1 + frontend/src/assets/img/helm/resources/pv.svg | 1 + .../src/assets/img/helm/resources/pvc.svg | 1 + .../src/assets/img/helm/resources/quota.svg | 1 + frontend/src/assets/img/helm/resources/rb.svg | 1 + .../src/assets/img/helm/resources/role.svg | 1 + frontend/src/assets/img/helm/resources/rs.svg | 1 + frontend/src/assets/img/helm/resources/sa.svg | 1 + frontend/src/assets/img/helm/resources/sc.svg | 1 + .../src/assets/img/helm/resources/secret.svg | 1 + .../src/assets/img/helm/resources/sts.svg | 1 + .../src/assets/img/helm/resources/svc.svg | 1 + .../src/assets/img/helm/resources/user.svg | 1 + .../src/assets/img/helm/resources/vol.svg | 1 + .../src/assets/img/ic-klovercloud-logo.png | Bin 0 -> 12711 bytes frontend/src/assets/img/ico-tool-tip.svg | 3 + frontend/src/assets/img/icons/airdrop.svg | 1 + .../icons/application-build-config-custom.svg | 11 + .../img/icons/application-config-custom.svg | 9 + frontend/src/assets/img/icons/bin1.svg | 13 + .../assets/img/icons/bucket-settings-1.svg | 12 + .../assets/img/icons/bucket-settings-2.svg | 15 + .../assets/img/icons/bucket-settings-3.svg | 12 + .../assets/img/icons/bucket-settings-4.svg | 14 + frontend/src/assets/img/icons/calendar.svg | 121 + frontend/src/assets/img/icons/camera.svg | 48 + frontend/src/assets/img/icons/cancelled.svg | 9 + .../src/assets/img/icons/capacity-custom.svg | 12 + .../img/icons/ci-cd-pipeline/custom.svg | 5 + .../img/icons/ci-cd-pipeline/env-dev.svg | 26 + .../icons/ci-cd-pipeline/env-prod-success.svg | 11 + .../img/icons/ci-cd-pipeline/env-qa.svg | 10 + .../src/assets/img/icons/cloud-server.svg | 13 + .../src/assets/img/icons/cloud_loader.svg | 20 + .../src/assets/img/icons/cluster-icon-2.svg | 16 + .../src/assets/img/icons/cluster-icon.svg | 4 + .../src/assets/img/icons/cluster/cicd.svg | 9 + .../assets/img/icons/cluster/cluster_name.svg | 4 + .../assets/img/icons/cluster/desired_node.svg | 9 + .../assets/img/icons/cluster/disc_size.svg | 4 + .../src/assets/img/icons/cluster/max_node.svg | 12 + .../img/icons/cluster/max_unavailable.svg | 4 + .../assets/img/icons/cluster/maximum_util.svg | 9 + .../src/assets/img/icons/cluster/min_node.svg | 8 + .../src/assets/img/icons/cluster/name.svg | 7 + .../assets/img/icons/cluster/node_type.svg | 4 + frontend/src/assets/img/icons/database.svg | 4 + frontend/src/assets/img/icons/database_ns.svg | 56 + frontend/src/assets/img/icons/db-security.svg | 14 + .../dedicated-externanl-endpoint-custom.svg | 11 + .../src/assets/img/icons/delete-custom.svg | 4 + frontend/src/assets/img/icons/deploy.svg | 3 + .../src/assets/img/icons/dev-computer.svg | 3 + frontend/src/assets/img/icons/discussion.svg | 17 + frontend/src/assets/img/icons/docker-icon.svg | 1 + frontend/src/assets/img/icons/easy-icon.svg | 16 + frontend/src/assets/img/icons/edit-custom.svg | 4 + .../src/assets/img/icons/endpoint-custom.svg | 10 + .../img/icons/external-endpoint-custom.svg | 10 + frontend/src/assets/img/icons/failed.svg | 10 + .../src/assets/img/icons/folder-explore.svg | 6 + frontend/src/assets/img/icons/git-icon.svg | 1 + frontend/src/assets/img/icons/hosted_zone.svg | 1 + .../assets/img/icons/ic-active-deployment.gif | Bin 0 -> 4009 bytes .../assets/img/icons/ic-active-deployment.svg | 10 + .../src/assets/img/icons/ic-app-deleted.svg | 16 + .../img/icons/ic-application-others.svg | 12 + .../src/assets/img/icons/ic-application.svg | 4 + .../src/assets/img/icons/ic-bitbucket.svg | 11 + .../src/assets/img/icons/ic-build-success.svg | 19 + .../src/assets/img/icons/ic-certificate.png | Bin 0 -> 3459 bytes .../src/assets/img/icons/ic-check-circle.svg | 1 + frontend/src/assets/img/icons/ic-checked.svg | 4 + .../src/assets/img/icons/ic-cicd-approved.svg | 3 + .../assets/img/icons/ic-cicd-disapproved.svg | 9 + .../src/assets/img/icons/ic-cicd-edit.svg | 3 + .../src/assets/img/icons/ic-cicd-info.svg | 3 + .../src/assets/img/icons/ic-cicd-start.svg | 8 + .../src/assets/img/icons/ic-cicd-stop.svg | 8 + frontend/src/assets/img/icons/ic-company.svg | 29 + .../src/assets/img/icons/ic-database-2.svg | 6 + frontend/src/assets/img/icons/ic-database.svg | 6 + frontend/src/assets/img/icons/ic-delete.gif | Bin 0 -> 17932 bytes .../assets/img/icons/ic-deployment-failed.svg | 11 + .../img/icons/ic-docker-build-failed.svg | 19 + .../assets/img/icons/ic-docker-building.gif | Bin 0 -> 37337 bytes .../assets/img/icons/ic-docker-building.svg | 19 + frontend/src/assets/img/icons/ic-error-1.svg | 1 + frontend/src/assets/img/icons/ic-git.png | Bin 0 -> 9257 bytes .../src/assets/img/icons/ic-github-dark.svg | 3 + frontend/src/assets/img/icons/ic-github.svg | 3 + frontend/src/assets/img/icons/ic-gitlab.svg | 23 + frontend/src/assets/img/icons/ic-google.svg | 6 + .../src/assets/img/icons/ic-hourglass.gif | Bin 0 -> 17218 bytes .../src/assets/img/icons/ic-individual.svg | 33 + .../img/icons/ic-ongoing-deployment.gif | Bin 0 -> 72109 bytes .../img/icons/ic-ongoing-deployment.svg | 11 + frontend/src/assets/img/icons/ic-pending.svg | 25 + .../img/icons/ic-product-object-storage-1.svg | 26 + .../img/icons/ic-product-object-storage-2.svg | 38 + .../img/icons/ic-product-object-storage-3.svg | 50 + .../img/icons/ic-product-object-storage.svg | 14 + .../src/assets/img/icons/ic-region-custom.svg | 3 + frontend/src/assets/img/icons/ic-scale.svg | 9 + frontend/src/assets/img/icons/ic-team.svg | 3 + .../src/assets/img/icons/ic-theme-dark.svg | 21 + .../src/assets/img/icons/ic-theme-light.svg | 21 + .../src/assets/img/icons/ic-theme-pink.svg | 2 + .../assets/img/icons/ic-unverified-user.svg | 10 + .../src/assets/img/icons/ic-verified-user.svg | 10 + .../img/icons/ic-vpc-intialization-failed.svg | 11 + .../assets/img/icons/ic-vpc-intializing.gif | Bin 0 -> 39036 bytes .../assets/img/icons/ic-vpc-intializing.svg | 9 + .../assets/img/icons/ic-vpc-terminating.gif | Bin 0 -> 36681 bytes .../assets/img/icons/ic-vpc-terminating.svg | 11 + .../img/icons/ic-vpc-termination-failed.svg | 11 + frontend/src/assets/img/icons/ic_build.png | Bin 0 -> 3669 bytes frontend/src/assets/img/icons/ic_cluster.png | Bin 0 -> 44592 bytes frontend/src/assets/img/icons/ic_cpu.png | Bin 0 -> 6258 bytes frontend/src/assets/img/icons/ic_django.png | Bin 0 -> 11052 bytes frontend/src/assets/img/icons/ic_docker.png | Bin 0 -> 14362 bytes .../src/assets/img/icons/ic_docker_black.png | Bin 0 -> 12795 bytes frontend/src/assets/img/icons/ic_dot_net.png | Bin 0 -> 18989 bytes frontend/src/assets/img/icons/ic_error.png | Bin 0 -> 19380 bytes .../src/assets/img/icons/ic_expressjs.png | Bin 0 -> 16788 bytes .../src/assets/img/icons/ic_folder_git.png | Bin 0 -> 10642 bytes .../assets/img/icons/ic_folder_git_blue.svg | 9 + frontend/src/assets/img/icons/ic_gears.svg | 16 + frontend/src/assets/img/icons/ic_git.png | Bin 0 -> 7022 bytes .../src/assets/img/icons/ic_git_branch.png | Bin 0 -> 2472 bytes frontend/src/assets/img/icons/ic_git_red.png | Bin 0 -> 17461 bytes .../src/assets/img/icons/ic_hard_drive.png | Bin 0 -> 26727 bytes .../assets/img/icons/ic_klovercloud_logo.png | Bin 0 -> 6063 bytes frontend/src/assets/img/icons/ic_laravel.png | Bin 0 -> 23153 bytes frontend/src/assets/img/icons/ic_launch.svg | 9 + .../assets/img/icons/ic_network_storage.png | Bin 0 -> 129739 bytes frontend/src/assets/img/icons/ic_new_app.png | Bin 0 -> 5480 bytes frontend/src/assets/img/icons/ic_ram.png | Bin 0 -> 15323 bytes frontend/src/assets/img/icons/ic_spring.svg | 1 + frontend/src/assets/img/icons/ic_success.png | Bin 0 -> 3514 bytes .../src/assets/img/icons/ic_success_2.png | Bin 0 -> 5722 bytes frontend/src/assets/img/icons/ic_warning.png | Bin 0 -> 7255 bytes .../src/assets/img/icons/ic_wordpress.png | Bin 0 -> 14099 bytes .../img/icons/ico-application-buildtype.svg | 8 + .../img/icons/ico-application-c-sharp.svg | 8 + .../img/icons/ico-application-csharp.svg | 8 + .../img/icons/ico-application-golang.svg | 18 + .../img/icons/ico-application-instances.svg | 8 + .../assets/img/icons/ico-application-java.svg | 7 + .../img/icons/ico-application-javascript.svg | 6 + .../assets/img/icons/ico-application-list.svg | 6 + .../img/icons/ico-application-others.svg | 12 + .../assets/img/icons/ico-application-php.svg | 4 + .../img/icons/ico-application-python.svg | 14 + .../img/icons/ico-application-status.svg | 5 + .../assets/img/icons/ico-application-team.svg | 4 + .../src/assets/img/icons/ico-application.svg | 7 + .../src/assets/img/icons/ico-auto-scaling.svg | 18 + frontend/src/assets/img/icons/ico-bin.svg | 4 + frontend/src/assets/img/icons/ico-build.svg | 31 + .../assets/img/icons/ico-canary-deplyment.svg | 10 + .../assets/img/icons/ico-chalander-dark.svg | 3 + .../src/assets/img/icons/ico-chalander.svg | 3 + .../assets/img/icons/ico-cicd-redeploy.svg | 7 + .../src/assets/img/icons/ico-cicd-restart.svg | 3 + .../assets/img/icons/ico-cicd-sucessfully.svg | 26 + .../img/icons/ico-cicd-unSucessfull.svg | 26 + .../src/assets/img/icons/ico-clock-custom.svg | 5 + .../src/assets/img/icons/ico-cpu-custom.svg | 6 + .../assets/img/icons/ico-cpu-threshold.svg | 21 + frontend/src/assets/img/icons/ico-cr.svg | 4 + .../img/icons/ico-custom-basic-auth.svg | 11 + .../img/icons/ico-custom-external-url.svg | 6 + .../assets/img/icons/ico-database-type.svg | 8 + frontend/src/assets/img/icons/ico-docker.svg | 13 + .../src/assets/img/icons/ico-easy-to-use.svg | 12 + .../img/icons/ico-enable-external-url.svg | 6 + frontend/src/assets/img/icons/ico-env-dev.svg | 7 + .../src/assets/img/icons/ico-env-pre-prod.svg | 4 + .../src/assets/img/icons/ico-env-prod.svg | 7 + frontend/src/assets/img/icons/ico-env-qa.svg | 10 + .../src/assets/img/icons/ico-env-staging.svg | 3 + .../src/assets/img/icons/ico-env-test.svg | 9 + .../src/assets/img/icons/ico-excution.svg | 15 + .../src/assets/img/icons/ico-filebrowser.svg | 4 + .../assets/img/icons/ico-git-commit-id.svg | 4 + frontend/src/assets/img/icons/ico-git.svg | 4 + .../src/assets/img/icons/ico-instances.svg | 4 + .../img/icons/ico-intro-app-on-boarding.svg | 16 + .../src/assets/img/icons/ico-intro-cicd.svg | 4 + .../img/icons/ico-intro-easy-monitoring.svg | 4 + .../img/icons/ico-intro-log-aggregation.svg | 4 + .../img/icons/ico-intro-multiple-env.svg | 4 + .../assets/img/icons/ico-language-custom.svg | 10 + .../src/assets/img/icons/ico-lock-custom.svg | 4 + .../src/assets/img/icons/ico-logo-icon.svg | 4 + .../assets/img/icons/ico-max-utilization.svg | 8 + .../assets/img/icons/ico-memory-custom.svg | 7 + .../img/icons/ico-micro-service-platform.svg | 6 + .../src/assets/img/icons/ico-name-custom.svg | 11 + .../src/assets/img/icons/ico-phpmyadmin-m.svg | 25 + frontend/src/assets/img/icons/ico-port.svg | 8 + .../img/icons/ico-presistent-volume.svg | 6 + .../assets/img/icons/ico-s3-compatiable.svg | 4 + .../assets/img/icons/ico-search-custom.svg | 3 + .../src/assets/img/icons/ico-spend-less.svg | 8 + .../src/assets/img/icons/ico-spring-boot.svg | 3 + frontend/src/assets/img/icons/ico-sso.svg | 17 + .../assets/img/icons/ico-storage-custom.svg | 16 + .../assets/img/icons/ico-theme-preference.svg | 11 + .../assets/img/icons/ico-tps-threshold.svg | 4 + .../src/assets/img/icons/ico-user-custom.svg | 4 + .../assets/img/icons/ico-version-custom.svg | 4 + .../img/icons/ico-volume-mount-path.svg | 4 + .../src/assets/img/icons/ico-vpc-custom.svg | 8 + .../src/assets/img/icons/ico-vpc-list.svg | 8 + .../src/assets/img/icons/ico-vpc-outline.svg | 3 + .../assets/img/icons/ico-wp-application.svg | 8 + .../src/assets/img/icons/ico-zero-trust.svg | 5 + frontend/src/assets/img/icons/live-icon.svg | 11 + .../assets/img/icons/manage-backups-icon.svg | 15 + .../src/assets/img/icons/multi-cluster.svg | 22 + .../src/assets/img/icons/on-demand-icon.svg | 17 + frontend/src/assets/img/icons/org-cog.svg | 8 + frontend/src/assets/img/icons/pending.svg | 12 + frontend/src/assets/img/icons/play-button.svg | 6 + frontend/src/assets/img/icons/records.svg | 2 + .../src/assets/img/icons/region-custom.svg | 9 + .../src/assets/img/icons/resources-icon.svg | 4 + .../src/assets/img/icons/rotate-arrow.svg | 40 + frontend/src/assets/img/icons/running.svg | 10 + frontend/src/assets/img/icons/search-icon.svg | 3 + .../src/assets/img/icons/snapshot-custom.svg | 13 + .../img/icons/snapshot-setting-custom.svg | 14 + .../icons/snapshot-setting-dark-custom.svg | 14 + frontend/src/assets/img/icons/succeeded.svg | 9 + frontend/src/assets/img/icons/team-custom.svg | 6 + .../src/assets/img/icons/team-name-custom.svg | 11 + frontend/src/assets/img/icons/type-pdf.svg | 9 + .../src/assets/img/icons/update-successor.svg | 7 + .../assets/img/icons/upgrade-vpc-custom.svg | 14 + frontend/src/assets/img/icons/v2_1.svg | 14 + .../img/icons/webclint-setting-custom.svg | 21 + frontend/src/assets/img/icons/webhooks.svg | 4 + .../src/assets/img/icons/world-wide-web.svg | 2 + .../assets/img/illustrations/checklist.svg | 164 + .../assets/img/illustrations/cms-header.svg | 197 + .../illustrations/dashbord-intro-hello-bg.svg | 47 + .../assets/img/illustrations/data_center.svg | 150 + .../email-verification-steps.svg | 10 + .../img/illustrations/forgot-password-bg.svg | 21 + .../illustrations/hello-box-illustration.svg | 8 + .../src/assets/img/illustrations/idea.svg | 213 + .../illustrations/ifg-email-verification.svg | 74 + .../assets/img/illustrations/ifg-email.svg | 28 + .../assets/img/illustrations/it_support.svg | 168 + .../img/illustrations/know-klovercloud.svg | 14 + .../img/illustrations/lets-start-left.svg | 22 + .../img/illustrations/lets-start-right.svg | 45 + .../img/illustrations/login-left-bg-dark.svg | 13 + .../login-ls-dark-illustration.svg | 371 + .../login-ls-light-illustration.svg | 349 + .../img/illustrations/login-right-bg-dark.svg | 19 + .../illustrations/login-right-bg-dark1.svg | 9 + .../object-storage-intro-bg-dark.svg | 69 + .../object-storage-intro-illustration.svg | 149 + .../object-storage-intro-illustration1.svg | 92 + .../onboarding-dark-btn-illustration.svg | 21 + .../onboarding-light-btn-illustration.svg | 21 + .../img/illustrations/peak_mountain_3.svg | 262 + .../assets/img/illustrations/queue-intro.svg | 153 + .../registration-ls-dark-illustration.svg | 179 + .../registration-ls-light-illustration.svg | 172 + .../illustrations/under_constructions_1.svg | 282 + frontend/src/assets/img/instance.svg | 15 + frontend/src/assets/img/list-style-custom.svg | 3 + frontend/src/assets/img/local-gateway-bd.svg | 58 + frontend/src/assets/img/location.svg | 38 + frontend/src/assets/img/marketplace.svg | 10 + frontend/src/assets/img/max_alloc.svg | 8 + frontend/src/assets/img/memory.svg | 11 + frontend/src/assets/img/migrate.svg | 9 + frontend/src/assets/img/mobile_banking.svg | 94 + frontend/src/assets/img/nosql.png | Bin 0 -> 22246 bytes .../src/assets/img/object-storage-home.svg | 438 + .../src/assets/img/organization-custom.svg | 22 + frontend/src/assets/img/package.svg | 24 + frontend/src/assets/img/pay-offline.svg | 20 + frontend/src/assets/img/pay.svg | 50 + frontend/src/assets/img/payAsYouGo-custom.svg | 14 + frontend/src/assets/img/payment.svg | 6 + frontend/src/assets/img/paypal.svg | 12 + frontend/src/assets/img/pipeline.png | Bin 0 -> 34660 bytes frontend/src/assets/img/plus.svg | 42 + frontend/src/assets/img/pod.svg | 3 + frontend/src/assets/img/postgresql-custom.svg | 9 + .../src/assets/img/prepaid-card-custom.svg | 15 + frontend/src/assets/img/processing-shadow.svg | 12 + .../src/assets/img/providers/aws_logo.svg | 5 + .../src/assets/img/providers/azure_logo.svg | 2 + .../assets/img/providers/bare_metal_logo.svg | 5 + .../img/providers/digital_ocean_logo.svg | 1 + .../src/assets/img/providers/gcp_logo.svg | 14 + frontend/src/assets/img/providers/onboard.svg | 1 + .../src/assets/img/providers/robi_logo.svg | 74 + frontend/src/assets/img/queue.svg | 13 + frontend/src/assets/img/ram-memory-custom.svg | 6 + frontend/src/assets/img/ram-memory.svg | 144 + frontend/src/assets/img/region-Asia.svg | 3 + frontend/src/assets/img/region-Australia.svg | 3 + frontend/src/assets/img/region-Europe.svg | 3 + .../src/assets/img/region-SouthAmerica.svg | 3 + frontend/src/assets/img/region-USA.svg | 3 + frontend/src/assets/img/region.svg | 12 + .../img/registration-ls-illustration.png | Bin 0 -> 597198 bytes frontend/src/assets/img/relational.png | Bin 0 -> 30569 bytes frontend/src/assets/img/reload.svg | 3 + frontend/src/assets/img/robot.svg | 194 + frontend/src/assets/img/running.svg | 10 + frontend/src/assets/img/server.svg | 1 + .../src/assets/img/signup-ls-infographics.png | Bin 0 -> 526132 bytes frontend/src/assets/img/sql.jpg | Bin 0 -> 44803 bytes frontend/src/assets/img/storage.svg | 11 + frontend/src/assets/img/success-bg.svg | 144 + frontend/src/assets/img/success-icon.svg | 11 + frontend/src/assets/img/team-custom.svg | 17 + frontend/src/assets/img/unverifiedUser.svg | 10 + frontend/src/assets/img/verifiedUser.svg | 10 + frontend/src/assets/img/vpc-custom.svg | 8 + frontend/src/assets/img/vpc-form-basi.svg | 14 + frontend/src/assets/img/vpc-form-high.svg | 32 + frontend/src/assets/img/vpc-form-price.svg | 81 + frontend/src/assets/img/vpc-form-stan.svg | 20 + frontend/src/assets/img/vpc-icon.svg | 13 + frontend/src/assets/img/vpc.svg | 83 + frontend/src/assets/img/wordpress.svg | 5 + frontend/src/data/navigation.ts | 83 + frontend/src/data/toolbar.ts | 32 + frontend/src/environments/environment.prod.ts | 8 + frontend/src/environments/environment.ts | 8 + frontend/src/favicon.ico | Bin 0 -> 1150 bytes frontend/src/index.html | 119 + frontend/src/libs/ace-editor/README.md | 3 + .../src/libs/ace-editor/acc-editor.enums.ts | 4 + .../libs/ace-editor/ace-editor.component.html | 1 + .../libs/ace-editor/ace-editor.component.scss | 0 .../libs/ace-editor/ace-editor.component.ts | 130 + .../src/libs/ace-editor/ace-editor.module.ts | 10 + frontend/src/libs/ace-editor/styles.scss | 25 + frontend/src/main.ts | 13 + frontend/src/note.txt | 11 + frontend/src/polyfills.ts | 52 + frontend/src/styles.scss | 12 + frontend/src/test.ts | 16 + frontend/tailwind.config.js | 691 + frontend/tsconfig.app.json | 9 + frontend/tsconfig.json | 36 + frontend/tsconfig.spec.json | 9 + frontend/tslint.json | 99 + frontend/webpack.config.js | 41 + frontend/webpack.prod.config.js | 78 + 1262 files changed, 89484 insertions(+), 1 deletion(-) create mode 100644 frontend/.browserslistrc create mode 100644 frontend/.dockerignore create mode 100644 frontend/.prettierignore create mode 100644 frontend/.prettierrc create mode 100644 frontend/Dockerfile create mode 100644 frontend/Dockerfile2 create mode 100644 frontend/README.md create mode 100644 frontend/angular.json create mode 100644 frontend/dashboard.json create mode 100644 frontend/e2e/protractor.conf.js create mode 100644 frontend/e2e/src/app.e2e-spec.ts create mode 100644 frontend/e2e/src/app.po.ts create mode 100644 frontend/e2e/tsconfig.json create mode 100644 frontend/karma.conf.js create mode 100644 frontend/nginx/default.conf create mode 100644 frontend/nginx/nginx.conf create mode 100644 frontend/package-lock.json create mode 100644 frontend/package.json create mode 100644 frontend/projects/cdk-ui/README.md create mode 100644 frontend/projects/cdk-ui/index.ts create mode 100644 frontend/projects/cdk-ui/karma.conf.js create mode 100644 frontend/projects/cdk-ui/ng-package.json create mode 100644 frontend/projects/cdk-ui/package.json create mode 100644 frontend/projects/cdk-ui/src/clipboard/DOCUMENTATION.md create mode 100644 frontend/projects/cdk-ui/src/clipboard/clipboard.component.ts create mode 100644 frontend/projects/cdk-ui/src/clipboard/clipboard.module.ts create mode 100644 frontend/projects/cdk-ui/src/clipboard/index.ts create mode 100644 frontend/projects/cdk-ui/src/clipboard/ng-package.json create mode 100644 frontend/projects/cdk-ui/src/clipboard/public-api.ts create mode 100644 frontend/projects/cdk-ui/src/hint/DOCUMENTATION.md create mode 100644 frontend/projects/cdk-ui/src/hint/hint.component.ts create mode 100644 frontend/projects/cdk-ui/src/hint/hint.module.ts create mode 100644 frontend/projects/cdk-ui/src/hint/index.ts create mode 100644 frontend/projects/cdk-ui/src/hint/ng-package.json create mode 100644 frontend/projects/cdk-ui/src/hint/public-api.ts create mode 100644 frontend/projects/cdk-ui/src/horizontal-stepper/horizontal-stepper.component.html create mode 100644 frontend/projects/cdk-ui/src/horizontal-stepper/horizontal-stepper.component.ts create mode 100644 frontend/projects/cdk-ui/src/horizontal-stepper/horizontal-stepper.module.ts create mode 100644 frontend/projects/cdk-ui/src/horizontal-stepper/index.ts create mode 100644 frontend/projects/cdk-ui/src/horizontal-stepper/ng-package.json create mode 100644 frontend/projects/cdk-ui/src/horizontal-stepper/public-api.ts create mode 100644 frontend/projects/cdk-ui/src/icon/DOCUMENTATION.md create mode 100644 frontend/projects/cdk-ui/src/icon/icon.component.ts create mode 100644 frontend/projects/cdk-ui/src/icon/icon.interfaces.ts create mode 100644 frontend/projects/cdk-ui/src/icon/icon.module.ts create mode 100644 frontend/projects/cdk-ui/src/icon/index.ts create mode 100644 frontend/projects/cdk-ui/src/icon/ng-package.json create mode 100644 frontend/projects/cdk-ui/src/icon/public-api.ts create mode 100644 frontend/projects/cdk-ui/src/test.ts create mode 100644 frontend/projects/cdk-ui/src/tooltip/DOCUMENTATION.md create mode 100644 frontend/projects/cdk-ui/src/tooltip/index.ts create mode 100644 frontend/projects/cdk-ui/src/tooltip/ng-package.json create mode 100644 frontend/projects/cdk-ui/src/tooltip/public-api.ts create mode 100644 frontend/projects/cdk-ui/src/tooltip/tooltip-content.component.ts create mode 100644 frontend/projects/cdk-ui/src/tooltip/tooltip.directive.ts create mode 100644 frontend/projects/cdk-ui/src/tooltip/tooltip.module.ts create mode 100644 frontend/projects/cdk-ui/styles/all-components.scss create mode 100644 frontend/projects/cdk-ui/styles/clipboard.scss create mode 100644 frontend/projects/cdk-ui/styles/hint.scss create mode 100644 frontend/projects/cdk-ui/styles/horizontal-stepper.scss create mode 100644 frontend/projects/cdk-ui/styles/icon.scss create mode 100644 frontend/projects/cdk-ui/styles/tooltip.scss create mode 100644 frontend/projects/cdk-ui/tsconfig.lib.json create mode 100644 frontend/projects/cdk-ui/tsconfig.lib.prod.json create mode 100644 frontend/projects/cdk-ui/tsconfig.spec.json create mode 100644 frontend/projects/core-ui/README.md create mode 100644 frontend/projects/core-ui/index.ts create mode 100644 frontend/projects/core-ui/karma.conf.js create mode 100644 frontend/projects/core-ui/ng-package.json create mode 100644 frontend/projects/core-ui/package.json create mode 100644 frontend/projects/core-ui/src/constants/constants.injection-token.ts create mode 100644 frontend/projects/core-ui/src/constants/index.ts create mode 100644 frontend/projects/core-ui/src/constants/ng-package.json create mode 100644 frontend/projects/core-ui/src/directives/has-any-authority.directive.ts create mode 100644 frontend/projects/core-ui/src/directives/index.ts create mode 100644 frontend/projects/core-ui/src/directives/ng-package.json create mode 100644 frontend/projects/core-ui/src/guards/admin.guard.ts create mode 100644 frontend/projects/core-ui/src/guards/auth.guard.ts create mode 100644 frontend/projects/core-ui/src/guards/index.ts create mode 100644 frontend/projects/core-ui/src/guards/ng-package.json create mode 100644 frontend/projects/core-ui/src/guards/role-guard.service.ts create mode 100644 frontend/projects/core-ui/src/guards/role.guard.ts create mode 100644 frontend/projects/core-ui/src/initializer.module.ts create mode 100644 frontend/projects/core-ui/src/interceptors/auth.interceptor.ts create mode 100644 frontend/projects/core-ui/src/interceptors/errors.interceptor.ts create mode 100644 frontend/projects/core-ui/src/interceptors/index.ts create mode 100644 frontend/projects/core-ui/src/interceptors/ng-package.json create mode 100644 frontend/projects/core-ui/src/interfaces/deep-partial.type.ts create mode 100644 frontend/projects/core-ui/src/interfaces/environment.ts create mode 100644 frontend/projects/core-ui/src/interfaces/index.ts create mode 100644 frontend/projects/core-ui/src/interfaces/ng-package.json create mode 100644 frontend/projects/core-ui/src/models/index.ts create mode 100644 frontend/projects/core-ui/src/models/ng-package.json create mode 100644 frontend/projects/core-ui/src/models/user-role.ts create mode 100644 frontend/projects/core-ui/src/services/core-config/core-config.interfaces.ts create mode 100644 frontend/projects/core-ui/src/services/core-config/core-config.service.ts create mode 100644 frontend/projects/core-ui/src/services/core-config/core-config.ts create mode 100644 frontend/projects/core-ui/src/services/core-config/index.ts create mode 100644 frontend/projects/core-ui/src/services/http.service.ts create mode 100644 frontend/projects/core-ui/src/services/index.ts create mode 100644 frontend/projects/core-ui/src/services/ng-package.json create mode 100644 frontend/projects/core-ui/src/services/permission.service.ts create mode 100644 frontend/projects/core-ui/src/services/public-api.ts create mode 100644 frontend/projects/core-ui/src/services/requester.service.ts create mode 100644 frontend/projects/core-ui/src/test.ts create mode 100644 frontend/projects/core-ui/src/utils/flatten-deep.ts create mode 100644 frontend/projects/core-ui/src/utils/flatten-object.ts create mode 100644 frontend/projects/core-ui/src/utils/index.ts create mode 100644 frontend/projects/core-ui/src/utils/merge-deep.ts create mode 100644 frontend/projects/core-ui/src/utils/ng-package.json create mode 100644 frontend/projects/core-ui/src/utils/to-params.ts create mode 100644 frontend/projects/core-ui/src/utils/to-query.ts create mode 100644 frontend/projects/core-ui/src/utils/track-by.ts create mode 100644 frontend/projects/core-ui/tsconfig.lib.json create mode 100644 frontend/projects/core-ui/tsconfig.lib.prod.json create mode 100644 frontend/projects/core-ui/tsconfig.spec.json create mode 100644 frontend/projects/sdk-ui/README.md create mode 100644 frontend/projects/sdk-ui/assets/images/favicon_klovercloud.ico create mode 100644 frontend/projects/sdk-ui/assets/images/ic_klovercloud_logo.png create mode 100644 frontend/projects/sdk-ui/assets/images/logo-dark.svg create mode 100644 frontend/projects/sdk-ui/assets/images/logo-favicon.ico create mode 100644 frontend/projects/sdk-ui/assets/images/logo-inverse.png create mode 100644 frontend/projects/sdk-ui/assets/images/logo-klovercloud-01.png create mode 100644 frontend/projects/sdk-ui/assets/images/logo-light.svg create mode 100644 frontend/projects/sdk-ui/assets/images/logo_klovercloud.png create mode 100644 frontend/projects/sdk-ui/assets/images/toastr/icon-error.svg create mode 100644 frontend/projects/sdk-ui/assets/images/toastr/icon-notification.svg create mode 100644 frontend/projects/sdk-ui/assets/images/toastr/icon-success.svg create mode 100644 frontend/projects/sdk-ui/assets/images/toastr/icon-warn.svg create mode 100644 frontend/projects/sdk-ui/assets/scss/argo/variables.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/_base.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/_fonticon.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/_root.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/_utilities.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/_var.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/components/_btn.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/components/_filter.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/components/_form.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/components/_icon.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/components/_status.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/components/index.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/components/table/_table-accordion.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/components/table/_table-kc.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/components/table/_table-label.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/components/table/_table-ui.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/components/table/index.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/core.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/partials/_horizontal.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/partials/_mixins.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/partials/_overrides.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/partials/_print.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/partials/_scrollbar.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/partials/_vertical.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/partials/plugins/_angular-calendar.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/partials/plugins/_angular-material.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/partials/plugins/_apexcharts.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/partials/styles/_style-dark.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/partials/styles/_style-light-pink.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/partials/styles/_style-light.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/plugins/_cdk-overlay.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/plugins/_charts.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/plugins/_owl-dt.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/plugins/_snackbar.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/plugins/_tooltip.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/plugins/form/_checkbox.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/plugins/form/_input.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/plugins/form/_select-panel.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/plugins/form/index.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/plugins/index.scss create mode 100644 frontend/projects/sdk-ui/assets/styles/tailwind.scss create mode 100644 frontend/projects/sdk-ui/assets/webfonts/klovercloud-icon.eot create mode 100644 frontend/projects/sdk-ui/assets/webfonts/klovercloud-icon.svg create mode 100644 frontend/projects/sdk-ui/assets/webfonts/klovercloud-icon.ttf create mode 100644 frontend/projects/sdk-ui/assets/webfonts/klovercloud-icon.woff create mode 100644 frontend/projects/sdk-ui/index.ts create mode 100644 frontend/projects/sdk-ui/karma.conf.js create mode 100644 frontend/projects/sdk-ui/ng-package.json create mode 100644 frontend/projects/sdk-ui/package.json create mode 100644 frontend/projects/sdk-ui/src/animations/dropdown.animation.ts create mode 100644 frontend/projects/sdk-ui/src/animations/fade-in-right.animation.ts create mode 100644 frontend/projects/sdk-ui/src/animations/fade-in-up.animation.ts create mode 100644 frontend/projects/sdk-ui/src/animations/index.ts create mode 100644 frontend/projects/sdk-ui/src/animations/ng-package.json create mode 100644 frontend/projects/sdk-ui/src/animations/popover.animation.ts create mode 100644 frontend/projects/sdk-ui/src/animations/public-api.ts create mode 100644 frontend/projects/sdk-ui/src/animations/scale-fade-in.animation.ts create mode 100644 frontend/projects/sdk-ui/src/animations/scale-in-out.animation.ts create mode 100644 frontend/projects/sdk-ui/src/animations/scale-in.animation.ts create mode 100644 frontend/projects/sdk-ui/src/animations/stagger.animation.ts create mode 100644 frontend/projects/sdk-ui/src/components/base-route-pagination.component.ts create mode 100644 frontend/projects/sdk-ui/src/components/base-table.componenet.ts create mode 100644 frontend/projects/sdk-ui/src/components/index.ts create mode 100644 frontend/projects/sdk-ui/src/components/ng-package.json create mode 100644 frontend/projects/sdk-ui/src/directives/container/container.directive.spec.ts create mode 100644 frontend/projects/sdk-ui/src/directives/container/container.directive.ts create mode 100644 frontend/projects/sdk-ui/src/directives/container/container.module.ts create mode 100644 frontend/projects/sdk-ui/src/directives/container/index.ts create mode 100644 frontend/projects/sdk-ui/src/directives/index.ts create mode 100644 frontend/projects/sdk-ui/src/directives/ng-package.json create mode 100644 frontend/projects/sdk-ui/src/interfaces/config.interface.ts create mode 100644 frontend/projects/sdk-ui/src/interfaces/css-variable.enum.ts create mode 100644 frontend/projects/sdk-ui/src/interfaces/index.ts create mode 100644 frontend/projects/sdk-ui/src/interfaces/kc-route.interface.ts create mode 100644 frontend/projects/sdk-ui/src/interfaces/navigation-item.interface.ts create mode 100644 frontend/projects/sdk-ui/src/interfaces/ng-package.json create mode 100644 frontend/projects/sdk-ui/src/interfaces/table-column.interface.ts create mode 100644 frontend/projects/sdk-ui/src/interfaces/toolbar-menu-item.interface.ts create mode 100644 frontend/projects/sdk-ui/src/layout/index.ts create mode 100644 frontend/projects/sdk-ui/src/layout/layout.component.html create mode 100644 frontend/projects/sdk-ui/src/layout/layout.component.scss create mode 100644 frontend/projects/sdk-ui/src/layout/layout.component.spec.ts create mode 100644 frontend/projects/sdk-ui/src/layout/layout.component.ts create mode 100644 frontend/projects/sdk-ui/src/layout/layout.module.ts create mode 100644 frontend/projects/sdk-ui/src/layout/navigation-item/navigation-item.component.html create mode 100644 frontend/projects/sdk-ui/src/layout/navigation-item/navigation-item.component.scss create mode 100644 frontend/projects/sdk-ui/src/layout/navigation-item/navigation-item.component.spec.ts create mode 100644 frontend/projects/sdk-ui/src/layout/navigation-item/navigation-item.component.ts create mode 100644 frontend/projects/sdk-ui/src/layout/navigation-item/navigation-item.module.ts create mode 100644 frontend/projects/sdk-ui/src/layout/navigation/navigation.component.html create mode 100644 frontend/projects/sdk-ui/src/layout/navigation/navigation.component.scss create mode 100644 frontend/projects/sdk-ui/src/layout/navigation/navigation.component.spec.ts create mode 100644 frontend/projects/sdk-ui/src/layout/navigation/navigation.component.ts create mode 100644 frontend/projects/sdk-ui/src/layout/navigation/navigation.module.ts create mode 100644 frontend/projects/sdk-ui/src/layout/ng-package.json create mode 100644 frontend/projects/sdk-ui/src/layout/sidenav-item/sidenav-item.component.html create mode 100644 frontend/projects/sdk-ui/src/layout/sidenav-item/sidenav-item.component.scss create mode 100644 frontend/projects/sdk-ui/src/layout/sidenav-item/sidenav-item.component.spec.ts create mode 100644 frontend/projects/sdk-ui/src/layout/sidenav-item/sidenav-item.component.ts create mode 100644 frontend/projects/sdk-ui/src/layout/sidenav-item/sidenav-item.module.ts create mode 100644 frontend/projects/sdk-ui/src/layout/sidenav/sidenav.component.html create mode 100644 frontend/projects/sdk-ui/src/layout/sidenav/sidenav.component.scss create mode 100644 frontend/projects/sdk-ui/src/layout/sidenav/sidenav.component.spec.ts create mode 100644 frontend/projects/sdk-ui/src/layout/sidenav/sidenav.component.ts create mode 100644 frontend/projects/sdk-ui/src/layout/sidenav/sidenav.module.ts create mode 100644 frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user-dropdown/toolbar-user-dropdown.component.html create mode 100644 frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user-dropdown/toolbar-user-dropdown.component.scss create mode 100644 frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user-dropdown/toolbar-user-dropdown.component.spec.ts create mode 100644 frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user-dropdown/toolbar-user-dropdown.component.ts create mode 100644 frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user.component.html create mode 100644 frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user.component.scss create mode 100644 frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user.component.spec.ts create mode 100644 frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user.component.ts create mode 100644 frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user.module.ts create mode 100644 frontend/projects/sdk-ui/src/layout/toolbar/toolbar.component.html create mode 100644 frontend/projects/sdk-ui/src/layout/toolbar/toolbar.component.scss create mode 100644 frontend/projects/sdk-ui/src/layout/toolbar/toolbar.component.spec.ts create mode 100644 frontend/projects/sdk-ui/src/layout/toolbar/toolbar.component.ts create mode 100644 frontend/projects/sdk-ui/src/layout/toolbar/toolbar.module.ts create mode 100644 frontend/projects/sdk-ui/src/pipes/index.ts create mode 100644 frontend/projects/sdk-ui/src/pipes/ng-package.json create mode 100644 frontend/projects/sdk-ui/src/pipes/safe-html/safe-html.module.ts create mode 100644 frontend/projects/sdk-ui/src/pipes/safe-html/safe-html.pipe.ts create mode 100644 frontend/projects/sdk-ui/src/pipes/safe-style/safe-style.module.ts create mode 100644 frontend/projects/sdk-ui/src/pipes/safe-style/safe-style.pipe.spec.ts create mode 100644 frontend/projects/sdk-ui/src/pipes/safe-style/safe-style.pipe.ts create mode 100644 frontend/projects/sdk-ui/src/sdk-ui.module.ts create mode 100644 frontend/projects/sdk-ui/src/services/config.service.ts create mode 100644 frontend/projects/sdk-ui/src/services/index.ts create mode 100644 frontend/projects/sdk-ui/src/services/layout.service.spec.ts create mode 100644 frontend/projects/sdk-ui/src/services/layout.service.ts create mode 100644 frontend/projects/sdk-ui/src/services/navigation.service.spec.ts create mode 100644 frontend/projects/sdk-ui/src/services/navigation.service.ts create mode 100644 frontend/projects/sdk-ui/src/services/ng-package.json create mode 100644 frontend/projects/sdk-ui/src/services/public-api.ts create mode 100644 frontend/projects/sdk-ui/src/services/splash-screen.service.spec.ts create mode 100644 frontend/projects/sdk-ui/src/services/splash-screen.service.ts create mode 100644 frontend/projects/sdk-ui/src/services/style.service.ts create mode 100644 frontend/projects/sdk-ui/src/services/toolbar.service.ts create mode 100644 frontend/projects/sdk-ui/src/test-setup.ts create mode 100644 frontend/projects/sdk-ui/src/ui/img/img.component.ts create mode 100644 frontend/projects/sdk-ui/src/ui/img/img.module.ts create mode 100644 frontend/projects/sdk-ui/src/ui/img/index.ts create mode 100644 frontend/projects/sdk-ui/src/ui/index.ts create mode 100644 frontend/projects/sdk-ui/src/ui/loading-bar/index.ts create mode 100644 frontend/projects/sdk-ui/src/ui/loading-bar/loading-bar-router.module.ts create mode 100644 frontend/projects/sdk-ui/src/ui/loading-bar/loading-bar.config.ts create mode 100644 frontend/projects/sdk-ui/src/ui/loading-bar/loading-bar.service.ts create mode 100644 frontend/projects/sdk-ui/src/ui/loading-bar/loading-bar.state.ts create mode 100644 frontend/projects/sdk-ui/src/ui/logo/index.ts create mode 100644 frontend/projects/sdk-ui/src/ui/logo/logo.component.ts create mode 100644 frontend/projects/sdk-ui/src/ui/logo/logo.module.ts create mode 100644 frontend/projects/sdk-ui/src/ui/ng-package.json create mode 100644 frontend/projects/sdk-ui/src/ui/page-layout/index.ts create mode 100644 frontend/projects/sdk-ui/src/ui/page-layout/page-layout-content.directive.ts create mode 100644 frontend/projects/sdk-ui/src/ui/page-layout/page-layout-header.directive.ts create mode 100644 frontend/projects/sdk-ui/src/ui/page-layout/page-layout.component.scss create mode 100644 frontend/projects/sdk-ui/src/ui/page-layout/page-layout.component.ts create mode 100644 frontend/projects/sdk-ui/src/ui/page-layout/page-layout.module.ts create mode 100644 frontend/projects/sdk-ui/src/ui/popover/index.ts create mode 100644 frontend/projects/sdk-ui/src/ui/popover/popover-ref.ts create mode 100644 frontend/projects/sdk-ui/src/ui/popover/popover.component.html create mode 100644 frontend/projects/sdk-ui/src/ui/popover/popover.component.scss create mode 100644 frontend/projects/sdk-ui/src/ui/popover/popover.component.ts create mode 100644 frontend/projects/sdk-ui/src/ui/popover/popover.module.ts create mode 100644 frontend/projects/sdk-ui/src/ui/popover/popover.service.ts create mode 100644 frontend/projects/sdk-ui/src/ui/progress-bar/index.ts create mode 100644 frontend/projects/sdk-ui/src/ui/progress-bar/progress-bar.component.html create mode 100644 frontend/projects/sdk-ui/src/ui/progress-bar/progress-bar.component.scss create mode 100644 frontend/projects/sdk-ui/src/ui/progress-bar/progress-bar.component.spec.ts create mode 100644 frontend/projects/sdk-ui/src/ui/progress-bar/progress-bar.component.ts create mode 100644 frontend/projects/sdk-ui/src/ui/progress-bar/progress-bar.module.ts create mode 100644 frontend/projects/sdk-ui/src/ui/secondary-toolbar/index.ts create mode 100644 frontend/projects/sdk-ui/src/ui/secondary-toolbar/secondary-toolbar.component.html create mode 100644 frontend/projects/sdk-ui/src/ui/secondary-toolbar/secondary-toolbar.component.scss create mode 100644 frontend/projects/sdk-ui/src/ui/secondary-toolbar/secondary-toolbar.component.spec.ts create mode 100644 frontend/projects/sdk-ui/src/ui/secondary-toolbar/secondary-toolbar.component.ts create mode 100644 frontend/projects/sdk-ui/src/ui/secondary-toolbar/secondary-toolbar.module.ts create mode 100644 frontend/projects/sdk-ui/src/ui/toastr/index.ts create mode 100644 frontend/projects/sdk-ui/src/ui/toastr/toastr.component.html create mode 100644 frontend/projects/sdk-ui/src/ui/toastr/toastr.component.scss create mode 100644 frontend/projects/sdk-ui/src/ui/toastr/toastr.component.ts create mode 100644 frontend/projects/sdk-ui/src/ui/toastr/toastr.data.ts create mode 100644 frontend/projects/sdk-ui/src/ui/toastr/toastr.directive.ts create mode 100644 frontend/projects/sdk-ui/src/ui/toastr/toastr.interface.ts create mode 100644 frontend/projects/sdk-ui/src/ui/toastr/toastr.module.ts create mode 100644 frontend/projects/sdk-ui/src/ui/toastr/toastr.service.ts create mode 100644 frontend/projects/sdk-ui/src/utils/check-router-childs-data.ts create mode 100644 frontend/projects/sdk-ui/src/utils/index.ts create mode 100644 frontend/projects/sdk-ui/src/utils/ng-package.json create mode 100644 frontend/projects/sdk-ui/tsconfig.lib.json create mode 100644 frontend/projects/sdk-ui/tsconfig.lib.prod.json create mode 100644 frontend/projects/sdk-ui/tsconfig.spec.json create mode 100644 frontend/projects/shared-ui/README.md create mode 100644 frontend/projects/shared-ui/index.ts create mode 100644 frontend/projects/shared-ui/karma.conf.js create mode 100644 frontend/projects/shared-ui/ng-package.json create mode 100644 frontend/projects/shared-ui/package.json create mode 100644 frontend/projects/shared-ui/src/index.ts create mode 100644 frontend/projects/shared-ui/src/pipes/ago.pipe.ts create mode 100644 frontend/projects/shared-ui/src/pipes/boolean-to-text.pipe.ts create mode 100644 frontend/projects/shared-ui/src/pipes/duration.pipe.ts create mode 100644 frontend/projects/shared-ui/src/pipes/enum-to-value.pipe.ts create mode 100644 frontend/projects/shared-ui/src/pipes/format-cpu.pipe.ts create mode 100644 frontend/projects/shared-ui/src/pipes/format-data-size.pipe.ts create mode 100644 frontend/projects/shared-ui/src/pipes/format-empty-string.ts create mode 100644 frontend/projects/shared-ui/src/pipes/format-memory.pipe.ts create mode 100644 frontend/projects/shared-ui/src/pipes/index.ts create mode 100644 frontend/projects/shared-ui/src/pipes/sort.pipe.ts create mode 100644 frontend/projects/shared-ui/src/pipes/str-replace.pipe.ts create mode 100644 frontend/projects/shared-ui/src/shared.module.ts create mode 100644 frontend/projects/shared-ui/src/test.ts create mode 100644 frontend/projects/shared-ui/src/ui/confirm-dialog-static/config-dialog-static.interfaces.ts create mode 100644 frontend/projects/shared-ui/src/ui/confirm-dialog-static/confirm-dialog-static.component.html create mode 100644 frontend/projects/shared-ui/src/ui/confirm-dialog-static/confirm-dialog-static.component.scss create mode 100644 frontend/projects/shared-ui/src/ui/confirm-dialog-static/confirm-dialog-static.component.ts create mode 100644 frontend/projects/shared-ui/src/ui/confirm-dialog/confirm-dialog.component.html create mode 100644 frontend/projects/shared-ui/src/ui/confirm-dialog/confirm-dialog.component.scss create mode 100644 frontend/projects/shared-ui/src/ui/confirm-dialog/confirm-dialog.component.ts create mode 100644 frontend/projects/shared-ui/src/ui/delete-confirm-dialog/delete-config-dialog.interfaces.ts create mode 100644 frontend/projects/shared-ui/src/ui/delete-confirm-dialog/delete-confirm-dialog.component.html create mode 100644 frontend/projects/shared-ui/src/ui/delete-confirm-dialog/delete-confirm-dialog.component.scss create mode 100644 frontend/projects/shared-ui/src/ui/delete-confirm-dialog/delete-confirm-dialog.component.ts create mode 100644 frontend/projects/shared-ui/src/ui/index.ts create mode 100644 frontend/projects/shared-ui/src/ui/nothing-found/nothing-found.component.html create mode 100644 frontend/projects/shared-ui/src/ui/nothing-found/nothing-found.component.scss create mode 100644 frontend/projects/shared-ui/src/ui/nothing-found/nothing-found.component.ts create mode 100644 frontend/projects/shared-ui/src/ui/secure-delete-dialog/secure-delete-dialog.component.html create mode 100644 frontend/projects/shared-ui/src/ui/secure-delete-dialog/secure-delete-dialog.component.scss create mode 100644 frontend/projects/shared-ui/src/ui/secure-delete-dialog/secure-delete-dialog.component.ts create mode 100644 frontend/projects/shared-ui/src/utils/argo.ts create mode 100644 frontend/projects/shared-ui/src/utils/index.ts create mode 100644 frontend/projects/shared-ui/src/utils/k8s-resources-short-name.ts create mode 100644 frontend/projects/shared-ui/src/utils/k8s-routes.ts create mode 100644 frontend/projects/shared-ui/src/utils/utils.ts create mode 100644 frontend/projects/shared-ui/src/validators/array.validators.ts create mode 100644 frontend/projects/shared-ui/src/validators/custom.dns.validators.ts create mode 100644 frontend/projects/shared-ui/src/validators/database.password.validators.ts create mode 100644 frontend/projects/shared-ui/src/validators/email.validator.ts create mode 100644 frontend/projects/shared-ui/src/validators/index.ts create mode 100644 frontend/projects/shared-ui/src/validators/inputs.validators.ts create mode 100644 frontend/projects/shared-ui/src/validators/must-match.validator.ts create mode 100644 frontend/projects/shared-ui/src/validators/no-white-space.validator.ts create mode 100644 frontend/projects/shared-ui/src/validators/password.validator.ts create mode 100644 frontend/projects/shared-ui/src/validators/space.validators.ts create mode 100644 frontend/projects/shared-ui/src/validators/unique.validator.ts create mode 100644 frontend/projects/shared-ui/src/validators/vpc.name.validators.ts create mode 100644 frontend/projects/shared-ui/tsconfig.lib.json create mode 100644 frontend/projects/shared-ui/tsconfig.lib.prod.json create mode 100644 frontend/projects/shared-ui/tsconfig.spec.json create mode 100644 frontend/run.sh create mode 100644 frontend/src/app/app.component.html create mode 100644 frontend/src/app/app.component.scss create mode 100644 frontend/src/app/app.component.spec.ts create mode 100644 frontend/src/app/app.component.ts create mode 100644 frontend/src/app/app.module.ts create mode 100644 frontend/src/app/app.routes.ts create mode 100644 frontend/src/app/auth/auth-routing.module.ts create mode 100644 frontend/src/app/auth/auth.endpoints.ts create mode 100644 frontend/src/app/auth/auth.interface.ts create mode 100644 frontend/src/app/auth/auth.module.ts create mode 100644 frontend/src/app/auth/auth.service.ts create mode 100644 frontend/src/app/auth/login/login.component.html create mode 100644 frontend/src/app/auth/login/login.component.scss create mode 100644 frontend/src/app/auth/login/login.component.spec.ts create mode 100644 frontend/src/app/auth/login/login.component.ts create mode 100644 frontend/src/app/cluster/ClusterFormData.ts create mode 100644 frontend/src/app/cluster/cluster-details/cluster-details.component.html create mode 100644 frontend/src/app/cluster/cluster-details/cluster-details.component.scss create mode 100644 frontend/src/app/cluster/cluster-details/cluster-details.component.spec.ts create mode 100644 frontend/src/app/cluster/cluster-details/cluster-details.component.ts create mode 100644 frontend/src/app/cluster/cluster-details/logs/logs.component.html create mode 100644 frontend/src/app/cluster/cluster-details/logs/logs.component.scss create mode 100644 frontend/src/app/cluster/cluster-details/logs/logs.component.spec.ts create mode 100644 frontend/src/app/cluster/cluster-details/logs/logs.component.ts create mode 100644 frontend/src/app/cluster/cluster-details/overview/cluster-release-dialogs/cluster-release-note-dialog/cluster-release-note-dialog.component.html create mode 100644 frontend/src/app/cluster/cluster-details/overview/cluster-release-dialogs/cluster-release-note-dialog/cluster-release-note-dialog.component.scss create mode 100644 frontend/src/app/cluster/cluster-details/overview/cluster-release-dialogs/cluster-release-note-dialog/cluster-release-note-dialog.component.ts create mode 100644 frontend/src/app/cluster/cluster-details/overview/overview.component.html create mode 100644 frontend/src/app/cluster/cluster-details/overview/overview.component.scss create mode 100644 frontend/src/app/cluster/cluster-details/overview/overview.component.spec.ts create mode 100644 frontend/src/app/cluster/cluster-details/overview/overview.component.ts create mode 100644 frontend/src/app/cluster/cluster-details/settings/cluster-update-form/cluster-update-form.component.html create mode 100644 frontend/src/app/cluster/cluster-details/settings/cluster-update-form/cluster-update-form.component.scss create mode 100644 frontend/src/app/cluster/cluster-details/settings/cluster-update-form/cluster-update-form.component.spec.ts create mode 100644 frontend/src/app/cluster/cluster-details/settings/cluster-update-form/cluster-update-form.component.ts create mode 100644 frontend/src/app/cluster/cluster-details/settings/confirm-delete-dialogue/confirm-delete-dialogue.component.html create mode 100644 frontend/src/app/cluster/cluster-details/settings/confirm-delete-dialogue/confirm-delete-dialogue.component.scss create mode 100644 frontend/src/app/cluster/cluster-details/settings/confirm-delete-dialogue/confirm-delete-dialogue.component.ts create mode 100644 frontend/src/app/cluster/cluster-details/settings/settings.component.html create mode 100644 frontend/src/app/cluster/cluster-details/settings/settings.component.scss create mode 100644 frontend/src/app/cluster/cluster-details/settings/settings.component.spec.ts create mode 100644 frontend/src/app/cluster/cluster-details/settings/settings.component.ts create mode 100644 frontend/src/app/cluster/cluster-intro/cluster-intro.component.html create mode 100644 frontend/src/app/cluster/cluster-intro/cluster-intro.component.scss create mode 100644 frontend/src/app/cluster/cluster-intro/cluster-intro.component.spec.ts create mode 100644 frontend/src/app/cluster/cluster-intro/cluster-intro.component.ts create mode 100644 frontend/src/app/cluster/cluster-list/cluster-list.component.html create mode 100644 frontend/src/app/cluster/cluster-list/cluster-list.component.scss create mode 100644 frontend/src/app/cluster/cluster-list/cluster-list.component.spec.ts create mode 100644 frontend/src/app/cluster/cluster-list/cluster-list.component.ts create mode 100644 frontend/src/app/cluster/cluster-routing.module.ts create mode 100644 frontend/src/app/cluster/cluster.constants.ts create mode 100644 frontend/src/app/cluster/cluster.endpoint.ts create mode 100644 frontend/src/app/cluster/cluster.interface.ts create mode 100644 frontend/src/app/cluster/cluster.module.ts create mode 100644 frontend/src/app/cluster/cluster.resolver.ts create mode 100644 frontend/src/app/cluster/cluster.service.ts create mode 100644 frontend/src/app/cluster/existing-cluster-form/existing-cluster-form.component.html create mode 100644 frontend/src/app/cluster/existing-cluster-form/existing-cluster-form.component.scss create mode 100644 frontend/src/app/cluster/existing-cluster-form/existing-cluster-form.component.spec.ts create mode 100644 frontend/src/app/cluster/existing-cluster-form/existing-cluster-form.component.ts create mode 100644 frontend/src/app/cluster/existing-cluster-form/onboard-cluster-prerequisite/onboard-cluster-prerequisite.component.html create mode 100644 frontend/src/app/cluster/existing-cluster-form/onboard-cluster-prerequisite/onboard-cluster-prerequisite.component.scss create mode 100644 frontend/src/app/cluster/existing-cluster-form/onboard-cluster-prerequisite/onboard-cluster-prerequisite.component.spec.ts create mode 100644 frontend/src/app/cluster/existing-cluster-form/onboard-cluster-prerequisite/onboard-cluster-prerequisite.component.ts create mode 100644 frontend/src/app/errors/error-403/error-403-routing.module.ts create mode 100644 frontend/src/app/errors/error-403/error-403.component.html create mode 100644 frontend/src/app/errors/error-403/error-403.component.scss create mode 100644 frontend/src/app/errors/error-403/error-403.component.ts create mode 100644 frontend/src/app/errors/error-403/error-403.module.ts create mode 100644 frontend/src/app/errors/error-404/error-404-routing.module.ts create mode 100644 frontend/src/app/errors/error-404/error-404.component.html create mode 100644 frontend/src/app/errors/error-404/error-404.component.scss create mode 100644 frontend/src/app/errors/error-404/error-404.component.spec.ts create mode 100644 frontend/src/app/errors/error-404/error-404.component.ts create mode 100644 frontend/src/app/errors/error-404/error-404.module.ts create mode 100644 frontend/src/app/errors/error-500/error-500-routing.module.ts create mode 100644 frontend/src/app/errors/error-500/error-500.component.html create mode 100644 frontend/src/app/errors/error-500/error-500.component.scss create mode 100644 frontend/src/app/errors/error-500/error-500.component.spec.ts create mode 100644 frontend/src/app/errors/error-500/error-500.component.ts create mode 100644 frontend/src/app/errors/error-500/error-500.module.ts create mode 100644 frontend/src/app/k8s/common/components/expansion-data-viewer-template/expansion-data-viewer-template.component.html create mode 100644 frontend/src/app/k8s/common/components/expansion-data-viewer-template/expansion-data-viewer-template.component.scss create mode 100644 frontend/src/app/k8s/common/components/expansion-data-viewer-template/expansion-data-viewer-template.component.ts create mode 100644 frontend/src/app/k8s/common/components/json-data-viewer-template/json-data-viewer-template.component.html create mode 100644 frontend/src/app/k8s/common/components/json-data-viewer-template/json-data-viewer-template.component.scss create mode 100644 frontend/src/app/k8s/common/components/json-data-viewer-template/json-data-viewer-template.component.ts create mode 100644 frontend/src/app/k8s/common/components/json-data-viewer/json-data-viewer.component.html create mode 100644 frontend/src/app/k8s/common/components/json-data-viewer/json-data-viewer.component.scss create mode 100644 frontend/src/app/k8s/common/components/json-data-viewer/json-data-viewer.component.ts create mode 100644 frontend/src/app/k8s/common/components/k8s-events-template/k8s-events-template.component.html create mode 100644 frontend/src/app/k8s/common/components/k8s-events-template/k8s-events-template.component.scss create mode 100644 frontend/src/app/k8s/common/components/k8s-events-template/k8s-events-template.component.ts create mode 100644 frontend/src/app/k8s/common/components/metadata-template/metadata-template.component.html create mode 100644 frontend/src/app/k8s/common/components/metadata-template/metadata-template.component.scss create mode 100644 frontend/src/app/k8s/common/components/metadata-template/metadata-template.component.spec.ts create mode 100644 frontend/src/app/k8s/common/components/metadata-template/metadata-template.component.ts create mode 100644 frontend/src/app/k8s/k8s-cluster-custom-resources/custom-resources-defination-details/custom-resources-defination-details.component.html create mode 100644 frontend/src/app/k8s/k8s-cluster-custom-resources/custom-resources-defination-details/custom-resources-defination-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-cluster-custom-resources/custom-resources-defination-details/custom-resources-defination-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-cluster-custom-resources/custom-resources-defination-list/custom-resources-defination-list.component.html create mode 100644 frontend/src/app/k8s/k8s-cluster-custom-resources/custom-resources-defination-list/custom-resources-defination-list.component.scss create mode 100644 frontend/src/app/k8s/k8s-cluster-custom-resources/custom-resources-defination-list/custom-resources-defination-list.component.ts create mode 100644 frontend/src/app/k8s/k8s-cluster-custom-resources/custom-resources-details/custom-resources-details.component.html create mode 100644 frontend/src/app/k8s/k8s-cluster-custom-resources/custom-resources-details/custom-resources-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-cluster-custom-resources/custom-resources-details/custom-resources-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-cluster-custom-resources/custom-resources-list/custom-resources-list.component.html create mode 100644 frontend/src/app/k8s/k8s-cluster-custom-resources/custom-resources-list/custom-resources-list.component.scss create mode 100644 frontend/src/app/k8s/k8s-cluster-custom-resources/custom-resources-list/custom-resources-list.component.ts create mode 100644 frontend/src/app/k8s/k8s-cluster-custom-resources/k8s-cluster-custom-resources-routing.module.ts create mode 100644 frontend/src/app/k8s/k8s-cluster-custom-resources/k8s-cluster-custom-resources.endpoints.ts create mode 100644 frontend/src/app/k8s/k8s-cluster-custom-resources/k8s-cluster-custom-resources.module.ts create mode 100644 frontend/src/app/k8s/k8s-cluster-custom-resources/k8s-cluster-custom-resources.service.ts create mode 100644 frontend/src/app/k8s/k8s-cluster-role-binding/k8s-cluster-role-binding-details/k8s-cluster-role-binding-details.component.html create mode 100644 frontend/src/app/k8s/k8s-cluster-role-binding/k8s-cluster-role-binding-details/k8s-cluster-role-binding-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-cluster-role-binding/k8s-cluster-role-binding-details/k8s-cluster-role-binding-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-cluster-role-binding/k8s-cluster-role-binding-list/k8s-cluster-role-binding-list.component.html create mode 100644 frontend/src/app/k8s/k8s-cluster-role-binding/k8s-cluster-role-binding-list/k8s-cluster-role-binding-list.component.scss create mode 100644 frontend/src/app/k8s/k8s-cluster-role-binding/k8s-cluster-role-binding-list/k8s-cluster-role-binding-list.component.ts create mode 100644 frontend/src/app/k8s/k8s-cluster-role-binding/k8s-cluster-role-binding-routing.module.ts create mode 100644 frontend/src/app/k8s/k8s-cluster-role-binding/k8s-cluster-role-binding.endpoints.ts create mode 100644 frontend/src/app/k8s/k8s-cluster-role-binding/k8s-cluster-role-binding.module.ts create mode 100644 frontend/src/app/k8s/k8s-cluster-role-binding/k8s-cluster-role-binding.service.ts create mode 100644 frontend/src/app/k8s/k8s-cluster-role/k8s-cluster-role-details/k8s-cluster-role-details.component.html create mode 100644 frontend/src/app/k8s/k8s-cluster-role/k8s-cluster-role-details/k8s-cluster-role-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-cluster-role/k8s-cluster-role-details/k8s-cluster-role-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-cluster-role/k8s-cluster-role-list/k8s-cluster-role-list.component.html create mode 100644 frontend/src/app/k8s/k8s-cluster-role/k8s-cluster-role-list/k8s-cluster-role-list.component.scss create mode 100644 frontend/src/app/k8s/k8s-cluster-role/k8s-cluster-role-list/k8s-cluster-role-list.component.ts create mode 100644 frontend/src/app/k8s/k8s-cluster-role/k8s-cluster-role-routing.module.ts create mode 100644 frontend/src/app/k8s/k8s-cluster-role/k8s-cluster-role.endpoints.ts create mode 100644 frontend/src/app/k8s/k8s-cluster-role/k8s-cluster-role.module.ts create mode 100644 frontend/src/app/k8s/k8s-cluster-role/k8s-cluster-role.service.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-certificates-details/k8s-certificates-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-certificates-details/k8s-certificates-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-certificates-details/k8s-certificates-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-certificates/k8s-certificates.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-certificates/k8s-certificates.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-certificates/k8s-certificates.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-config-maps-details/k8s-config-maps-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-config-maps-details/k8s-config-maps-details.component.spec.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-config-maps-details/k8s-config-maps-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-config-maps/k8s-config-maps.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-config-maps/k8s-config-maps.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-config-maps/k8s-config-maps.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-controller-revision-details/k8s-controller-revision-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-controller-revision-details/k8s-controller-revision-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-controller-revision-details/k8s-controller-revision-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-controller-revision/k8s-controller-revision.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-controller-revision/k8s-controller-revision.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-controller-revision/k8s-controller-revision.component.spec.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-controller-revision/k8s-controller-revision.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-cron-job-details/k8s-cron-job-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-cron-job-details/k8s-cron-job-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-cron-job-details/k8s-cron-job-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-cron-job/k8s-cron-job.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-cron-job/k8s-cron-job.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-cron-job/k8s-cron-job.component.spec.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-cron-job/k8s-cron-job.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-daemon-sets-details/k8s-daemon-sets-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-daemon-sets-details/k8s-daemon-sets-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-daemon-sets-details/k8s-daemon-sets-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-daemon-sets/k8s-daemon-sets.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-daemon-sets/k8s-daemon-sets.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-daemon-sets/k8s-daemon-sets.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-deployments-details/k8s-deployment-pod-list/k8s-deployment-pod-list.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-deployments-details/k8s-deployment-pod-list/k8s-deployment-pod-list.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-deployments-details/k8s-deployment-pod-list/k8s-deployment-pod-list.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-deployments-details/k8s-deployments-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-deployments-details/k8s-deployments-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-deployments-details/k8s-deployments-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-deployments/k8s-deployments.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-deployments/k8s-deployments.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-deployments/k8s-deployments.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-endpoint-slice-details/k8s-endpoint-slice-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-endpoint-slice-details/k8s-endpoint-slice-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-endpoint-slice-details/k8s-endpoint-slice-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-endpoint-slice/k8s-endpoint-slice.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-endpoint-slice/k8s-endpoint-slice.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-endpoint-slice/k8s-endpoint-slice.component.spec.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-endpoint-slice/k8s-endpoint-slice.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-endpoints-details/k8s-endpoints-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-endpoints-details/k8s-endpoints-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-endpoints-details/k8s-endpoints-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-endpoints/k8s-endpoints.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-endpoints/k8s-endpoints.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-endpoints/k8s-endpoints.component.spec.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-endpoints/k8s-endpoints.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-gateway-details/k8s-gateway-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-gateway-details/k8s-gateway-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-gateway-details/k8s-gateway-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-gateway/k8s-gateway.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-gateway/k8s-gateway.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-gateway/k8s-gateway.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-ingresses-details/k8s-ingresses-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-ingresses-details/k8s-ingresses-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-ingresses-details/k8s-ingresses-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-ingresses/k8s-ingresses.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-ingresses/k8s-ingresses.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-ingresses/k8s-ingresses.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-job-details/k8s-job-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-job-details/k8s-job-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-job-details/k8s-job-details.component.spec.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-job-details/k8s-job-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-job/k8s-job.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-job/k8s-job.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-job/k8s-job.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-namespaces-details/k8s-namespaces-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-namespaces-details/k8s-namespaces-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-namespaces-details/k8s-namespaces-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-namespaces-list/k8s-namespaces-list.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-namespaces-list/k8s-namespaces-list.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-namespaces-list/k8s-namespaces-list.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-namespaces-routing.module.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-namespaces.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-namespaces.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-namespaces.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-namespaces.endpoints.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-namespaces.module.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-namespaces.service.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-network-policy-details/k8s-network-policy-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-network-policy-details/k8s-network-policy-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-network-policy-details/k8s-network-policy-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-network-policy/k8s-network-policy.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-network-policy/k8s-network-policy.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-network-policy/k8s-network-policy.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pod-disruption-budgets-details/k8s-pod-disruption-budgets-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pod-disruption-budgets-details/k8s-pod-disruption-budgets-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pod-disruption-budgets-details/k8s-pod-disruption-budgets-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pod-disruption-budgets/k8s-pod-disruption-budgets.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pod-disruption-budgets/k8s-pod-disruption-budgets.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pod-disruption-budgets/k8s-pod-disruption-budgets.component.spec.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pod-disruption-budgets/k8s-pod-disruption-budgets.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pods-details/grafana-dashboard/grafana-dashboard.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pods-details/grafana-dashboard/grafana-dashboard.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pods-details/grafana-dashboard/grafana-dashboard.component.spec.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pods-details/grafana-dashboard/grafana-dashboard.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pods-details/k8s-pods-container-log/k8s-pod-ws.service.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pods-details/k8s-pods-container-log/k8s-pods-container-log.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pods-details/k8s-pods-container-log/k8s-pods-container-log.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pods-details/k8s-pods-container-log/k8s-pods-container-log.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pods-details/k8s-pods-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pods-details/k8s-pods-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pods-details/k8s-pods-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pods/k8s-pods.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pods/k8s-pods.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pods/k8s-pods.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pvcs-details/k8s-pvcs-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pvcs-details/k8s-pvcs-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pvcs-details/k8s-pvcs-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pvcs/k8s-pvcs.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pvcs/k8s-pvcs.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-pvcs/k8s-pvcs.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-replica-sets-details/k8s-replica-sets-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-replica-sets-details/k8s-replica-sets-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-replica-sets-details/k8s-replica-sets-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-replica-sets/k8s-replica-sets.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-replica-sets/k8s-replica-sets.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-replica-sets/k8s-replica-sets.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-replication-controller-details/k8s-replication-controller-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-replication-controller-details/k8s-replication-controller-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-replication-controller-details/k8s-replication-controller-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-replication-controller/k8s-replication-controller.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-replication-controller/k8s-replication-controller.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-replication-controller/k8s-replication-controller.component.spec.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-replication-controller/k8s-replication-controller.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-resource-quota-details/k8s-resource-quota-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-resource-quota-details/k8s-resource-quota-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-resource-quota-details/k8s-resource-quota-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-resource-quota/k8s-resource-quota.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-resource-quota/k8s-resource-quota.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-resource-quota/k8s-resource-quota.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-role-binding-details/k8s-role-binding-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-role-binding-details/k8s-role-binding-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-role-binding-details/k8s-role-binding-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-role-binding/k8s-role-binding.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-role-binding/k8s-role-binding.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-role-binding/k8s-role-binding.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-role-details/k8s-role-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-role-details/k8s-role-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-role-details/k8s-role-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-role/k8s-role.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-role/k8s-role.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-role/k8s-role.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-secrets-details/k8s-secrets-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-secrets-details/k8s-secrets-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-secrets-details/k8s-secrets-details.component.spec.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-secrets-details/k8s-secrets-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-secrets/k8s-secrets.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-secrets/k8s-secrets.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-secrets/k8s-secrets.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-service-accounts-details/k8s-service-accounts-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-service-accounts-details/k8s-service-accounts-details.component.spec.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-service-accounts-details/k8s-service-accounts-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-service-accounts/k8s-service-accounts.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-service-accounts/k8s-service-accounts.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-service-accounts/k8s-service-accounts.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-service-details/k8s-service-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-service-details/k8s-service-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-service-details/k8s-service-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-service/k8s-service.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-service/k8s-service.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-service/k8s-service.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-stateful-sets-details/k8s-stateful-sets-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-stateful-sets-details/k8s-stateful-sets-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-stateful-sets-details/k8s-stateful-sets-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-stateful-sets-details/k8s-statefulset-pod-list/k8s-statefulset-pod-list.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-stateful-sets-details/k8s-statefulset-pod-list/k8s-statefulset-pod-list.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-stateful-sets-details/k8s-statefulset-pod-list/k8s-statefulset-pod-list.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-stateful-sets/k8s-stateful-sets.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-stateful-sets/k8s-stateful-sets.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-stateful-sets/k8s-stateful-sets.component.spec.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-stateful-sets/k8s-stateful-sets.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-virtual-service-details/k8s-virtual-service-details.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-virtual-service-details/k8s-virtual-service-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-virtual-service-details/k8s-virtual-service-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-virtual-service/k8s-virtual-service.component.html create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-virtual-service/k8s-virtual-service.component.scss create mode 100644 frontend/src/app/k8s/k8s-namespaces/k8s-virtual-service/k8s-virtual-service.component.ts create mode 100644 frontend/src/app/k8s/k8s-nodes/k8s-nodes-routing.module.ts create mode 100644 frontend/src/app/k8s/k8s-nodes/k8s-nodes.endpoints.ts create mode 100644 frontend/src/app/k8s/k8s-nodes/k8s-nodes.module.ts create mode 100644 frontend/src/app/k8s/k8s-nodes/k8s-nodes.service.ts create mode 100644 frontend/src/app/k8s/k8s-nodes/node-details/node-details.component.html create mode 100644 frontend/src/app/k8s/k8s-nodes/node-details/node-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-nodes/node-details/node-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-nodes/node-list/node-list.component.html create mode 100644 frontend/src/app/k8s/k8s-nodes/node-list/node-list.component.scss create mode 100644 frontend/src/app/k8s/k8s-nodes/node-list/node-list.component.ts create mode 100644 frontend/src/app/k8s/k8s-nodes/node-list/node-taint-dialog/node-taint-dialog.component.html create mode 100644 frontend/src/app/k8s/k8s-nodes/node-list/node-taint-dialog/node-taint-dialog.component.scss create mode 100644 frontend/src/app/k8s/k8s-nodes/node-list/node-taint-dialog/node-taint-dialog.component.spec.ts create mode 100644 frontend/src/app/k8s/k8s-nodes/node-list/node-taint-dialog/node-taint-dialog.component.ts create mode 100644 frontend/src/app/k8s/k8s-persistent-volume/k8s-persistent-volume-routing.module.ts create mode 100644 frontend/src/app/k8s/k8s-persistent-volume/k8s-persistent-volume.endpoints.ts create mode 100644 frontend/src/app/k8s/k8s-persistent-volume/k8s-persistent-volume.module.ts create mode 100644 frontend/src/app/k8s/k8s-persistent-volume/k8s-persistent-volume.service.ts create mode 100644 frontend/src/app/k8s/k8s-persistent-volume/pv-details/pv-details.component.html create mode 100644 frontend/src/app/k8s/k8s-persistent-volume/pv-details/pv-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-persistent-volume/pv-details/pv-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-persistent-volume/pv-list/pv-list.component.html create mode 100644 frontend/src/app/k8s/k8s-persistent-volume/pv-list/pv-list.component.scss create mode 100644 frontend/src/app/k8s/k8s-persistent-volume/pv-list/pv-list.component.ts create mode 100644 frontend/src/app/k8s/k8s-routing.module.ts create mode 100644 frontend/src/app/k8s/k8s-storage-class/k8s-storage-class-details/k8s-storage-class-details.component.html create mode 100644 frontend/src/app/k8s/k8s-storage-class/k8s-storage-class-details/k8s-storage-class-details.component.scss create mode 100644 frontend/src/app/k8s/k8s-storage-class/k8s-storage-class-details/k8s-storage-class-details.component.ts create mode 100644 frontend/src/app/k8s/k8s-storage-class/k8s-storage-class-list/k8s-storage-class-list.component.html create mode 100644 frontend/src/app/k8s/k8s-storage-class/k8s-storage-class-list/k8s-storage-class-list.component.scss create mode 100644 frontend/src/app/k8s/k8s-storage-class/k8s-storage-class-list/k8s-storage-class-list.component.ts create mode 100644 frontend/src/app/k8s/k8s-storage-class/k8s-storage-class-routing.module.ts create mode 100644 frontend/src/app/k8s/k8s-storage-class/k8s-storage-class.component.scss create mode 100644 frontend/src/app/k8s/k8s-storage-class/k8s-storage-class.endpoints.ts create mode 100644 frontend/src/app/k8s/k8s-storage-class/k8s-storage-class.module.ts create mode 100644 frontend/src/app/k8s/k8s-storage-class/k8s-storage-class.service.ts create mode 100644 frontend/src/app/k8s/k8s-terminal/k8s-terminal-routing.module.ts create mode 100644 frontend/src/app/k8s/k8s-terminal/k8s-terminal.module.ts create mode 100644 frontend/src/app/k8s/k8s-terminal/pod-terminal/pod-terminal.component.html create mode 100644 frontend/src/app/k8s/k8s-terminal/pod-terminal/pod-terminal.component.scss create mode 100644 frontend/src/app/k8s/k8s-terminal/pod-terminal/pod-terminal.component.ts create mode 100644 frontend/src/app/k8s/k8s-update/k8s-update.component.html create mode 100644 frontend/src/app/k8s/k8s-update/k8s-update.component.scss create mode 100644 frontend/src/app/k8s/k8s-update/k8s-update.component.ts create mode 100644 frontend/src/app/k8s/k8s-update/k8s-update.module.ts create mode 100644 frontend/src/app/k8s/k8s.component.html create mode 100644 frontend/src/app/k8s/k8s.component.scss create mode 100644 frontend/src/app/k8s/k8s.component.ts create mode 100644 frontend/src/app/k8s/k8s.endpoints.ts create mode 100644 frontend/src/app/k8s/k8s.module.ts create mode 100644 frontend/src/app/k8s/k8s.resolver.ts create mode 100644 frontend/src/app/k8s/k8s.service.ts create mode 100644 frontend/src/app/management/access-role/access-role-interface.ts create mode 100644 frontend/src/app/management/access-role/access-role-routing.module.ts create mode 100644 frontend/src/app/management/access-role/access-role.endpoints.ts create mode 100644 frontend/src/app/management/access-role/access-role.module.ts create mode 100644 frontend/src/app/management/access-role/access-role.service.ts create mode 100644 frontend/src/app/management/access-role/common/components/role-delete-conformation/role-delete-conformation.component.html create mode 100644 frontend/src/app/management/access-role/common/components/role-delete-conformation/role-delete-conformation.component.scss create mode 100644 frontend/src/app/management/access-role/common/components/role-delete-conformation/role-delete-conformation.component.spec.ts create mode 100644 frontend/src/app/management/access-role/common/components/role-delete-conformation/role-delete-conformation.component.ts create mode 100644 frontend/src/app/management/access-role/containers/access-role-form/access-role-form.component.html create mode 100644 frontend/src/app/management/access-role/containers/access-role-form/access-role-form.component.scss create mode 100644 frontend/src/app/management/access-role/containers/access-role-form/access-role-form.component.ts create mode 100644 frontend/src/app/management/access-role/containers/access-role-list/access-role-list.component.html create mode 100644 frontend/src/app/management/access-role/containers/access-role-list/access-role-list.component.scss create mode 100644 frontend/src/app/management/access-role/containers/access-role-list/access-role-list.component.ts create mode 100644 frontend/src/app/management/user/update-password/update-password.component.html create mode 100644 frontend/src/app/management/user/update-password/update-password.component.scss create mode 100644 frontend/src/app/management/user/update-password/update-password.component.spec.ts create mode 100644 frontend/src/app/management/user/update-password/update-password.component.ts create mode 100644 frontend/src/app/management/user/user-details/user-details.component.html create mode 100644 frontend/src/app/management/user/user-details/user-details.component.scss create mode 100644 frontend/src/app/management/user/user-details/user-details.component.spec.ts create mode 100644 frontend/src/app/management/user/user-details/user-details.component.ts create mode 100644 frontend/src/app/management/user/user-details/user-permission-item/user-permission-item.component.html create mode 100644 frontend/src/app/management/user/user-details/user-permission-item/user-permission-item.component.scss create mode 100644 frontend/src/app/management/user/user-details/user-permission-item/user-permission-item.component.spec.ts create mode 100644 frontend/src/app/management/user/user-details/user-permission-item/user-permission-item.component.ts create mode 100644 frontend/src/app/management/user/user-details/user-role-update-form/user-role-update-form.component.html create mode 100644 frontend/src/app/management/user/user-details/user-role-update-form/user-role-update-form.component.scss create mode 100644 frontend/src/app/management/user/user-details/user-role-update-form/user-role-update-form.component.spec.ts create mode 100644 frontend/src/app/management/user/user-details/user-role-update-form/user-role-update-form.component.ts create mode 100644 frontend/src/app/management/user/user-form/user-form.component.html create mode 100644 frontend/src/app/management/user/user-form/user-form.component.scss create mode 100644 frontend/src/app/management/user/user-form/user-form.component.spec.ts create mode 100644 frontend/src/app/management/user/user-form/user-form.component.ts create mode 100644 frontend/src/app/management/user/user-list/user-list.component.html create mode 100644 frontend/src/app/management/user/user-list/user-list.component.scss create mode 100644 frontend/src/app/management/user/user-list/user-list.component.spec.ts create mode 100644 frontend/src/app/management/user/user-list/user-list.component.ts create mode 100644 frontend/src/app/management/user/user-routing.module.ts create mode 100644 frontend/src/app/management/user/user.endpoints.ts create mode 100644 frontend/src/app/management/user/user.interfaces.ts create mode 100644 frontend/src/app/management/user/user.module.ts create mode 100644 frontend/src/app/management/user/user.service.spec.ts create mode 100644 frontend/src/app/management/user/user.service.ts create mode 100644 frontend/src/app/management/user/user.ts create mode 100644 frontend/src/app/settings/settings-routing.module.ts create mode 100644 frontend/src/app/settings/settings.module.ts create mode 100644 frontend/src/app/settings/system-settings/common/components/theme-info/theme-info.component.html create mode 100644 frontend/src/app/settings/system-settings/common/components/theme-info/theme-info.component.scss create mode 100644 frontend/src/app/settings/system-settings/common/components/theme-info/theme-info.component.spec.ts create mode 100644 frontend/src/app/settings/system-settings/common/components/theme-info/theme-info.component.ts create mode 100644 frontend/src/app/settings/system-settings/containers/system-settings/system-settings.component.html create mode 100644 frontend/src/app/settings/system-settings/containers/system-settings/system-settings.component.scss create mode 100644 frontend/src/app/settings/system-settings/containers/system-settings/system-settings.component.spec.ts create mode 100644 frontend/src/app/settings/system-settings/containers/system-settings/system-settings.component.ts create mode 100644 frontend/src/app/settings/system-settings/system-settings-routing.module.ts create mode 100644 frontend/src/app/settings/system-settings/system-settings.endpoints.ts create mode 100644 frontend/src/app/settings/system-settings/system-settings.module.ts create mode 100644 frontend/src/app/settings/system-settings/system-settings.service.ts create mode 100644 frontend/src/app/user-profile/change-password/change-password.component.html create mode 100644 frontend/src/app/user-profile/change-password/change-password.component.scss create mode 100644 frontend/src/app/user-profile/change-password/change-password.component.spec.ts create mode 100644 frontend/src/app/user-profile/change-password/change-password.component.ts create mode 100644 frontend/src/app/user-profile/user-profile-details/user-profile-details.component.html create mode 100644 frontend/src/app/user-profile/user-profile-details/user-profile-details.component.scss create mode 100644 frontend/src/app/user-profile/user-profile-details/user-profile-details.component.spec.ts create mode 100644 frontend/src/app/user-profile/user-profile-details/user-profile-details.component.ts create mode 100644 frontend/src/app/user-profile/user-profile-routing.module.ts create mode 100644 frontend/src/app/user-profile/user-profile.module.ts create mode 100644 frontend/src/assets/.gitkeep create mode 100644 frontend/src/assets/img/Backed by AWS Route 53.svg create mode 100644 frontend/src/assets/img/CASSANDRA-2.svg create mode 100644 frontend/src/assets/img/CASSANDRA.svg create mode 100644 frontend/src/assets/img/Cloud.svg create mode 100644 frontend/src/assets/img/Grafana_logo.svg create mode 100644 frontend/src/assets/img/Highly Available.svg create mode 100644 frontend/src/assets/img/Integrated Security.svg create mode 100644 frontend/src/assets/img/KAFKA.svg create mode 100644 frontend/src/assets/img/Latency Based Routing.svg create mode 100644 frontend/src/assets/img/MONGODB.svg create mode 100644 frontend/src/assets/img/MSSQL.svg create mode 100644 frontend/src/assets/img/MYSQL.svg create mode 100644 frontend/src/assets/img/POSTGRESQL-2.svg create mode 100644 frontend/src/assets/img/POSTGRESQL.svg create mode 100644 frontend/src/assets/img/RABBITMQ.svg create mode 100644 frontend/src/assets/img/REDIS-2.svg create mode 100644 frontend/src/assets/img/REDIS.svg create mode 100644 frontend/src/assets/img/Support DNS Failover.svg create mode 100644 frontend/src/assets/img/access.svg create mode 100644 frontend/src/assets/img/apache-server.svg create mode 100644 frontend/src/assets/img/app-home.svg create mode 100644 frontend/src/assets/img/application.svg create mode 100644 frontend/src/assets/img/automatic.svg create mode 100644 frontend/src/assets/img/automatic_database.svg create mode 100644 frontend/src/assets/img/bin.svg create mode 100644 frontend/src/assets/img/bitnami/cassandra.svg create mode 100644 frontend/src/assets/img/bitnami/grafana.svg create mode 100644 frontend/src/assets/img/bitnami/kafka.svg create mode 100644 frontend/src/assets/img/bitnami/mongodb.svg create mode 100644 frontend/src/assets/img/bitnami/mysql.svg create mode 100644 frontend/src/assets/img/bitnami/postgresql.svg create mode 100644 frontend/src/assets/img/bitnami/rabbitmq.svg create mode 100644 frontend/src/assets/img/bitnami/redis.svg create mode 100644 frontend/src/assets/img/bitnami/wordpress.svg create mode 100644 frontend/src/assets/img/bucket-icon.svg create mode 100644 frontend/src/assets/img/bucket.svg create mode 100644 frontend/src/assets/img/cache.svg create mode 100644 frontend/src/assets/img/cassandra-custom.svg create mode 100644 frontend/src/assets/img/checked-2.svg create mode 100644 frontend/src/assets/img/checked.svg create mode 100644 frontend/src/assets/img/cloud-network.svg create mode 100644 frontend/src/assets/img/company-custom.svg create mode 100644 frontend/src/assets/img/cpu-custom.svg create mode 100644 frontend/src/assets/img/cpu-twotone.svg create mode 100644 frontend/src/assets/img/cpu.svg create mode 100644 frontend/src/assets/img/credit.svg create mode 100644 frontend/src/assets/img/current_alloc.svg create mode 100644 frontend/src/assets/img/data-storage-custom.svg create mode 100644 frontend/src/assets/img/data-storage.svg create mode 100644 frontend/src/assets/img/database-intro.svg create mode 100644 frontend/src/assets/img/database.svg create mode 100644 frontend/src/assets/img/debit.svg create mode 100644 frontend/src/assets/img/ellipsis.svg create mode 100644 frontend/src/assets/img/failed-bg.svg create mode 100644 frontend/src/assets/img/failed-icon.svg create mode 100644 frontend/src/assets/img/failed.svg create mode 100644 frontend/src/assets/img/fast.svg create mode 100644 frontend/src/assets/img/gateways/credit.svg create mode 100644 frontend/src/assets/img/gateways/local-gateway-bd.svg create mode 100644 frontend/src/assets/img/gateways/pay-offline.svg create mode 100644 frontend/src/assets/img/gateways/paypal.svg create mode 100644 frontend/src/assets/img/helm/resources/c-role.svg create mode 100644 frontend/src/assets/img/helm/resources/cm.svg create mode 100644 frontend/src/assets/img/helm/resources/crb.svg create mode 100644 frontend/src/assets/img/helm/resources/crd.svg create mode 100644 frontend/src/assets/img/helm/resources/cronjob.svg create mode 100644 frontend/src/assets/img/helm/resources/deploy.svg create mode 100644 frontend/src/assets/img/helm/resources/ds.svg create mode 100644 frontend/src/assets/img/helm/resources/ep.svg create mode 100644 frontend/src/assets/img/helm/resources/group.svg create mode 100644 frontend/src/assets/img/helm/resources/hpa.svg create mode 100644 frontend/src/assets/img/helm/resources/ing.svg create mode 100644 frontend/src/assets/img/helm/resources/job.svg create mode 100644 frontend/src/assets/img/helm/resources/limits.svg create mode 100644 frontend/src/assets/img/helm/resources/netpol.svg create mode 100644 frontend/src/assets/img/helm/resources/ns.svg create mode 100644 frontend/src/assets/img/helm/resources/pod.svg create mode 100644 frontend/src/assets/img/helm/resources/psp.svg create mode 100644 frontend/src/assets/img/helm/resources/pv.svg create mode 100644 frontend/src/assets/img/helm/resources/pvc.svg create mode 100644 frontend/src/assets/img/helm/resources/quota.svg create mode 100644 frontend/src/assets/img/helm/resources/rb.svg create mode 100644 frontend/src/assets/img/helm/resources/role.svg create mode 100644 frontend/src/assets/img/helm/resources/rs.svg create mode 100644 frontend/src/assets/img/helm/resources/sa.svg create mode 100644 frontend/src/assets/img/helm/resources/sc.svg create mode 100644 frontend/src/assets/img/helm/resources/secret.svg create mode 100644 frontend/src/assets/img/helm/resources/sts.svg create mode 100644 frontend/src/assets/img/helm/resources/svc.svg create mode 100644 frontend/src/assets/img/helm/resources/user.svg create mode 100644 frontend/src/assets/img/helm/resources/vol.svg create mode 100644 frontend/src/assets/img/ic-klovercloud-logo.png create mode 100644 frontend/src/assets/img/ico-tool-tip.svg create mode 100644 frontend/src/assets/img/icons/airdrop.svg create mode 100644 frontend/src/assets/img/icons/application-build-config-custom.svg create mode 100644 frontend/src/assets/img/icons/application-config-custom.svg create mode 100644 frontend/src/assets/img/icons/bin1.svg create mode 100644 frontend/src/assets/img/icons/bucket-settings-1.svg create mode 100644 frontend/src/assets/img/icons/bucket-settings-2.svg create mode 100644 frontend/src/assets/img/icons/bucket-settings-3.svg create mode 100644 frontend/src/assets/img/icons/bucket-settings-4.svg create mode 100644 frontend/src/assets/img/icons/calendar.svg create mode 100644 frontend/src/assets/img/icons/camera.svg create mode 100644 frontend/src/assets/img/icons/cancelled.svg create mode 100644 frontend/src/assets/img/icons/capacity-custom.svg create mode 100644 frontend/src/assets/img/icons/ci-cd-pipeline/custom.svg create mode 100644 frontend/src/assets/img/icons/ci-cd-pipeline/env-dev.svg create mode 100644 frontend/src/assets/img/icons/ci-cd-pipeline/env-prod-success.svg create mode 100644 frontend/src/assets/img/icons/ci-cd-pipeline/env-qa.svg create mode 100644 frontend/src/assets/img/icons/cloud-server.svg create mode 100644 frontend/src/assets/img/icons/cloud_loader.svg create mode 100644 frontend/src/assets/img/icons/cluster-icon-2.svg create mode 100644 frontend/src/assets/img/icons/cluster-icon.svg create mode 100644 frontend/src/assets/img/icons/cluster/cicd.svg create mode 100644 frontend/src/assets/img/icons/cluster/cluster_name.svg create mode 100644 frontend/src/assets/img/icons/cluster/desired_node.svg create mode 100644 frontend/src/assets/img/icons/cluster/disc_size.svg create mode 100644 frontend/src/assets/img/icons/cluster/max_node.svg create mode 100644 frontend/src/assets/img/icons/cluster/max_unavailable.svg create mode 100644 frontend/src/assets/img/icons/cluster/maximum_util.svg create mode 100644 frontend/src/assets/img/icons/cluster/min_node.svg create mode 100644 frontend/src/assets/img/icons/cluster/name.svg create mode 100644 frontend/src/assets/img/icons/cluster/node_type.svg create mode 100644 frontend/src/assets/img/icons/database.svg create mode 100644 frontend/src/assets/img/icons/database_ns.svg create mode 100644 frontend/src/assets/img/icons/db-security.svg create mode 100644 frontend/src/assets/img/icons/dedicated-externanl-endpoint-custom.svg create mode 100644 frontend/src/assets/img/icons/delete-custom.svg create mode 100644 frontend/src/assets/img/icons/deploy.svg create mode 100644 frontend/src/assets/img/icons/dev-computer.svg create mode 100644 frontend/src/assets/img/icons/discussion.svg create mode 100644 frontend/src/assets/img/icons/docker-icon.svg create mode 100644 frontend/src/assets/img/icons/easy-icon.svg create mode 100644 frontend/src/assets/img/icons/edit-custom.svg create mode 100644 frontend/src/assets/img/icons/endpoint-custom.svg create mode 100644 frontend/src/assets/img/icons/external-endpoint-custom.svg create mode 100644 frontend/src/assets/img/icons/failed.svg create mode 100644 frontend/src/assets/img/icons/folder-explore.svg create mode 100644 frontend/src/assets/img/icons/git-icon.svg create mode 100644 frontend/src/assets/img/icons/hosted_zone.svg create mode 100644 frontend/src/assets/img/icons/ic-active-deployment.gif create mode 100644 frontend/src/assets/img/icons/ic-active-deployment.svg create mode 100644 frontend/src/assets/img/icons/ic-app-deleted.svg create mode 100644 frontend/src/assets/img/icons/ic-application-others.svg create mode 100644 frontend/src/assets/img/icons/ic-application.svg create mode 100644 frontend/src/assets/img/icons/ic-bitbucket.svg create mode 100644 frontend/src/assets/img/icons/ic-build-success.svg create mode 100644 frontend/src/assets/img/icons/ic-certificate.png create mode 100644 frontend/src/assets/img/icons/ic-check-circle.svg create mode 100644 frontend/src/assets/img/icons/ic-checked.svg create mode 100644 frontend/src/assets/img/icons/ic-cicd-approved.svg create mode 100644 frontend/src/assets/img/icons/ic-cicd-disapproved.svg create mode 100644 frontend/src/assets/img/icons/ic-cicd-edit.svg create mode 100644 frontend/src/assets/img/icons/ic-cicd-info.svg create mode 100644 frontend/src/assets/img/icons/ic-cicd-start.svg create mode 100644 frontend/src/assets/img/icons/ic-cicd-stop.svg create mode 100644 frontend/src/assets/img/icons/ic-company.svg create mode 100644 frontend/src/assets/img/icons/ic-database-2.svg create mode 100644 frontend/src/assets/img/icons/ic-database.svg create mode 100644 frontend/src/assets/img/icons/ic-delete.gif create mode 100644 frontend/src/assets/img/icons/ic-deployment-failed.svg create mode 100644 frontend/src/assets/img/icons/ic-docker-build-failed.svg create mode 100644 frontend/src/assets/img/icons/ic-docker-building.gif create mode 100644 frontend/src/assets/img/icons/ic-docker-building.svg create mode 100644 frontend/src/assets/img/icons/ic-error-1.svg create mode 100644 frontend/src/assets/img/icons/ic-git.png create mode 100644 frontend/src/assets/img/icons/ic-github-dark.svg create mode 100644 frontend/src/assets/img/icons/ic-github.svg create mode 100644 frontend/src/assets/img/icons/ic-gitlab.svg create mode 100644 frontend/src/assets/img/icons/ic-google.svg create mode 100644 frontend/src/assets/img/icons/ic-hourglass.gif create mode 100644 frontend/src/assets/img/icons/ic-individual.svg create mode 100644 frontend/src/assets/img/icons/ic-ongoing-deployment.gif create mode 100644 frontend/src/assets/img/icons/ic-ongoing-deployment.svg create mode 100644 frontend/src/assets/img/icons/ic-pending.svg create mode 100644 frontend/src/assets/img/icons/ic-product-object-storage-1.svg create mode 100644 frontend/src/assets/img/icons/ic-product-object-storage-2.svg create mode 100644 frontend/src/assets/img/icons/ic-product-object-storage-3.svg create mode 100644 frontend/src/assets/img/icons/ic-product-object-storage.svg create mode 100644 frontend/src/assets/img/icons/ic-region-custom.svg create mode 100644 frontend/src/assets/img/icons/ic-scale.svg create mode 100644 frontend/src/assets/img/icons/ic-team.svg create mode 100644 frontend/src/assets/img/icons/ic-theme-dark.svg create mode 100644 frontend/src/assets/img/icons/ic-theme-light.svg create mode 100644 frontend/src/assets/img/icons/ic-theme-pink.svg create mode 100644 frontend/src/assets/img/icons/ic-unverified-user.svg create mode 100644 frontend/src/assets/img/icons/ic-verified-user.svg create mode 100644 frontend/src/assets/img/icons/ic-vpc-intialization-failed.svg create mode 100644 frontend/src/assets/img/icons/ic-vpc-intializing.gif create mode 100644 frontend/src/assets/img/icons/ic-vpc-intializing.svg create mode 100644 frontend/src/assets/img/icons/ic-vpc-terminating.gif create mode 100644 frontend/src/assets/img/icons/ic-vpc-terminating.svg create mode 100644 frontend/src/assets/img/icons/ic-vpc-termination-failed.svg create mode 100644 frontend/src/assets/img/icons/ic_build.png create mode 100644 frontend/src/assets/img/icons/ic_cluster.png create mode 100644 frontend/src/assets/img/icons/ic_cpu.png create mode 100644 frontend/src/assets/img/icons/ic_django.png create mode 100644 frontend/src/assets/img/icons/ic_docker.png create mode 100644 frontend/src/assets/img/icons/ic_docker_black.png create mode 100644 frontend/src/assets/img/icons/ic_dot_net.png create mode 100644 frontend/src/assets/img/icons/ic_error.png create mode 100644 frontend/src/assets/img/icons/ic_expressjs.png create mode 100644 frontend/src/assets/img/icons/ic_folder_git.png create mode 100644 frontend/src/assets/img/icons/ic_folder_git_blue.svg create mode 100644 frontend/src/assets/img/icons/ic_gears.svg create mode 100644 frontend/src/assets/img/icons/ic_git.png create mode 100644 frontend/src/assets/img/icons/ic_git_branch.png create mode 100644 frontend/src/assets/img/icons/ic_git_red.png create mode 100644 frontend/src/assets/img/icons/ic_hard_drive.png create mode 100644 frontend/src/assets/img/icons/ic_klovercloud_logo.png create mode 100644 frontend/src/assets/img/icons/ic_laravel.png create mode 100644 frontend/src/assets/img/icons/ic_launch.svg create mode 100644 frontend/src/assets/img/icons/ic_network_storage.png create mode 100644 frontend/src/assets/img/icons/ic_new_app.png create mode 100644 frontend/src/assets/img/icons/ic_ram.png create mode 100644 frontend/src/assets/img/icons/ic_spring.svg create mode 100644 frontend/src/assets/img/icons/ic_success.png create mode 100644 frontend/src/assets/img/icons/ic_success_2.png create mode 100644 frontend/src/assets/img/icons/ic_warning.png create mode 100644 frontend/src/assets/img/icons/ic_wordpress.png create mode 100644 frontend/src/assets/img/icons/ico-application-buildtype.svg create mode 100644 frontend/src/assets/img/icons/ico-application-c-sharp.svg create mode 100644 frontend/src/assets/img/icons/ico-application-csharp.svg create mode 100644 frontend/src/assets/img/icons/ico-application-golang.svg create mode 100644 frontend/src/assets/img/icons/ico-application-instances.svg create mode 100644 frontend/src/assets/img/icons/ico-application-java.svg create mode 100644 frontend/src/assets/img/icons/ico-application-javascript.svg create mode 100644 frontend/src/assets/img/icons/ico-application-list.svg create mode 100644 frontend/src/assets/img/icons/ico-application-others.svg create mode 100644 frontend/src/assets/img/icons/ico-application-php.svg create mode 100644 frontend/src/assets/img/icons/ico-application-python.svg create mode 100644 frontend/src/assets/img/icons/ico-application-status.svg create mode 100644 frontend/src/assets/img/icons/ico-application-team.svg create mode 100644 frontend/src/assets/img/icons/ico-application.svg create mode 100644 frontend/src/assets/img/icons/ico-auto-scaling.svg create mode 100644 frontend/src/assets/img/icons/ico-bin.svg create mode 100644 frontend/src/assets/img/icons/ico-build.svg create mode 100644 frontend/src/assets/img/icons/ico-canary-deplyment.svg create mode 100644 frontend/src/assets/img/icons/ico-chalander-dark.svg create mode 100644 frontend/src/assets/img/icons/ico-chalander.svg create mode 100644 frontend/src/assets/img/icons/ico-cicd-redeploy.svg create mode 100644 frontend/src/assets/img/icons/ico-cicd-restart.svg create mode 100644 frontend/src/assets/img/icons/ico-cicd-sucessfully.svg create mode 100644 frontend/src/assets/img/icons/ico-cicd-unSucessfull.svg create mode 100644 frontend/src/assets/img/icons/ico-clock-custom.svg create mode 100644 frontend/src/assets/img/icons/ico-cpu-custom.svg create mode 100644 frontend/src/assets/img/icons/ico-cpu-threshold.svg create mode 100644 frontend/src/assets/img/icons/ico-cr.svg create mode 100644 frontend/src/assets/img/icons/ico-custom-basic-auth.svg create mode 100644 frontend/src/assets/img/icons/ico-custom-external-url.svg create mode 100644 frontend/src/assets/img/icons/ico-database-type.svg create mode 100644 frontend/src/assets/img/icons/ico-docker.svg create mode 100644 frontend/src/assets/img/icons/ico-easy-to-use.svg create mode 100644 frontend/src/assets/img/icons/ico-enable-external-url.svg create mode 100644 frontend/src/assets/img/icons/ico-env-dev.svg create mode 100644 frontend/src/assets/img/icons/ico-env-pre-prod.svg create mode 100644 frontend/src/assets/img/icons/ico-env-prod.svg create mode 100644 frontend/src/assets/img/icons/ico-env-qa.svg create mode 100644 frontend/src/assets/img/icons/ico-env-staging.svg create mode 100644 frontend/src/assets/img/icons/ico-env-test.svg create mode 100644 frontend/src/assets/img/icons/ico-excution.svg create mode 100644 frontend/src/assets/img/icons/ico-filebrowser.svg create mode 100644 frontend/src/assets/img/icons/ico-git-commit-id.svg create mode 100644 frontend/src/assets/img/icons/ico-git.svg create mode 100644 frontend/src/assets/img/icons/ico-instances.svg create mode 100644 frontend/src/assets/img/icons/ico-intro-app-on-boarding.svg create mode 100644 frontend/src/assets/img/icons/ico-intro-cicd.svg create mode 100644 frontend/src/assets/img/icons/ico-intro-easy-monitoring.svg create mode 100644 frontend/src/assets/img/icons/ico-intro-log-aggregation.svg create mode 100644 frontend/src/assets/img/icons/ico-intro-multiple-env.svg create mode 100644 frontend/src/assets/img/icons/ico-language-custom.svg create mode 100644 frontend/src/assets/img/icons/ico-lock-custom.svg create mode 100644 frontend/src/assets/img/icons/ico-logo-icon.svg create mode 100644 frontend/src/assets/img/icons/ico-max-utilization.svg create mode 100644 frontend/src/assets/img/icons/ico-memory-custom.svg create mode 100644 frontend/src/assets/img/icons/ico-micro-service-platform.svg create mode 100644 frontend/src/assets/img/icons/ico-name-custom.svg create mode 100644 frontend/src/assets/img/icons/ico-phpmyadmin-m.svg create mode 100644 frontend/src/assets/img/icons/ico-port.svg create mode 100644 frontend/src/assets/img/icons/ico-presistent-volume.svg create mode 100644 frontend/src/assets/img/icons/ico-s3-compatiable.svg create mode 100644 frontend/src/assets/img/icons/ico-search-custom.svg create mode 100644 frontend/src/assets/img/icons/ico-spend-less.svg create mode 100644 frontend/src/assets/img/icons/ico-spring-boot.svg create mode 100644 frontend/src/assets/img/icons/ico-sso.svg create mode 100644 frontend/src/assets/img/icons/ico-storage-custom.svg create mode 100644 frontend/src/assets/img/icons/ico-theme-preference.svg create mode 100644 frontend/src/assets/img/icons/ico-tps-threshold.svg create mode 100644 frontend/src/assets/img/icons/ico-user-custom.svg create mode 100644 frontend/src/assets/img/icons/ico-version-custom.svg create mode 100644 frontend/src/assets/img/icons/ico-volume-mount-path.svg create mode 100644 frontend/src/assets/img/icons/ico-vpc-custom.svg create mode 100644 frontend/src/assets/img/icons/ico-vpc-list.svg create mode 100644 frontend/src/assets/img/icons/ico-vpc-outline.svg create mode 100644 frontend/src/assets/img/icons/ico-wp-application.svg create mode 100644 frontend/src/assets/img/icons/ico-zero-trust.svg create mode 100644 frontend/src/assets/img/icons/live-icon.svg create mode 100644 frontend/src/assets/img/icons/manage-backups-icon.svg create mode 100644 frontend/src/assets/img/icons/multi-cluster.svg create mode 100644 frontend/src/assets/img/icons/on-demand-icon.svg create mode 100644 frontend/src/assets/img/icons/org-cog.svg create mode 100644 frontend/src/assets/img/icons/pending.svg create mode 100644 frontend/src/assets/img/icons/play-button.svg create mode 100644 frontend/src/assets/img/icons/records.svg create mode 100644 frontend/src/assets/img/icons/region-custom.svg create mode 100644 frontend/src/assets/img/icons/resources-icon.svg create mode 100644 frontend/src/assets/img/icons/rotate-arrow.svg create mode 100644 frontend/src/assets/img/icons/running.svg create mode 100644 frontend/src/assets/img/icons/search-icon.svg create mode 100644 frontend/src/assets/img/icons/snapshot-custom.svg create mode 100644 frontend/src/assets/img/icons/snapshot-setting-custom.svg create mode 100644 frontend/src/assets/img/icons/snapshot-setting-dark-custom.svg create mode 100644 frontend/src/assets/img/icons/succeeded.svg create mode 100644 frontend/src/assets/img/icons/team-custom.svg create mode 100644 frontend/src/assets/img/icons/team-name-custom.svg create mode 100644 frontend/src/assets/img/icons/type-pdf.svg create mode 100644 frontend/src/assets/img/icons/update-successor.svg create mode 100644 frontend/src/assets/img/icons/upgrade-vpc-custom.svg create mode 100644 frontend/src/assets/img/icons/v2_1.svg create mode 100644 frontend/src/assets/img/icons/webclint-setting-custom.svg create mode 100644 frontend/src/assets/img/icons/webhooks.svg create mode 100644 frontend/src/assets/img/icons/world-wide-web.svg create mode 100644 frontend/src/assets/img/illustrations/checklist.svg create mode 100644 frontend/src/assets/img/illustrations/cms-header.svg create mode 100644 frontend/src/assets/img/illustrations/dashbord-intro-hello-bg.svg create mode 100644 frontend/src/assets/img/illustrations/data_center.svg create mode 100644 frontend/src/assets/img/illustrations/email-verification-steps.svg create mode 100644 frontend/src/assets/img/illustrations/forgot-password-bg.svg create mode 100644 frontend/src/assets/img/illustrations/hello-box-illustration.svg create mode 100644 frontend/src/assets/img/illustrations/idea.svg create mode 100644 frontend/src/assets/img/illustrations/ifg-email-verification.svg create mode 100644 frontend/src/assets/img/illustrations/ifg-email.svg create mode 100644 frontend/src/assets/img/illustrations/it_support.svg create mode 100644 frontend/src/assets/img/illustrations/know-klovercloud.svg create mode 100644 frontend/src/assets/img/illustrations/lets-start-left.svg create mode 100644 frontend/src/assets/img/illustrations/lets-start-right.svg create mode 100644 frontend/src/assets/img/illustrations/login-left-bg-dark.svg create mode 100644 frontend/src/assets/img/illustrations/login-ls-dark-illustration.svg create mode 100644 frontend/src/assets/img/illustrations/login-ls-light-illustration.svg create mode 100644 frontend/src/assets/img/illustrations/login-right-bg-dark.svg create mode 100644 frontend/src/assets/img/illustrations/login-right-bg-dark1.svg create mode 100644 frontend/src/assets/img/illustrations/object-storage-intro-bg-dark.svg create mode 100644 frontend/src/assets/img/illustrations/object-storage-intro-illustration.svg create mode 100644 frontend/src/assets/img/illustrations/object-storage-intro-illustration1.svg create mode 100644 frontend/src/assets/img/illustrations/onboarding-dark-btn-illustration.svg create mode 100644 frontend/src/assets/img/illustrations/onboarding-light-btn-illustration.svg create mode 100644 frontend/src/assets/img/illustrations/peak_mountain_3.svg create mode 100644 frontend/src/assets/img/illustrations/queue-intro.svg create mode 100644 frontend/src/assets/img/illustrations/registration-ls-dark-illustration.svg create mode 100644 frontend/src/assets/img/illustrations/registration-ls-light-illustration.svg create mode 100644 frontend/src/assets/img/illustrations/under_constructions_1.svg create mode 100644 frontend/src/assets/img/instance.svg create mode 100644 frontend/src/assets/img/list-style-custom.svg create mode 100644 frontend/src/assets/img/local-gateway-bd.svg create mode 100644 frontend/src/assets/img/location.svg create mode 100644 frontend/src/assets/img/marketplace.svg create mode 100644 frontend/src/assets/img/max_alloc.svg create mode 100644 frontend/src/assets/img/memory.svg create mode 100644 frontend/src/assets/img/migrate.svg create mode 100644 frontend/src/assets/img/mobile_banking.svg create mode 100644 frontend/src/assets/img/nosql.png create mode 100644 frontend/src/assets/img/object-storage-home.svg create mode 100644 frontend/src/assets/img/organization-custom.svg create mode 100644 frontend/src/assets/img/package.svg create mode 100644 frontend/src/assets/img/pay-offline.svg create mode 100644 frontend/src/assets/img/pay.svg create mode 100644 frontend/src/assets/img/payAsYouGo-custom.svg create mode 100644 frontend/src/assets/img/payment.svg create mode 100644 frontend/src/assets/img/paypal.svg create mode 100644 frontend/src/assets/img/pipeline.png create mode 100644 frontend/src/assets/img/plus.svg create mode 100644 frontend/src/assets/img/pod.svg create mode 100644 frontend/src/assets/img/postgresql-custom.svg create mode 100644 frontend/src/assets/img/prepaid-card-custom.svg create mode 100644 frontend/src/assets/img/processing-shadow.svg create mode 100644 frontend/src/assets/img/providers/aws_logo.svg create mode 100644 frontend/src/assets/img/providers/azure_logo.svg create mode 100644 frontend/src/assets/img/providers/bare_metal_logo.svg create mode 100644 frontend/src/assets/img/providers/digital_ocean_logo.svg create mode 100644 frontend/src/assets/img/providers/gcp_logo.svg create mode 100644 frontend/src/assets/img/providers/onboard.svg create mode 100644 frontend/src/assets/img/providers/robi_logo.svg create mode 100644 frontend/src/assets/img/queue.svg create mode 100644 frontend/src/assets/img/ram-memory-custom.svg create mode 100644 frontend/src/assets/img/ram-memory.svg create mode 100644 frontend/src/assets/img/region-Asia.svg create mode 100644 frontend/src/assets/img/region-Australia.svg create mode 100644 frontend/src/assets/img/region-Europe.svg create mode 100644 frontend/src/assets/img/region-SouthAmerica.svg create mode 100644 frontend/src/assets/img/region-USA.svg create mode 100644 frontend/src/assets/img/region.svg create mode 100644 frontend/src/assets/img/registration-ls-illustration.png create mode 100644 frontend/src/assets/img/relational.png create mode 100644 frontend/src/assets/img/reload.svg create mode 100644 frontend/src/assets/img/robot.svg create mode 100644 frontend/src/assets/img/running.svg create mode 100644 frontend/src/assets/img/server.svg create mode 100644 frontend/src/assets/img/signup-ls-infographics.png create mode 100644 frontend/src/assets/img/sql.jpg create mode 100644 frontend/src/assets/img/storage.svg create mode 100644 frontend/src/assets/img/success-bg.svg create mode 100644 frontend/src/assets/img/success-icon.svg create mode 100644 frontend/src/assets/img/team-custom.svg create mode 100644 frontend/src/assets/img/unverifiedUser.svg create mode 100644 frontend/src/assets/img/verifiedUser.svg create mode 100644 frontend/src/assets/img/vpc-custom.svg create mode 100644 frontend/src/assets/img/vpc-form-basi.svg create mode 100644 frontend/src/assets/img/vpc-form-high.svg create mode 100644 frontend/src/assets/img/vpc-form-price.svg create mode 100644 frontend/src/assets/img/vpc-form-stan.svg create mode 100644 frontend/src/assets/img/vpc-icon.svg create mode 100644 frontend/src/assets/img/vpc.svg create mode 100644 frontend/src/assets/img/wordpress.svg create mode 100644 frontend/src/data/navigation.ts create mode 100644 frontend/src/data/toolbar.ts create mode 100644 frontend/src/environments/environment.prod.ts create mode 100644 frontend/src/environments/environment.ts create mode 100644 frontend/src/favicon.ico create mode 100644 frontend/src/index.html create mode 100644 frontend/src/libs/ace-editor/README.md create mode 100644 frontend/src/libs/ace-editor/acc-editor.enums.ts create mode 100644 frontend/src/libs/ace-editor/ace-editor.component.html create mode 100644 frontend/src/libs/ace-editor/ace-editor.component.scss create mode 100644 frontend/src/libs/ace-editor/ace-editor.component.ts create mode 100644 frontend/src/libs/ace-editor/ace-editor.module.ts create mode 100644 frontend/src/libs/ace-editor/styles.scss create mode 100644 frontend/src/main.ts create mode 100644 frontend/src/note.txt create mode 100644 frontend/src/polyfills.ts create mode 100644 frontend/src/styles.scss create mode 100644 frontend/src/test.ts create mode 100644 frontend/tailwind.config.js create mode 100644 frontend/tsconfig.app.json create mode 100644 frontend/tsconfig.json create mode 100644 frontend/tsconfig.spec.json create mode 100644 frontend/tslint.json create mode 100644 frontend/webpack.config.js create mode 100644 frontend/webpack.prod.config.js diff --git a/.gitignore b/.gitignore index d1a0e6f..fd87fed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,8 @@ .idea .vscode node_modules -coverage \ No newline at end of file +coverage + +frontend/dist +frontend/.angular/cache +frontend/.sass-cache \ No newline at end of file diff --git a/frontend/.browserslistrc b/frontend/.browserslistrc new file mode 100644 index 0000000..f34c633 --- /dev/null +++ b/frontend/.browserslistrc @@ -0,0 +1,12 @@ +# This file is used by the build system to adjust CSS and JS output to support the specified browsers below. +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries + +# You can see what browsers were selected by your queries by running: +# npx browserslist + +> 0.5% +last 2 versions +Firefox ESR +not dead +not IE 9-11 # For IE 9-11 support, remove 'not'. diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/frontend/.prettierignore b/frontend/.prettierignore new file mode 100644 index 0000000..124b16e --- /dev/null +++ b/frontend/.prettierignore @@ -0,0 +1,5 @@ +# Add files here to ignore them from prettier formatting + +/dist +/coverage +nodes_modules \ No newline at end of file diff --git a/frontend/.prettierrc b/frontend/.prettierrc new file mode 100644 index 0000000..6010bf0 --- /dev/null +++ b/frontend/.prettierrc @@ -0,0 +1,14 @@ +{ + "printWidth": 140, + "tabWidth": 2, + "useTabs": false, + "semi": true, + "singleQuote": true, + "trailingComma": "none", + "bracketSpacing": true, + "arrowParens": "avoid", + "rangeStart": 0, + "requirePragma": false, + "insertPragma": false, + "proseWrap": "preserve" +} diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..716b09a --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,41 @@ +### STAGE 1: Build ### + +# We label our stage as 'builder' +FROM node:14.21.1-alpine as builder + +# previous: 8192 +RUN export NODE_OPTIONS=--max_old_space_size=6144 + +WORKDIR /ng-app + +COPY package*.json ./ + +RUN npm i -f + +COPY . . + +RUN npm run build:prod + +### STAGE 2: Setup ### +FROM nginx:1.21 + +ENV KLOVERCLOUD_API_ENDPOINT='' + +## Copy our default nginx config +COPY nginx/default.conf /etc/nginx/conf.d/ +COPY nginx/nginx.conf /etc/nginx/nginx.conf + +## Remove default nginx website +RUN rm -rf /usr/share/nginx/html/* + +## From 'builder' stage copy over the artifacts in dist folder to default nginx public folder +COPY --from=builder /ng-app/dist/kc /usr/share/nginx/html + +RUN mkdir /app +COPY run.sh /app/run.sh +RUN chmod +x /app/run.sh +RUN sed -i -e 's/\r$//' /app/run.sh + +EXPOSE 8000 + +ENTRYPOINT ["bin/sh", "/app/run.sh"] diff --git a/frontend/Dockerfile2 b/frontend/Dockerfile2 new file mode 100644 index 0000000..8caf7f2 --- /dev/null +++ b/frontend/Dockerfile2 @@ -0,0 +1,22 @@ +FROM nginx:1.21 + +ENV KLOVERCLOUD_API_ENDPOINT='' + +## Copy our default nginx config +COPY nginx/default.conf /etc/nginx/conf.d/ +COPY nginx/nginx.conf /etc/nginx/nginx.conf + +## Remove default nginx website +RUN rm -rf /usr/share/nginx/html/* + +## From 'builder' stage copy over the artifacts in dist folder to default nginx public folder +COPY dist/kc /usr/share/nginx/html + +RUN mkdir /app +COPY run.sh /app/run.sh +RUN chmod +x /app/run.sh +RUN sed -i -e 's/\r$//' /app/run.sh + +EXPOSE 8000 + +ENTRYPOINT ["bash", "/app/run.sh"] diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..a725423 --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,30 @@ +### Prerequisites + +> Before we can install Angular-CLI we will have to get a few thing set up first. To run Angular-CLI we will need to install this prerequisite first: + +- **NodeJS** v14.21.1 or newer +- Preferable/Stable Version **NodeJS** v20.14.0 + +### Installing Angular-CLI + +```sh +`npm install -g @angular/cli@latest` +# or +`sudo npm install -g @angular/cli@latest` +``` + +### Install Dependencies +```sh +cd frontend +npm install --force +``` + +### Run App +``` +npm run start +``` + +### Build App +``` +npm run build +``` \ No newline at end of file diff --git a/frontend/angular.json b/frontend/angular.json new file mode 100644 index 0000000..4e88304 --- /dev/null +++ b/frontend/angular.json @@ -0,0 +1,349 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "kc": { + "projectType": "application", + "schematics": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "root": "", + "sourceRoot": "src", + "prefix": "kc", + "architect": { + "build": { + "builder": "@angular-builders/custom-webpack:browser", + "options": { + "outputPath": "dist/kc", + "index": "src/index.html", + "main": "src/main.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "tsconfig.app.json", + "assets": [ + "src/favicon.ico", + "src/assets", + { + "glob": "**/*", + "input": "projects/sdk-ui/assets/images", + "output": "/assets/images" + }, + { + "glob": "**/*", + "input": "projects/sdk-ui/assets/webfonts", + "output": "/assets/webfonts" + } + ], + "styles": ["src/styles.scss", "projects/sdk-ui/assets/styles/tailwind.scss"], + "stylePreprocessorOptions": { + "includePaths": ["projects/cdk/src/styles"] + }, + "customWebpackConfig": { + "path": "./webpack.config.js" + }, + "allowedCommonJsDependencies": [ + "sockjs-client", + "stompjs", + "json2yaml", + "file-saver", + "pako", + "dayjs", + "moment", + "ace-builds", + "dayjs/plugin/localeData", + "dayjs/plugin/localizedFormat", + "dayjs/plugin/objectSupport", + "dayjs/plugin/utc", + "xterm", + "@xterm/addon-fit", + "@xterm/xterm", + "ace-builds/src-noconflict/theme-tomorrow_night_blue", + "ace-builds/src-noconflict/mode-scrypt", + "ace-builds/src-noconflict/mode-yaml", + "ace-builds/src-noconflict/mode-json", + "rfdc", + "pluralize", + "@dagrejs/dagre", + + "@iconify/icons-fa-solid/info-circle", + + "@iconify/icons-ic/twotone-filter-list", + "@iconify/icons-ic/twotone-lock", + "@iconify/icons-ic/twotone-greater-than", + "@iconify/icons-ic/twotone-arrow-drop-up", + "@iconify/icons-ic/twotone-download", + "@iconify/icons-ic/twotone-format-clear", + "@iconify/icons-ic/twotone-mail", + "@iconify/icons-ic/twotone-edit", + "@iconify/icons-ic/twotone-lens", + "@iconify/icons-ic/twotone-keyboard-arrow-down", + "@iconify/icons-ic/twotone-delete", + "@iconify/icons-ic/twotone-cancel", + "@iconify/icons-ic/twotone-more-vert", + "@iconify/icons-ic/twotone-more-horiz", + "@iconify/icons-ic/twotone-info", + "@iconify/icons-ic/twotone-assignment", + "@iconify/icons-ic/twotone-bubble-chart", + "@iconify/icons-ic/twotone-contact-support", + "@iconify/icons-ic/twotone-contacts", + "@iconify/icons-ic/twotone-control-camera", + "@iconify/icons-ic/twotone-dashboard", + "@iconify/icons-ic/twotone-dns", + "@iconify/icons-ic/twotone-flare", + "@iconify/icons-ic/twotone-group-work", + "@iconify/icons-ic/twotone-layers", + "@iconify/icons-ic/twotone-payment", + "@iconify/icons-ic/twotone-settings", + "@iconify/icons-ic/twotone-add", + "@iconify/icons-ic/twotone-open-in-new", + "@iconify/icons-ic/twotone-arrow-right", + "@iconify/icons-ic/twotone-search", + "@iconify/icons-ic/twotone-visibility-off", + "@iconify/icons-ic/twotone-visibility", + "@iconify/icons-ic/twotone-close", + "@iconify/icons-ic/twotone-menu", + "@iconify/icons-ic/twotone-arrow-drop-down", + "@iconify/icons-ic/twotone-refresh", + "@iconify/icons-ic/twotone-label", + "@iconify/icons-ic/twotone-file-upload", + "@iconify/icons-ic/twotone-description", + "@iconify/icons-ic/twotone-timer", + "@iconify/icons-ic/twotone-timer-off", + "@iconify/icons-ic/twotone-category", + "@iconify/icons-ic/twotone-people-outline", + "@iconify/icons-ic/twotone-account-circle", + "@iconify/icons-ic/twotone-queue", + "@iconify/icons-ic/twotone-shield", + "@iconify/icons-ic/twotone-apps", + "@iconify/icons-ic/twotone-explicit", + + "@iconify/icons-ic/expand-more", + "@iconify/icons-ic/keyboard-backspace", + "@iconify/icons-ic/hourglass-empty", + "@iconify/icons-ic/check-circle", + "@iconify/icons-ic/autorenew", + "@iconify/icons-ic/add", + "@iconify/icons-ic/delete", + "@iconify/icons-ic/info", + "@iconify/icons-ic/search", + "@iconify/icons-ic/arrow-back", + "@iconify/icons-ic/drag-handle", + "@iconify/icons-ic/close", + "@iconify/icons-ic/cloud-queue", + "@iconify/icons-ic/arrow-drop-down", + "@iconify/icons-ic/visibility-off", + "@iconify/icons-ic/visibility", + "@iconify/icons-ic/verified-user", + "@iconify/icons-ic/cancel", + "@iconify/icons-ic/do-not-disturb-on", + "@iconify/icons-ic/sharp-check-circle", + "@iconify/icons-ic/add-circle-outline", + "@iconify/icons-ic/lock" + ] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "3mb", + "maximumError": "5mb" + } + ], + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + } + ], + "outputHashing": "all", + "customWebpackConfig": { + "path": "./webpack.prod.config.js" + } + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular-builders/custom-webpack:dev-server", + "configurations": { + "production": { + "browserTarget": "kc:build:production" + }, + "development": { + "browserTarget": "kc:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "kc:build" + } + }, + "test": { + "builder": "@angular-builders/custom-webpack:karma", + "options": { + "main": "src/test.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "tsconfig.spec.json", + "karmaConfig": "karma.conf.js", + "assets": ["src/favicon.ico", "src/assets"], + "styles": ["src/styles.scss"], + "scripts": [] + } + }, + "e2e": { + "builder": "@angular-devkit/build-angular:protractor", + "options": { + "protractorConfig": "e2e/protractor.conf.js", + "devServerTarget": "kc:serve" + }, + "configurations": { + "production": { + "devServerTarget": "kc:serve:production" + } + } + } + } + }, + "cdk-ui": { + "projectType": "library", + "root": "projects/cdk-ui", + "sourceRoot": "projects/cdk-ui/src", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:ng-packagr", + "options": { + "project": "projects/cdk-ui/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/cdk-ui/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/cdk-ui/tsconfig.lib.json" + } + }, + "defaultConfiguration": "production" + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/cdk-ui/src/test.ts", + "tsConfig": "projects/cdk-ui/tsconfig.spec.json", + "karmaConfig": "projects/cdk-ui/karma.conf.js" + } + } + } + }, + "core-ui": { + "projectType": "library", + "root": "projects/core-ui", + "sourceRoot": "projects/core-ui/src", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:ng-packagr", + "options": { + "project": "projects/core-ui/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/core-ui/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/core-ui/tsconfig.lib.json" + } + }, + "defaultConfiguration": "production" + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/core-ui/src/test.ts", + "tsConfig": "projects/core-ui/tsconfig.spec.json", + "karmaConfig": "projects/core-ui/karma.conf.js" + } + } + } + }, + "shared-ui": { + "projectType": "library", + "root": "projects/shared-ui", + "sourceRoot": "projects/shared-ui/src", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:ng-packagr", + "options": { + "project": "projects/shared-ui/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/shared-ui/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/shared-ui/tsconfig.lib.json" + } + }, + "defaultConfiguration": "production" + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/shared-ui/src/test.ts", + "tsConfig": "projects/shared-ui/tsconfig.spec.json", + "karmaConfig": "projects/shared-ui/karma.conf.js" + } + } + } + }, + "sdk-ui": { + "projectType": "library", + "root": "projects/sdk-ui", + "sourceRoot": "projects/sdk-ui/src", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:ng-packagr", + "options": { + "project": "projects/sdk-ui/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/sdk-ui/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/sdk-ui/tsconfig.lib.json" + } + }, + "defaultConfiguration": "production" + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/sdk-ui/src/test.ts", + "tsConfig": "projects/sdk-ui/tsconfig.spec.json", + "karmaConfig": "projects/sdk-ui/karma.conf.js" + } + } + } + } + }, + "cli": { + "analytics": false + } +} diff --git a/frontend/dashboard.json b/frontend/dashboard.json new file mode 100644 index 0000000..e69de29 diff --git a/frontend/e2e/protractor.conf.js b/frontend/e2e/protractor.conf.js new file mode 100644 index 0000000..c92a194 --- /dev/null +++ b/frontend/e2e/protractor.conf.js @@ -0,0 +1,30 @@ +// @ts-check +// Protractor configuration file, see link for more information +// https://github.com/angular/protractor/blob/master/lib/config.ts + +const { SpecReporter } = require('jasmine-spec-reporter'); + +/** + * @type { import("protractor").Config } + */ +exports.config = { + allScriptsTimeout: 11000, + specs: ['./src/**/*.e2e-spec.ts'], + capabilities: { + browserName: 'chrome' + }, + directConnect: true, + baseUrl: 'http://localhost:4200/', + framework: 'jasmine', + jasmineNodeOpts: { + showColors: true, + defaultTimeoutInterval: 30000, + print: function () {} + }, + onPrepare() { + require('ts-node').register({ + project: require('path').join(__dirname, './tsconfig.json') + }); + jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); + } +}; diff --git a/frontend/e2e/src/app.e2e-spec.ts b/frontend/e2e/src/app.e2e-spec.ts new file mode 100644 index 0000000..0086910 --- /dev/null +++ b/frontend/e2e/src/app.e2e-spec.ts @@ -0,0 +1,25 @@ +import { AppPage } from './app.po'; +import { browser, logging } from 'protractor'; + +describe('workspace-project App', () => { + let page: AppPage; + + beforeEach(() => { + page = new AppPage(); + }); + + it('should display welcome message', () => { + page.navigateTo(); + expect(page.getTitleText()).toEqual('Welcome to klovercloud!'); + }); + + afterEach(async () => { + // Assert that there are no errors emitted from the browser + const logs = await browser.manage().logs().get(logging.Type.BROWSER); + expect(logs).not.toContain( + jasmine.objectContaining({ + level: logging.Level.SEVERE + } as logging.Entry) + ); + }); +}); diff --git a/frontend/e2e/src/app.po.ts b/frontend/e2e/src/app.po.ts new file mode 100644 index 0000000..5776aa9 --- /dev/null +++ b/frontend/e2e/src/app.po.ts @@ -0,0 +1,11 @@ +import { browser, by, element } from 'protractor'; + +export class AppPage { + navigateTo() { + return browser.get(browser.baseUrl) as Promise; + } + + getTitleText() { + return element(by.css('app-root h1')).getText() as Promise; + } +} diff --git a/frontend/e2e/tsconfig.json b/frontend/e2e/tsconfig.json new file mode 100644 index 0000000..dbf470a --- /dev/null +++ b/frontend/e2e/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/e2e", + "module": "commonjs", + "target": "es2018", + "types": ["jasmine", "jasminewd2", "node"] + } +} diff --git a/frontend/karma.conf.js b/frontend/karma.conf.js new file mode 100644 index 0000000..2cd177a --- /dev/null +++ b/frontend/karma.conf.js @@ -0,0 +1,32 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, './coverage/kc'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/frontend/nginx/default.conf b/frontend/nginx/default.conf new file mode 100644 index 0000000..bc64c4d --- /dev/null +++ b/frontend/nginx/default.conf @@ -0,0 +1,30 @@ +server { + + listen 8000; + + sendfile on; + + default_type application/octet-stream; + + + gzip on; + gzip_http_version 1.1; + gzip_disable "MSIE [1-6]\."; + gzip_min_length 256; + gzip_vary on; + gzip_proxied expired no-cache no-store private auth; + gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; + gzip_comp_level 9; + + + root /usr/share/nginx/html; + + + location / { + try_files $uri $uri/ /index.html =404; + } + + location /health { + return 200 'I am live :)'; + } +} diff --git a/frontend/nginx/nginx.conf b/frontend/nginx/nginx.conf new file mode 100644 index 0000000..80433d5 --- /dev/null +++ b/frontend/nginx/nginx.conf @@ -0,0 +1,31 @@ +user nginx; +worker_processes 4; + +error_log /var/log/nginx/error.log notice; +pid /var/run/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + keepalive_timeout 65; + + #gzip on; + + include /etc/nginx/conf.d/*.conf; +} diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000..0528ddb --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,16745 @@ +{ + "name": "kc", + "version": "14.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "kc", + "version": "14.0.0", + "dependencies": { + "@angular/animations": "14.3.0", + "@angular/cdk": "14.2.7", + "@angular/common": "14.3.0", + "@angular/compiler": "14.3.0", + "@angular/core": "14.3.0", + "@angular/flex-layout": "^14.0.0-beta.41", + "@angular/forms": "14.3.0", + "@angular/material": "14.2.7", + "@angular/platform-browser": "14.3.0", + "@angular/platform-browser-dynamic": "14.3.0", + "@angular/router": "14.3.0", + "@dagrejs/dagre": "^1.1.4", + "@iconify/icons-fa-brands": "^1.2.4", + "@iconify/icons-fa-solid": "^1.2.4", + "@iconify/icons-ic": "^1.2.13", + "@ngx-loading-bar/core": "^6.0.2", + "@ngx-loading-bar/router": "^6.0.2", + "@swimlane/ngx-charts": "^20.5.0", + "@types/pluralize": "^0.0.33", + "@visurel/iconify-angular": "^11.0.0", + "ace-builds": "^1.32.6", + "dayjs": "^1.11.10", + "file-saver": "^2.0.5", + "js-yaml": "^4.1.0", + "json2yaml": "^1.1.0", + "jwt-decode": "^3.1.2", + "moment": "^2.30.1", + "net": "1.0.2", + "ng-pick-datetime-ex": "^14.0.0", + "ng-terminal": "^6.1.0", + "ng2-search-filter": "0.5.1", + "ngx-webstorage": "^10.0.1", + "normalize.css": "8.0.1", + "pako": "1.0.11", + "pluralize": "^8.0.0", + "rxjs": "^6.6.7", + "sockjs-client": "1.3.0", + "stompjs": "2.3.3", + "tailwindcss": "^2.2.19", + "tslib": "^2.6.2", + "xterm": "^5.3.0", + "zone.js": "^0.11.8" + }, + "devDependencies": { + "@angular-builders/custom-webpack": "^14.1.0", + "@angular-devkit/build-angular": "^14.2.13", + "@angular/cli": "14.2.13", + "@angular/compiler-cli": "14.3.0", + "@angular/language-service": "14.3.0", + "@fullhuman/purgecss-loader": "1.0.0", + "@types/jasmine": "~3.6.0", + "@types/jasminewd2": "2.0.8", + "@types/node": "^12.20.55", + "@types/simplebar": "2.4.2", + "codelyzer": "^6.0.2", + "jasmine-core": "^3.8.0", + "jasmine-spec-reporter": "~5.0.0", + "karma": "~6.4.2", + "karma-chrome-launcher": "~3.1.0", + "karma-coverage-istanbul-reporter": "~3.0.2", + "karma-jasmine": "~4.0.0", + "karma-jasmine-html-reporter": "^1.7.0", + "ng-packagr": "^14.2.2", + "postcss-import": "^15.1.0", + "postcss-loader": "^4.3.0", + "postcss-scss": "^3.0.5", + "prettier": "^3.4.2", + "protractor": "~7.0.0", + "tailwindcss-dir": "4.0.0", + "ts-node": "^9.0.0", + "tslint": "~6.1.0", + "typescript": "4.6.4", + "webpack-bundle-analyzer": "^4.10.1" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.0.tgz", + "integrity": "sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==", + "dev": true + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@angular-builders/custom-webpack": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@angular-builders/custom-webpack/-/custom-webpack-14.1.0.tgz", + "integrity": "sha512-FLGDrBOg04cYvzCudeb15LWY2v91dtJ5+AfmP0aS/0T0D0AYmY4uM3FxZeh4jJcWETLvnHVFBCjan6y2Ct9J3A==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": ">=0.1400.0 < 0.1500.0", + "@angular-devkit/build-angular": "^14.0.0", + "@angular-devkit/core": "^14.0.0", + "lodash": "^4.17.15", + "ts-node": "^10.0.0", + "tsconfig-paths": "^3.9.0", + "webpack-merge": "^5.7.3" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^14.0.0" + } + }, + "node_modules/@angular-builders/custom-webpack/node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/@angular-builders/custom-webpack/node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/@angular-builders/custom-webpack/node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/architect": { + "version": "0.1402.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1402.13.tgz", + "integrity": "sha512-n0ISBuvkZHoOpAzuAZql1TU9VLHUE9e/a9g4VNOPHewjMzpN02VqeGKvJfOCKtzkCs6gVssIlILm2/SXxkIFxQ==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "14.2.13", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/build-angular": { + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-14.2.13.tgz", + "integrity": "sha512-FJZKQ3xYFvEJ807sxVy4bCVyGU2NMl3UUPNfLIdIdzwwDEP9tx/cc+c4VtVPEZZfU8jVenu8XOvL6L0vpjt3yg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "2.2.0", + "@angular-devkit/architect": "0.1402.13", + "@angular-devkit/build-webpack": "0.1402.13", + "@angular-devkit/core": "14.2.13", + "@babel/core": "7.18.10", + "@babel/generator": "7.18.12", + "@babel/helper-annotate-as-pure": "7.18.6", + "@babel/plugin-proposal-async-generator-functions": "7.18.10", + "@babel/plugin-transform-async-to-generator": "7.18.6", + "@babel/plugin-transform-runtime": "7.18.10", + "@babel/preset-env": "7.18.10", + "@babel/runtime": "7.18.9", + "@babel/template": "7.18.10", + "@discoveryjs/json-ext": "0.5.7", + "@ngtools/webpack": "14.2.13", + "ansi-colors": "4.1.3", + "babel-loader": "8.2.5", + "babel-plugin-istanbul": "6.1.1", + "browserslist": "^4.9.1", + "cacache": "16.1.2", + "copy-webpack-plugin": "11.0.0", + "critters": "0.0.16", + "css-loader": "6.7.1", + "esbuild-wasm": "0.15.5", + "glob": "8.0.3", + "https-proxy-agent": "5.0.1", + "inquirer": "8.2.4", + "jsonc-parser": "3.1.0", + "karma-source-map-support": "1.4.0", + "less": "4.1.3", + "less-loader": "11.0.0", + "license-webpack-plugin": "4.0.2", + "loader-utils": "3.2.1", + "mini-css-extract-plugin": "2.6.1", + "minimatch": "5.1.0", + "open": "8.4.0", + "ora": "5.4.1", + "parse5-html-rewriting-stream": "6.0.1", + "piscina": "3.2.0", + "postcss": "8.4.31", + "postcss-import": "15.0.0", + "postcss-loader": "7.0.1", + "postcss-preset-env": "7.8.0", + "regenerator-runtime": "0.13.9", + "resolve-url-loader": "5.0.0", + "rxjs": "6.6.7", + "sass": "1.54.4", + "sass-loader": "13.0.2", + "semver": "7.5.3", + "source-map-loader": "4.0.0", + "source-map-support": "0.5.21", + "stylus": "0.59.0", + "stylus-loader": "7.0.0", + "terser": "5.14.2", + "text-table": "0.2.0", + "tree-kill": "1.2.2", + "tslib": "2.4.0", + "webpack": "5.76.1", + "webpack-dev-middleware": "5.3.3", + "webpack-dev-server": "4.11.0", + "webpack-merge": "5.8.0", + "webpack-subresource-integrity": "5.1.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "optionalDependencies": { + "esbuild": "0.15.5" + }, + "peerDependencies": { + "@angular/compiler-cli": "^14.0.0", + "@angular/localize": "^14.0.0", + "@angular/service-worker": "^14.0.0", + "karma": "^6.3.0", + "ng-packagr": "^14.0.0", + "protractor": "^7.0.0", + "tailwindcss": "^2.0.0 || ^3.0.0", + "typescript": ">=4.6.2 <4.9" + }, + "peerDependenciesMeta": { + "@angular/localize": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "karma": { + "optional": true + }, + "ng-packagr": { + "optional": true + }, + "protractor": { + "optional": true + }, + "tailwindcss": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/esbuild-wasm": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.15.5.tgz", + "integrity": "sha512-lTJOEKekN/4JI/eOEq0wLcx53co2N6vaT/XjBz46D1tvIVoUEyM0o2K6txW6gEotf31szFD/J1PbxmnbkGlK9A==", + "dev": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/@angular-devkit/build-angular/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/postcss-import": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.0.0.tgz", + "integrity": "sha512-Y20shPQ07RitgBGv2zvkEAu9bqvrD77C9axhj/aA1BQj4czape2MdClCExvB27EwYEJdGgKZBpKanb0t1rK2Kg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/postcss-loader": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.1.tgz", + "integrity": "sha512-VRviFEyYlLjctSM93gAZtcJJ/iSkPZ79zWbN/1fSH+NisBByEiVLqpdVDrPLVSi8DX0oJo12kL/GppTBdKVXiQ==", + "dev": true, + "dependencies": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.7" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, + "node_modules/@angular-devkit/build-angular/node_modules/webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@angular-devkit/build-webpack": { + "version": "0.1402.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1402.13.tgz", + "integrity": "sha512-K27aJmuw86ZOdiu5PoGeGDJ2v7g2ZCK0bGwc8jzkjTLRfvd4FRKIIZumGv3hbQ3vQRLikiU6WMDRTFyCZky/EA==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1402.13", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "webpack": "^5.30.0", + "webpack-dev-server": "^4.0.0" + } + }, + "node_modules/@angular-devkit/core": { + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.13.tgz", + "integrity": "sha512-aIefeZcbjghQg/V6U9CTLtyB5fXDJ63KwYqVYkWP+i0XriS5A9puFgq2u/OVsWxAfYvqpDqp5AdQ0g0bi3CAsA==", + "dev": true, + "dependencies": { + "ajv": "8.11.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.1.0", + "rxjs": "6.6.7", + "source-map": "0.7.4" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/core/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@angular-devkit/core/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/@angular-devkit/core/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@angular-devkit/schematics": { + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-14.2.13.tgz", + "integrity": "sha512-2zczyeNzeBcrT2HOysv52X9SH3tZoHfWJvVf6H0SIa74rfDKEl7hFpKNXnh3x8sIMLj5mZn05n5RCqGxCczcIg==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "14.2.13", + "jsonc-parser": "3.1.0", + "magic-string": "0.26.2", + "ora": "5.4.1", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/animations": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-14.3.0.tgz", + "integrity": "sha512-QoBcIKy1ZiU+4qJsAh5Ls20BupWiXiZzKb0s6L9/dntPt5Msr4Ao289XR2P6O1L+kTsCprH9Kt41zyGQ/bkRqg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/core": "14.3.0" + } + }, + "node_modules/@angular/cdk": { + "version": "14.2.7", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-14.2.7.tgz", + "integrity": "sha512-/tEsYaUbDSnfEmKVvAMramIptmhI67O+9STjOV0i+74XR2NospeK0fkbywIANu1n3w6AHGMotvRWJrjmbCElFg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "optionalDependencies": { + "parse5": "^5.0.0" + }, + "peerDependencies": { + "@angular/common": "^14.0.0 || ^15.0.0", + "@angular/core": "^14.0.0 || ^15.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/cli": { + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-14.2.13.tgz", + "integrity": "sha512-I5EepRem2CCyS3GDzQxZ2ZrqQwVqoGoLY+ZQhsK1QGWUnUyFOjbv3OlUGxRUYwcedu19V1EBAKjmQ96HzMIcVQ==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1402.13", + "@angular-devkit/core": "14.2.13", + "@angular-devkit/schematics": "14.2.13", + "@schematics/angular": "14.2.13", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.3", + "debug": "4.3.4", + "ini": "3.0.0", + "inquirer": "8.2.4", + "jsonc-parser": "3.1.0", + "npm-package-arg": "9.1.0", + "npm-pick-manifest": "7.0.1", + "open": "8.4.0", + "ora": "5.4.1", + "pacote": "13.6.2", + "resolve": "1.22.1", + "semver": "7.5.3", + "symbol-observable": "4.0.0", + "uuid": "8.3.2", + "yargs": "17.5.1" + }, + "bin": { + "ng": "bin/ng.js" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/cli/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@angular/cli/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@angular/cli/node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@angular/common": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.3.0.tgz", + "integrity": "sha512-pV9oyG3JhGWeQ+TFB0Qub6a1VZWMNZ6/7zEopvYivdqa5yDLLDSBRWb6P80RuONXyGnM1pa7l5nYopX+r/23GQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/core": "14.3.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/compiler": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-14.3.0.tgz", + "integrity": "sha512-E15Rh0t3vA+bctbKnBCaDmLvc3ix+ZBt6yFZmhZalReQ+KpOlvOJv+L9oiFEgg+rYVl2QdvN7US1fvT0PqswLw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/core": "14.3.0" + }, + "peerDependenciesMeta": { + "@angular/core": { + "optional": true + } + } + }, + "node_modules/@angular/compiler-cli": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-14.3.0.tgz", + "integrity": "sha512-eoKpKdQ2X6axMgzcPUMZVYl3bIlTMzMeTo5V29No4BzgiUB+QoOTYGNJZkGRyqTNpwD9uSBJvmT2vG9+eC4ghQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.17.2", + "chokidar": "^3.0.0", + "convert-source-map": "^1.5.1", + "dependency-graph": "^0.11.0", + "magic-string": "^0.26.0", + "reflect-metadata": "^0.1.2", + "semver": "^7.0.0", + "sourcemap-codec": "^1.4.8", + "tslib": "^2.3.0", + "yargs": "^17.2.1" + }, + "bin": { + "ng-xi18n": "bundles/src/bin/ng_xi18n.js", + "ngc": "bundles/src/bin/ngc.js", + "ngcc": "bundles/ngcc/main-ngcc.js" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/compiler": "14.3.0", + "typescript": ">=4.6.2 <4.9" + } + }, + "node_modules/@angular/core": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-14.3.0.tgz", + "integrity": "sha512-wYiwItc0Uyn4FWZ/OAx/Ubp2/WrD3EgUJ476y1XI7yATGPF8n9Ld5iCXT08HOvc4eBcYlDfh90kTXR6/MfhzdQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.11.4 || ~0.12.0" + } + }, + "node_modules/@angular/flex-layout": { + "version": "14.0.0-beta.41", + "resolved": "https://registry.npmjs.org/@angular/flex-layout/-/flex-layout-14.0.0-beta.41.tgz", + "integrity": "sha512-x1YcxqkdFlcbVXEy9ebCgW/F+7n/MXkEkwEcVEIPf5v5qn7HZsjQxgIj35Lf0amvMyF7h35prpoxO1uX5+ntFg==", + "deprecated": "This package has been deprecated. Please see https://blog.angular.io/modern-css-in-angular-layouts-4a259dca9127", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/cdk": "^14.0.0", + "@angular/common": "^14.0.0", + "@angular/core": "^14.0.0", + "@angular/platform-browser": "^14.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/forms": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-14.3.0.tgz", + "integrity": "sha512-fBZZC2UFMom2AZPjGQzROPXFWO6kvCsPDKctjJwClVC8PuMrkm+RRyiYRdBbt2qxWHEqOZM2OCQo73xUyZOYHw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/common": "14.3.0", + "@angular/core": "14.3.0", + "@angular/platform-browser": "14.3.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/language-service": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-14.3.0.tgz", + "integrity": "sha512-Sij3OQzj1UGs1O8H9PxVAY/o27+oqZwQRnib66rsWvtbIBTjHp4FV3dTs5iVcr62GGv4V4Mff/2I82NP10GPQg==", + "dev": true, + "engines": { + "node": "^14.15.0 || >=16.10.0" + } + }, + "node_modules/@angular/material": { + "version": "14.2.7", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-14.2.7.tgz", + "integrity": "sha512-WXHh8pEStpgkXZJmYOg2cI8BSHkV82ET4XTJCNPdveumaCn1UYnaNzsXD13kw5z+zmy8CufhFEzdXTrv/yt7KQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/animations": "^14.0.0 || ^15.0.0", + "@angular/cdk": "14.2.7", + "@angular/common": "^14.0.0 || ^15.0.0", + "@angular/core": "^14.0.0 || ^15.0.0", + "@angular/forms": "^14.0.0 || ^15.0.0", + "@angular/platform-browser": "^14.0.0 || ^15.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/platform-browser": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-14.3.0.tgz", + "integrity": "sha512-w9Y3740UmTz44T0Egvc+4QV9sEbO61L+aRHbpkLTJdlEGzHByZvxJmJyBYmdqeyTPwc/Zpy7c02frlpfAlyB7A==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/animations": "14.3.0", + "@angular/common": "14.3.0", + "@angular/core": "14.3.0" + }, + "peerDependenciesMeta": { + "@angular/animations": { + "optional": true + } + } + }, + "node_modules/@angular/platform-browser-dynamic": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-14.3.0.tgz", + "integrity": "sha512-rneZiMrIiYRhrkQvdL40E2ErKRn4Zdo6EtjBM9pAmWeyoM8oMnOZb9gz5vhrkNWg06kVMVg0yKqluP5How7j3A==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/common": "14.3.0", + "@angular/compiler": "14.3.0", + "@angular/core": "14.3.0", + "@angular/platform-browser": "14.3.0" + } + }, + "node_modules/@angular/router": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-14.3.0.tgz", + "integrity": "sha512-uip0V7w7k7xyxxpTPbr7EuMnYLj3FzJrwkLVJSEw3TMMGHt5VU5t4BBa9veGZOta2C205XFrTAHnp8mD+XYY1w==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/common": "14.3.0", + "@angular/core": "14.3.0", + "@angular/platform-browser": "14.3.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@assemblyscript/loader": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", + "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", + "dev": true + }, + "node_modules/@babel/code-frame": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.9.tgz", + "integrity": "sha512-z88xeGxnzehn2sqZ8UdGQEvYErF1odv2CftxInpSYJt6uHuPe9YjahKZITGs3l5LeI9d2ROG+obuDAoSlqbNfQ==", + "dependencies": { + "@babel/highlight": "^7.25.9", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.9.tgz", + "integrity": "sha512-yD+hEuJ/+wAJ4Ox2/rpNv5HIuPG82x3ZlQvYVn8iYCprdxzE7P1udpGF1jyjQVBU4dgznN+k2h103vxZ7NdPyw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.10.tgz", + "integrity": "sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.10", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helpers": "^7.18.9", + "@babel/parser": "^7.18.10", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.10", + "@babel/types": "^7.18.10", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.18.12", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz", + "integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.10", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.9.tgz", + "integrity": "sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", + "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.25.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.9.tgz", + "integrity": "sha512-ORPNZ3h6ZRkOyAa/SaHU+XsLZr0UQzRwuDQ0cczIA17nAzZ+85G5cVkOJIj7QavLZGSe8QXUmNFxSZzjcZF9bw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "regexpu-core": "^6.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.9.tgz", + "integrity": "sha512-TvLZY/F3+GvdRYFZFyxMvnsKi+4oJdgZzU3BoGN9Uc2d9C6zfNwJcKKhjqLAhK8i46mv93jsO74fDh3ih6rpHA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-simple-access": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", + "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-wrap-function": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz", + "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.9.tgz", + "integrity": "sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", + "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", + "dev": true, + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function/node_modules/@babel/template": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.9.tgz", + "integrity": "sha512-oKWp3+usOJSzDZOucZUAMayhPz/xVjzymyDzUN8dk0Wd3RWMlGLXi07UCQ/CgQVb8LvXx3XBajJH4XGgkt7H7g==", + "dev": true, + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/template": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.9.tgz", + "integrity": "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.9.tgz", + "integrity": "sha512-aI3jjAAO1fh7vY/pBGsn1i9LDbRP43+asrRlkPuTXW5yHXtd1NgTEMudbBoDDxrf1daEEfPJqR+JBMakzrR4Dg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.9" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", + "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.10.tgz", + "integrity": "sha512-1mFuY2TOsR1hxbjCo4QL+qlIjV07p4H4EUYw2J/WCqsvFV6V9X9z9YhXbWndc/4fw+hYGlDT7egYxliMp5O6Ew==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead.", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-static-block": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.21.0.tgz", + "integrity": "sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-static-block instead.", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-proposal-dynamic-import": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-dynamic-import instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-export-namespace-from instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-json-strings": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-json-strings instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", + "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-logical-assignment-operators instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", + "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", + "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead.", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz", + "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-property-in-object instead.", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-unicode-property-regex instead.", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.9.tgz", + "integrity": "sha512-4GHX5uzr5QMOOuzV0an9MFju4hKlm0OyePl/lHhcsTVae5t/IKVHnb8W67Vr6FuLlk5lPqLB7n7O+K5R46emYg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", + "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", + "integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", + "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", + "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/traverse": "^7.25.9", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", + "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/template": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties/node_modules/@babel/template": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", + "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", + "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", + "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.9.tgz", + "integrity": "sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", + "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", + "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", + "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", + "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", + "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.9.tgz", + "integrity": "sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-simple-access": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", + "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", + "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", + "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", + "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", + "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", + "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", + "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", + "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.10.tgz", + "integrity": "sha512-q5mMeYAdfEbpBAgzl7tBre/la3LeCxmDO1+wMXRdPWbcoMjR3GiXlCLk7JBZVVye0bqTGNMbt0yYVXX1B1jEWQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", + "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", + "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", + "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", + "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz", + "integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", + "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", + "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.10.tgz", + "integrity": "sha512-wVxs1yjFdW3Z/XkNfXKoblxoHgbtUF7/l3PvvP4m02Qz9TZ6uZGxRVYjSQeR87oQmHco9zWitW5J82DJ7sCjvA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.18.10", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.18.9", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.18.9", + "@babel/plugin-transform-classes": "^7.18.9", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.18.9", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.18.9", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.18.6", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.8", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.18.9", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.18.10", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", + "core-js-compat": "^3.22.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6.tgz", + "integrity": "sha512-ID2yj6K/4lKfhuU3+EX4UvNbIt7eACFbHmNUjzA+ep+B5971CknnA/9DEWKbRokfbbtblxxxXFJJrH47UEAMVg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-modules/node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", + "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", + "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/template": "^7.25.9", + "@babel/types": "^7.25.9", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/generator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.9.tgz", + "integrity": "sha512-omlUGkr5EaoIJrhLf9CJ0TvjBRpd9+AXRG//0GEQ9THSo8wPiTlbpy1/Ow8ZTrbXpjd9FHXfbFQx32I04ht0FA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.9", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/template": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/types": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.9.tgz", + "integrity": "sha512-OwS2CM5KocvQ/k7dFJa8i5bNGJP0hXWfVCfDkqRFP1IreH1JDC7wG6eCYCi0+McbfT8OR/kNqsI0UU0xP9H6PQ==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@csstools/postcss-cascade-layers": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", + "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", + "dev": true, + "dependencies": { + "@csstools/selector-specificity": "^2.0.2", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-color-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz", + "integrity": "sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz", + "integrity": "sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-hwb-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz", + "integrity": "sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-ic-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz", + "integrity": "sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz", + "integrity": "sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==", + "dev": true, + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-nested-calc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-1.0.0.tgz", + "integrity": "sha512-JCsQsw1wjYwv1bJmgjKSoZNvf7R6+wuHDAbi5f/7MbFhl2d/+v+TvBTU4BJH3G1X1H87dHl0mh6TfYogbT/dJQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz", + "integrity": "sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-oklab-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz", + "integrity": "sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", + "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz", + "integrity": "sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-text-decoration-shorthand": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-1.0.0.tgz", + "integrity": "sha512-c1XwKJ2eMIWrzQenN0XbcfzckOLLJiczqy+YvfGmzoVXd7pT9FfObiSEfzs84bpE/VqfpEuAZ9tCRbZkZxxbdw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz", + "integrity": "sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-unset-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", + "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/selector-specificity": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", + "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss-selector-parser": "^6.0.10" + } + }, + "node_modules/@dagrejs/dagre": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@dagrejs/dagre/-/dagre-1.1.4.tgz", + "integrity": "sha512-QUTc54Cg/wvmlEUxB+uvoPVKFazM1H18kVHBQNmK2NbrDR5ihOCR6CXLnDSZzMcSQKJtabPUWridBOlJM3WkDg==", + "dependencies": { + "@dagrejs/graphlib": "2.2.4" + } + }, + "node_modules/@dagrejs/graphlib": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@dagrejs/graphlib/-/graphlib-2.2.4.tgz", + "integrity": "sha512-mepCf/e9+SKYy1d02/UkvSy6+6MoyXhVxP8lLDfA7BPE1X1d4dR0sZznmbM8/XVJ1GPM+Svnx7Xj6ZweByWUkw==", + "engines": { + "node": ">17.0.0" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.5.tgz", + "integrity": "sha512-UHkDFCfSGTuXq08oQltXxSZmH1TXyWsL+4QhZDWvvLl6mEJQqk3u7/wq1LjhrrAXYIllaTtRSzUXl4Olkf2J8A==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@fullhuman/postcss-purgecss": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-2.3.0.tgz", + "integrity": "sha512-qnKm5dIOyPGJ70kPZ5jiz0I9foVOic0j+cOzNDoo8KoCf6HjicIZ99UfO2OmE7vCYSKAAepEwJtNzpiiZAh9xw==", + "dev": true, + "dependencies": { + "postcss": "7.0.32", + "purgecss": "^2.3.0" + } + }, + "node_modules/@fullhuman/postcss-purgecss/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@fullhuman/postcss-purgecss/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@fullhuman/postcss-purgecss/node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@fullhuman/postcss-purgecss/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@fullhuman/postcss-purgecss/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@fullhuman/postcss-purgecss/node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@fullhuman/postcss-purgecss/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@fullhuman/postcss-purgecss/node_modules/postcss": { + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + }, + "node_modules/@fullhuman/postcss-purgecss/node_modules/purgecss": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-2.3.0.tgz", + "integrity": "sha512-BE5CROfVGsx2XIhxGuZAT7rTH9lLeQx/6M0P7DTXQH4IUc3BBzs9JUzt4yzGf3JrH9enkeq6YJBe9CTtkm1WmQ==", + "dev": true, + "dependencies": { + "commander": "^5.0.0", + "glob": "^7.0.0", + "postcss": "7.0.32", + "postcss-selector-parser": "^6.0.2" + }, + "bin": { + "purgecss": "bin/purgecss" + } + }, + "node_modules/@fullhuman/postcss-purgecss/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@fullhuman/postcss-purgecss/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fullhuman/purgecss-loader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@fullhuman/purgecss-loader/-/purgecss-loader-1.0.0.tgz", + "integrity": "sha512-n7BGzlbFFkyb9otDHaXNHUOIb8xBOYa4IDOOXUXP6SyEG+ZD/NnWjaCjm/eag5MJg/jCGtVomBBqXqpndZZCpg==", + "dev": true, + "dependencies": { + "loader-utils": "^1.1.0", + "purgecss": "^1.1.0" + } + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "dev": true, + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/purgecss": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-1.4.2.tgz", + "integrity": "sha512-hkOreFTgiyMHMmC2BxzdIw5DuC6kxAbP/gGOGd3MEsF3+5m69rIvUEPaxrnoUtfODTFKe9hcXjGwC6jcjoyhOw==", + "dev": true, + "dependencies": { + "glob": "^7.1.3", + "postcss": "^7.0.14", + "postcss-selector-parser": "^6.0.0", + "yargs": "^14.0.0" + }, + "bin": { + "purgecss": "bin/purgecss" + }, + "engines": { + "node": ">=4.4.0", + "npm": ">=5.2.0" + }, + "funding": { + "url": "https://github.com/sponsors/Ffloriel" + } + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/yargs": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz", + "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==", + "dev": true, + "dependencies": { + "cliui": "^5.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^15.0.1" + } + }, + "node_modules/@fullhuman/purgecss-loader/node_modules/yargs-parser": { + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.3.tgz", + "integrity": "sha512-/MVEVjTXy/cGAjdtQf8dW3V9b97bPN7rNn8ETj6BmAQL7ibC7O1Q9SPJbGjgh3SlwoBNXMzj/ZGIj8mBgl12YA==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true + }, + "node_modules/@iconify/icons-fa-brands": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@iconify/icons-fa-brands/-/icons-fa-brands-1.2.4.tgz", + "integrity": "sha512-MnUUfPhKJ6ECvVNxipBCmyuvJPDgRJcJ1f9nfgv0obikp6D9d6dGtMrR+bw4Gku6Gr/WCnS1e/Qd5gdmXlE84w==", + "dependencies": { + "@iconify/types": "*" + } + }, + "node_modules/@iconify/icons-fa-solid": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@iconify/icons-fa-solid/-/icons-fa-solid-1.2.4.tgz", + "integrity": "sha512-gLH+zYl/Srpnlsb++vys7WNXNGPTXjd/BaUO0Q9Z52vpZnmdiHx420TzsGSS5Pi5AR3QL1wdbkopS3EIaSdsZg==", + "dependencies": { + "@iconify/types": "*" + } + }, + "node_modules/@iconify/icons-ic": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@iconify/icons-ic/-/icons-ic-1.2.13.tgz", + "integrity": "sha512-TphrhwOvgd7CTmUhz6jgXF+SPnMtvTm03bZsAYbny2kwq4zlkhr9e16YEyPGMvKhjtTqNooA3iZ9Wa+pZ8moXQ==", + "dependencies": { + "@iconify/types": "*" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==" + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@juggle/resize-observer": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz", + "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==" + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true + }, + "node_modules/@ngtools/webpack": { + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.2.13.tgz", + "integrity": "sha512-RQx/rGX7K/+R55x1R6Ax1JzyeHi8cW11dEXpzHWipyuSpusQLUN53F02eMB4VTakXsL3mFNWWy4bX3/LSq8/9w==", + "dev": true, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^14.0.0", + "typescript": ">=4.6.2 <4.9", + "webpack": "^5.54.0" + } + }, + "node_modules/@ngx-loading-bar/core": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@ngx-loading-bar/core/-/core-6.0.2.tgz", + "integrity": "sha512-8r+OQEYXwvU+2ZXK6CY3Guh2yJuG8pQ2XNryHVbPZB2Ub3VmzhGWqjxXAQgxmsi+GxrD4m+nGmGZPeOrNH1ztA==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": ">=13.0.0", + "rxjs": "^6.5.3 || ^7.0.0" + } + }, + "node_modules/@ngx-loading-bar/router": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@ngx-loading-bar/router/-/router-6.0.2.tgz", + "integrity": "sha512-el+32ysDhqr46Zcg+H8UiKpOEz43qY0++CUxj8DADLRm3mAzKqNn/X+5qhFQS4o5Nb/SdvZn5apfFlXoNNUViQ==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/router": ">=13.0.0", + "@ngx-loading-bar/core": "6.0.2" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "dev": true, + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-3.0.2.tgz", + "integrity": "sha512-CAcd08y3DWBJqJDpfuVL0uijlq5oaXaOJEKHKc4wqrjd00gkvTZB+nFuLn+doOOKddaQS9JfqtNoFCO2LCvA3w==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^3.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^7.0.0", + "proc-log": "^2.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", + "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "dev": true, + "dependencies": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + }, + "bin": { + "installed-package-contents": "index.js" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@npmcli/move-file": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-2.0.0.tgz", + "integrity": "sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-3.0.0.tgz", + "integrity": "sha512-s9SgS+p3a9Eohe68cSI3fi+hpcZUmXq5P7w0kMlAsWVtR7XbK3ptkZqKT2cK1zLDObJ3sR+8P59sJE0w/KTL1g==", + "dev": true, + "dependencies": { + "infer-owner": "^1.0.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-4.2.1.tgz", + "integrity": "sha512-7dqywvVudPSrRCW5nTHpHgeWnbBtz8cFkOuKrecm6ih+oO9ciydhWt6OF7HlqupRRmB8Q/gECVdB9LMfToJbRg==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/promise-spawn": "^3.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^2.0.3", + "which": "^2.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.28", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", + "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", + "dev": true + }, + "node_modules/@rollup/plugin-json": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", + "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.0.8" + }, + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz", + "integrity": "sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.1.0", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "rollup": "^2.42.0" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/pluginutils/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "node_modules/@schematics/angular": { + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-14.2.13.tgz", + "integrity": "sha512-MLxTpTU3E8QACQ/5c0sENMR2gRiMXpGaKeD5IHY+3wyU2fUSJVB0QPU/l1WhoyZbX8N9ospBgf5UEG7taVF9rg==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "14.2.13", + "@angular-devkit/schematics": "14.2.13", + "jsonc-parser": "3.1.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "dev": true + }, + "node_modules/@swimlane/ngx-charts": { + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@swimlane/ngx-charts/-/ngx-charts-20.5.0.tgz", + "integrity": "sha512-PNBIHdu/R3ceD7jnw1uCBVOj4k3T6IxfdW6xsDsglGkZyoWMEEq4tLoEurjLEKzmDtRv9c35kVNOXy0lkOuXeA==", + "dependencies": { + "d3-array": "^3.1.1", + "d3-brush": "^3.0.0", + "d3-color": "^3.1.0", + "d3-ease": "^3.0.1", + "d3-format": "^3.1.0", + "d3-hierarchy": "^3.1.0", + "d3-interpolate": "^3.0.1", + "d3-sankey": "^0.12.3", + "d3-scale": "^4.0.2", + "d3-selection": "^3.0.0", + "d3-shape": "^3.2.0", + "d3-time-format": "^3.0.0", + "d3-transition": "^3.0.1", + "rfdc": "^1.3.0", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/animations": ">=12.0.0", + "@angular/cdk": ">=12.0.0", + "@angular/common": ">=12.0.0", + "@angular/core": ">=12.0.0", + "@angular/forms": ">=12.0.0", + "@angular/platform-browser": ">=12.0.0", + "@angular/platform-browser-dynamic": ">=12.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.0.tgz", + "integrity": "sha512-AbXMTZGt40T+KON9/Fdxx0B2WK5hsgxcfXJLr5bFpZ7b4JCex2WyQPTEKdXqfHiY5nKKBScZ7yCoO6Pvgxfvnw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express/node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.15", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", + "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/jasmine": { + "version": "3.6.11", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.6.11.tgz", + "integrity": "sha512-S6pvzQDvMZHrkBz2Mcn/8Du7cpr76PlRJBAoHnSDNbulULsH5dp0Gns+WRyNX5LHejz/ljxK4/vIHK/caHt6SQ==", + "dev": true + }, + "node_modules/@types/jasminewd2": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.8.tgz", + "integrity": "sha512-d9p31r7Nxk0ZH0U39PTH0hiDlJ+qNVGjlt1ucOoTUptxb2v+Y5VMnsxfwN+i3hK4yQnqBi3FMmoMFcd1JHDxdg==", + "dev": true, + "dependencies": { + "@types/jasmine": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "dev": true + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, + "node_modules/@types/pluralize": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/pluralize/-/pluralize-0.0.33.tgz", + "integrity": "sha512-JOqsl+ZoCpP4e8TDke9W79FDcSgPAR0l6pixx2JHkhnRjvShyYiAYw2LVsnA7K08Y6DeOnaU6ujmENO4os/cYg==" + }, + "node_modules/@types/q": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", + "integrity": "sha512-qYi3YV9inU/REEfxwVcGZzbS3KG/Xs90lv0Pr+lDtuVjBPGd1A+eciXzVSaRvLify132BfcvhvEjeVahrUl0Ug==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.16", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", + "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "node_modules/@types/selenium-webdriver": { + "version": "3.0.26", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.26.tgz", + "integrity": "sha512-dyIGFKXfUFiwkMfNGn1+F6b80ZjR3uSYv1j6xVJSDlft5waZ2cwkHW4e7zNzvq7hiEackcgvBpmnXZrI1GltPg==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/simplebar": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/simplebar/-/simplebar-2.4.2.tgz", + "integrity": "sha512-omSnWgcQ5hGANK8MijABHDNtj7bM2GH80g8wVqeRmaePJ2lPN4RmbrVihEbYtnovW2aS51a0joITsb6+Q1HnnA==", + "dev": true + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.12", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", + "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@visurel/iconify-angular": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@visurel/iconify-angular/-/iconify-angular-11.0.0.tgz", + "integrity": "sha512-VaF0Zg0em3an3BnylxquJQATh7/Z34KG76dd85hvWXrm/FIv6q5yB8GAndUuTwTOU3CIRswsv6Lt15pdzk//xA==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": ">=5.0.0", + "@angular/core": ">=5.0.0" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xterm/addon-fit": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.9.0.tgz", + "integrity": "sha512-hDlPPbTVPYyvwXu/asW8HbJkI/2RMi0cMaJnBZYVeJB0SWP2NeESMCNr+I7CvBlyI0sAxpxOg8Wk4OMkxBz9WA==", + "peerDependencies": { + "@xterm/xterm": "^5.0.0" + } + }, + "node_modules/@xterm/xterm": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz", + "integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==" + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ace-builds": { + "version": "1.36.3", + "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.36.3.tgz", + "integrity": "sha512-YcdwV2IIaJSfjkWAR1NEYN5IxBiXefTgwXsJ//UlaFrjXDX5hQpvPFvEePHz2ZBUfvO54RjHeRUQGX8MS5HaMQ==" + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "deprecated": "package has been renamed to acorn-import-attributes", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "dependencies": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "node_modules/acorn-node/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/adm-zip": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz", + "integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==", + "dev": true, + "engines": { + "node": ">=12.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "dev": true, + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/angular-resizable-element": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/angular-resizable-element/-/angular-resizable-element-5.0.0.tgz", + "integrity": "sha512-GbV8myA2x8aUU8CK7siTi1QMjtilzQzIgClqUVpE/YM1WAp0/OnioBV12oLcOT24eEwP3zDqPTHL+D1Kv2rNAw==", + "dependencies": { + "tslib": "^2.2.0" + }, + "peerDependencies": { + "@angular/core": ">=10.0.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/app-root-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz", + "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==", + "dev": true, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "deprecated": "This package is no longer supported.", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/aria-query": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", + "integrity": "sha512-majUxHgLehQTeSA+hClx+DY09OVUqG3GtezWkF1krgLGNdlDu9l9V8DaqNMWbq4Eddc8wsyDA0hpDUtnYxQEXw==", + "dev": true, + "dependencies": { + "ast-types-flow": "0.0.7", + "commander": "^2.11.0" + } + }, + "node_modules/aria-query/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "dev": true, + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", + "dev": true + }, + "node_modules/axobject-query": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", + "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", + "dev": true, + "dependencies": { + "ast-types-flow": "0.0.7" + } + }, + "node_modules/babel-loader": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "dev": true, + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz", + "integrity": "sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.2", + "core-js-compat": "^3.21.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true, + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/blocking-proxy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", + "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "blocking-proxy": "built/lib/bin.js" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/browserstack": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.6.1.tgz", + "integrity": "sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==", + "dev": true, + "dependencies": { + "https-proxy-agent": "^2.2.1" + } + }, + "node_modules/browserstack/node_modules/agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/browserstack/node_modules/https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "devOptional": true + }, + "node_modules/bufferutil": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", + "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/builtins": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz", + "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "16.1.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.2.tgz", + "integrity": "sha512-Xx+xPlfCZIUHagysjjOAje9nRo8pRDczQCcXb4J2O0BLtH+xeVue6ba4y1kfJfQMAnM2mkcoMIAyOctlaRGWYA==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/cacache/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001669", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz", + "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/codelyzer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-6.0.2.tgz", + "integrity": "sha512-v3+E0Ucu2xWJMOJ2fA/q9pDT/hlxHftHGPUay1/1cTgyPV5JTHFdO9hqo837Sx2s9vKBMTt5gO+lhF95PO6J+g==", + "dev": true, + "dependencies": { + "@angular/compiler": "9.0.0", + "@angular/core": "9.0.0", + "app-root-path": "^3.0.0", + "aria-query": "^3.0.0", + "axobject-query": "2.0.2", + "css-selector-tokenizer": "^0.7.1", + "cssauron": "^1.4.0", + "damerau-levenshtein": "^1.0.4", + "rxjs": "^6.5.3", + "semver-dsl": "^1.0.1", + "source-map": "^0.5.7", + "sprintf-js": "^1.1.2", + "tslib": "^1.10.0", + "zone.js": "~0.10.3" + }, + "peerDependencies": { + "@angular/compiler": ">=2.3.1 <13.0.0 || ^12.0.0-next || ^12.1.0-next || ^12.2.0-next", + "@angular/core": ">=2.3.1 <13.0.0 || ^12.0.0-next || ^12.1.0-next || ^12.2.0-next", + "tslint": "^5.0.0 || ^6.0.0" + } + }, + "node_modules/codelyzer/node_modules/@angular/compiler": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.0.0.tgz", + "integrity": "sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ==", + "dev": true, + "peerDependencies": { + "tslib": "^1.10.0" + } + }, + "node_modules/codelyzer/node_modules/@angular/core": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.0.0.tgz", + "integrity": "sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w==", + "dev": true, + "peerDependencies": { + "rxjs": "^6.5.3", + "tslib": "^1.10.0", + "zone.js": "~0.10.2" + } + }, + "node_modules/codelyzer/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/codelyzer/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true + }, + "node_modules/codelyzer/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/codelyzer/node_modules/zone.js": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz", + "integrity": "sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg==", + "dev": true + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/connect/node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/connect/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/connect/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/copy-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/copy-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/core-js-compat": { + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", + "integrity": "sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "devOptional": true + }, + "node_modules/critters": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz", + "integrity": "sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "css-select": "^4.2.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "postcss": "^8.3.7", + "pretty-bytes": "^5.3.0" + } + }, + "node_modules/critters/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-blank-pseudo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", + "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-blank-pseudo": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha512-zj5D7X1U2h2zsXOAM8EyUREBnnts6H+Jm+d1M2DbiQQcUtnqgQsMrdo8JW9R80YFUmIdBZeMu5wvYM7hcgWP/Q==", + "engines": { + "node": "*" + } + }, + "node_modules/css-has-pseudo": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", + "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-has-pseudo": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-loader": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", + "integrity": "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.7", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.5" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/css-prefers-color-scheme": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", + "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "dev": true, + "bin": { + "css-prefers-color-scheme": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-selector-tokenizer": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz", + "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "fastparse": "^1.1.2" + } + }, + "node_modules/css-unit-converter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", + "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==" + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssauron": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", + "integrity": "sha512-Ht70DcFBh+/ekjVrYS2PlDMdSQEl3OFNmjK6lcn49HptBgilXf/Zwg4uFh9Xn0pX3Q8YOkSjIFOfK2osvdqpBw==", + "dev": true, + "dependencies": { + "through": "X.X.X" + } + }, + "node_modules/cssdb": { + "version": "7.11.2", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.11.2.tgz", + "integrity": "sha512-lhQ32TFkc1X4eTefGfYPvgovRSzIMofHkigfH8nWtyRL4XJLsRhJFreRvEgKzept7x1rjBuy3J/MurXLaFxW/A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + } + ] + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cuint": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz", + "integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==", + "dev": true + }, + "node_modules/custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", + "dev": true + }, + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "optional": true, + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape/node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz", + "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==", + "dependencies": { + "d3-time": "1 - 2" + } + }, + "node_modules/d3-time-format/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-time-format/node_modules/d3-time": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz", + "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", + "dependencies": { + "d3-array": "2" + } + }, + "node_modules/d3-time-format/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/date-format": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/dayjs": { + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "dev": true + }, + "node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/defined": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", + "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha512-Z4fzpbIRjOu7lO5jCETSWoqUDVe0IPOlfugBsF6suen2LKDlVb4QZpKEM9P+buNJ4KI1eN7I083w/pbKUpsrWQ==", + "dev": true, + "dependencies": { + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha512-HJRTIH2EeH44ka+LWig+EqT2ONSYpVlNfx6pyd592/VF1TbfljJ7elwie7oSwcViLGqOdWocSdu2txwBF9bjmQ==", + "dev": true, + "dependencies": { + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dependency-graph": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "node_modules/di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", + "dev": true + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "devOptional": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", + "dev": true, + "dependencies": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ecc-jsbn/node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.5.45", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.45.tgz", + "integrity": "sha512-vOzZS6uZwhhbkZbcRyiy99Wg+pYFV5hk+5YaECvx0+Z31NR3Tt5zS6dze2OepT6PCTzVzT0dIJItti+uAW5zmw==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/engine.io": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.2.tgz", + "integrity": "sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw==", + "dev": true, + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.1.tgz", + "integrity": "sha512-QHuXVeZx9d+tIQAz/XztU0ZwZf2Agg9CcXcgE1rurqvdBeDBrpSwjl8/6XUqMg7tw2Y7uAdKb2sRv+bSEFqQ5A==", + "dev": true, + "dependencies": { + "punycode": "^1.4.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ent/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-ex/node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "optional": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "dev": true, + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "optional": true, + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/esbuild": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.5.tgz", + "integrity": "sha512-VSf6S1QVqvxfIsSKb3UKr3VhUCis7wgDbtF4Vd9z84UJr05/Sp2fRKmzC+CSPG/dNAPPJZ0BTBLTT1Fhd6N9Gg==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/linux-loong64": "0.15.5", + "esbuild-android-64": "0.15.5", + "esbuild-android-arm64": "0.15.5", + "esbuild-darwin-64": "0.15.5", + "esbuild-darwin-arm64": "0.15.5", + "esbuild-freebsd-64": "0.15.5", + "esbuild-freebsd-arm64": "0.15.5", + "esbuild-linux-32": "0.15.5", + "esbuild-linux-64": "0.15.5", + "esbuild-linux-arm": "0.15.5", + "esbuild-linux-arm64": "0.15.5", + "esbuild-linux-mips64le": "0.15.5", + "esbuild-linux-ppc64le": "0.15.5", + "esbuild-linux-riscv64": "0.15.5", + "esbuild-linux-s390x": "0.15.5", + "esbuild-netbsd-64": "0.15.5", + "esbuild-openbsd-64": "0.15.5", + "esbuild-sunos-64": "0.15.5", + "esbuild-windows-32": "0.15.5", + "esbuild-windows-64": "0.15.5", + "esbuild-windows-arm64": "0.15.5" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.5.tgz", + "integrity": "sha512-dYPPkiGNskvZqmIK29OPxolyY3tp+c47+Fsc2WYSOVjEPWNCHNyqhtFqQadcXMJDQt8eN0NMDukbyQgFcHquXg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.5.tgz", + "integrity": "sha512-YyEkaQl08ze3cBzI/4Cm1S+rVh8HMOpCdq8B78JLbNFHhzi4NixVN93xDrHZLztlocEYqi45rHHCgA8kZFidFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.5.tgz", + "integrity": "sha512-Cr0iIqnWKx3ZTvDUAzG0H/u9dWjLE4c2gTtRLz4pqOBGjfjqdcZSfAObFzKTInLLSmD0ZV1I/mshhPoYSBMMCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.5.tgz", + "integrity": "sha512-WIfQkocGtFrz7vCu44ypY5YmiFXpsxvz2xqwe688jFfSVCnUsCn2qkEVDo7gT8EpsLOz1J/OmqjExePL1dr1Kg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.5.tgz", + "integrity": "sha512-M5/EfzV2RsMd/wqwR18CELcenZ8+fFxQAAEO7TJKDmP3knhWSbD72ILzrXFMMwshlPAS1ShCZ90jsxkm+8FlaA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.5.tgz", + "integrity": "sha512-2JQQ5Qs9J0440F/n/aUBNvY6lTo4XP/4lt1TwDfHuo0DY3w5++anw+jTjfouLzbJmFFiwmX7SmUhMnysocx96w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.5.tgz", + "integrity": "sha512-gO9vNnIN0FTUGjvTFucIXtBSr1Woymmx/aHQtuU+2OllGU6YFLs99960UD4Dib1kFovVgs59MTXwpFdVoSMZoQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.5.tgz", + "integrity": "sha512-ne0GFdNLsm4veXbTnYAWjbx3shpNKZJUd6XpNbKNUZaNllDZfYQt0/zRqOg0sc7O8GQ+PjSMv9IpIEULXVTVmg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.5.tgz", + "integrity": "sha512-wvAoHEN+gJ/22gnvhZnS/+2H14HyAxM07m59RSLn3iXrQsdS518jnEWRBnJz3fR6BJa+VUTo0NxYjGaNt7RA7Q==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.5.tgz", + "integrity": "sha512-7EgFyP2zjO065XTfdCxiXVEk+f83RQ1JsryN1X/VSX2li9rnHAt2swRbpoz5Vlrl6qjHrCmq5b6yxD13z6RheA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.5.tgz", + "integrity": "sha512-KdnSkHxWrJ6Y40ABu+ipTZeRhFtc8dowGyFsZY5prsmMSr1ZTG9zQawguN4/tunJ0wy3+kD54GaGwdcpwWAvZQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.5.tgz", + "integrity": "sha512-QdRHGeZ2ykl5P0KRmfGBZIHmqcwIsUKWmmpZTOq573jRWwmpfRmS7xOhmDHBj9pxv+6qRMH8tLr2fe+ZKQvCYw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.5.tgz", + "integrity": "sha512-p+WE6RX+jNILsf+exR29DwgV6B73khEQV0qWUbzxaycxawZ8NE0wA6HnnTxbiw5f4Gx9sJDUBemh9v49lKOORA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.5.tgz", + "integrity": "sha512-J2ngOB4cNzmqLHh6TYMM/ips8aoZIuzxJnDdWutBw5482jGXiOzsPoEF4j2WJ2mGnm7FBCO4StGcwzOgic70JQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.5.tgz", + "integrity": "sha512-MmKUYGDizYjFia0Rwt8oOgmiFH7zaYlsoQ3tIOfPxOqLssAsEgG0MUdRDm5lliqjiuoog8LyDu9srQk5YwWF3w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.5.tgz", + "integrity": "sha512-2mMFfkLk3oPWfopA9Plj4hyhqHNuGyp5KQyTT9Rc8hFd8wAn5ZrbJg+gNcLMo2yzf8Uiu0RT6G9B15YN9WQyMA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.5.tgz", + "integrity": "sha512-2sIzhMUfLNoD+rdmV6AacilCHSxZIoGAU2oT7XmJ0lXcZWnCvCtObvO6D4puxX9YRE97GodciRGDLBaiC6x1SA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.5.tgz", + "integrity": "sha512-e+duNED9UBop7Vnlap6XKedA/53lIi12xv2ebeNS4gFmu7aKyTrok7DPIZyU5w/ftHD4MUDs5PJUkQPP9xJRzg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.5.tgz", + "integrity": "sha512-v+PjvNtSASHOjPDMIai9Yi+aP+Vwox+3WVdg2JB8N9aivJ7lyhp4NVU+J0MV2OkWFPnVO8AE/7xH+72ibUUEnw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.5.tgz", + "integrity": "sha512-Yz8w/D8CUPYstvVQujByu6mlf48lKmXkq6bkeSZZxTA626efQOJb26aDGLzmFWx6eg/FwrXgt6SZs9V8Pwy/aA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "optional": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "optional": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/eventemitter-asyncresource": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", + "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", + "dev": true + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/eventsource": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.2.tgz", + "integrity": "sha512-xAH3zWhgO2/3KIniEKYPr8plNSzlGINOUqYj0m0u7AB81iRw8b/3E73W6AuU+6klLbaSFmZnaETQ2lXPfAydrA==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, + "node_modules/express": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.10", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "optional": true, + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/external-editor/node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ] + }, + "node_modules/fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "deprecated": "This package is no longer supported.", + "dev": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dev": true, + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dev": true, + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hdr-histogram-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", + "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", + "dev": true, + "dependencies": { + "@assemblyscript/loader": "^0.10.1", + "base64-js": "^1.2.0", + "pako": "^1.0.3" + } + }, + "node_modules/hdr-histogram-percentiles-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", + "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", + "dev": true + }, + "node_modules/hex-color-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" + }, + "node_modules/hosted-git-info": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/hsl-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", + "integrity": "sha512-M5ezZw4LzXbBKMruP+BNANf0k+19hDQMgpzBIYnya//Al+fjNct9Wf3b1WedLqdEs2hKBvxq/jh+DsHJLj0F9A==" + }, + "node_modules/hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "integrity": "sha512-7Wn5GMLuHBjZCb2bTmnDOycho0p/7UVaAeqXZGbHrBCl6Yd/xDhQJAXe6Ga9AXJH2I5zY1dEdYw2u1UptnSBJA==" + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-5.0.1.tgz", + "integrity": "sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==", + "dev": true, + "dependencies": { + "minimatch": "^5.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ignore-walk/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true + }, + "node_modules/immutable": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", + "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.0.tgz", + "integrity": "sha512-TxYQaeNW/N8ymDvwAxPyRbhMBtnEwuvaTYpOQkFx1nSeusgezHniEc/l35Vo4iCq/mMiTJbpD7oYxN98hFlfmw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/injection-js": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/injection-js/-/injection-js-2.4.0.tgz", + "integrity": "sha512-6jiJt0tCAo9zjHbcwLiPL+IuNe9SQ6a9g0PEzafThW3fOQi0mrmiJGBJvDD6tmhPh8cQHIQtCOrJuBfQME4kPA==", + "dev": true, + "dependencies": { + "tslib": "^2.0.0" + } + }, + "node_modules/inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-color-stop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", + "integrity": "sha512-H1U8Vz0cfXNujrJzEcvvwMDW9Ra+biSYA3ThdQvAnMLJkEHQXn6bWzLkxHtVYJ+Sdbx0b6finn3jZiaVe7MAHA==", + "dependencies": { + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" + } + }, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha512-cnS56eR9SPAscL77ik76ATVqoPARTqPIVkMDVxRaWH06zT+6+CzIroYRJ0VVvm0Z1zfAvxvz9i/D3Ppjaqt5Nw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "dev": true, + "dependencies": { + "is-path-inside": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha512-qhsCR/Esx4U4hg/9I19OVUAJkGWtjRYHMRgUMZE2TDdj+Ag+kttZanLupfddNyglzz50cUlmWzUaI37GDfNx/g==", + "dev": true, + "dependencies": { + "path-is-inside": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "devOptional": true + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true, + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jasmine": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", + "integrity": "sha512-KbdGQTf5jbZgltoHs31XGiChAPumMSY64OZMWLNYnEnMfG5uwGBhffePwuskexjT+/Jea/gU3qAU8344hNohSw==", + "dev": true, + "dependencies": { + "exit": "^0.1.2", + "glob": "^7.0.6", + "jasmine-core": "~2.8.0" + }, + "bin": { + "jasmine": "bin/jasmine.js" + } + }, + "node_modules/jasmine-core": { + "version": "3.99.1", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.99.1.tgz", + "integrity": "sha512-Hu1dmuoGcZ7AfyynN3LsfruwMbxMALMka+YtZeGoLuDEySVmVAPaonkNoBRIw/ectu8b9tVQCJNgp4a4knp+tg==", + "dev": true + }, + "node_modules/jasmine-spec-reporter": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-5.0.2.tgz", + "integrity": "sha512-6gP1LbVgJ+d7PKksQBc2H0oDGNRQI3gKUsWlswKaQ2fif9X5gzhQcgM5+kiJGCQVurOG09jqNhk7payggyp5+g==", + "dev": true, + "dependencies": { + "colors": "1.4.0" + } + }, + "node_modules/jasmine/node_modules/jasmine-core": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", + "integrity": "sha512-SNkOkS+/jMZvLhuSx1fjhcNWUC/KG6oVyFUGkSBEr9n1axSNduWU8GlI7suaHXr4yxjet6KjrUZxUTE5WzzWwQ==", + "dev": true + }, + "node_modules/jasminewd2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", + "integrity": "sha512-Rn0nZe4rfDhzA63Al3ZGh0E+JTmM6ESZYXJGKuqKGZObsAB9fwXPD03GjtIEvJBDOhN94T5MzbwZSqzFHSQPzg==", + "dev": true, + "engines": { + "node": ">= 6.9.x" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "node_modules/json2yaml": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/json2yaml/-/json2yaml-1.1.0.tgz", + "integrity": "sha512-/xse+m0SlllfZahQrNOelmLrFNfeZv4QG0QKlvg7VsPSGIxpB3X+ggLkdffwmI1DdQ3o9XjZX+K+EOI1epdKgg==", + "dependencies": { + "remedial": "1.x" + }, + "bin": { + "json2yaml": "cli.js", + "json2yml": "cli.js", + "jsontoyaml": "cli.js", + "jsontoyml": "cli.js" + }, + "engines": { + "node": ">= 0.2.0" + } + }, + "node_modules/json3": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", + "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.1.0.tgz", + "integrity": "sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dev": true, + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, + "node_modules/karma": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.4.tgz", + "integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==", + "dev": true, + "dependencies": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.7.2", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "bin": { + "karma": "bin/karma" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/karma-chrome-launcher": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz", + "integrity": "sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ==", + "dev": true, + "dependencies": { + "which": "^1.2.1" + } + }, + "node_modules/karma-chrome-launcher/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/karma-coverage-istanbul-reporter": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-3.0.3.tgz", + "integrity": "sha512-wE4VFhG/QZv2Y4CdAYWDbMmcAHeS926ZIji4z+FkB2aF/EposRb6DP6G5ncT/wXhqUfAb/d7kZrNKPonbvsATw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^3.0.6", + "istanbul-reports": "^3.0.2", + "minimatch": "^3.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/mattlewis92" + } + }, + "node_modules/karma-jasmine": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-4.0.2.tgz", + "integrity": "sha512-ggi84RMNQffSDmWSyyt4zxzh2CQGwsxvYYsprgyR1j8ikzIduEdOlcLvXjZGwXG/0j41KUXOWsUCBfbEHPWP9g==", + "dev": true, + "dependencies": { + "jasmine-core": "^3.6.0" + }, + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "karma": "*" + } + }, + "node_modules/karma-jasmine-html-reporter": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.7.0.tgz", + "integrity": "sha512-pzum1TL7j90DTE86eFt48/s12hqwQuiD+e5aXx2Dc9wDEn2LfGq6RoAxEZZjFiN0RDSCOnosEKRZWxbQ+iMpQQ==", + "dev": true, + "peerDependencies": { + "jasmine-core": ">=3.8", + "karma": ">=0.9", + "karma-jasmine": ">=1.1" + } + }, + "node_modules/karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "dependencies": { + "source-map-support": "^0.5.5" + } + }, + "node_modules/karma/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/karma/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/karma/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/karma/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/karma/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/less": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", + "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", + "dev": true, + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/less-loader": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.0.0.tgz", + "integrity": "sha512-9+LOWWjuoectIEx3zrfN83NAGxSUB5pWEabbbidVQVgZhN+wN68pOvuyirVlH1IK4VT1f3TmlyvAnCXh8O5KEw==", + "dev": true, + "dependencies": { + "klona": "^2.0.4" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "less": "^3.5.0 || ^4.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/less/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/less/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/license-webpack-plugin": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", + "dev": true, + "dependencies": { + "webpack-sources": "^3.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-sources": { + "optional": true + } + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.topath": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/lodash.topath/-/lodash.topath-4.5.2.tgz", + "integrity": "sha512-1/W4dM+35DwvE/iEd1M9ekewOSTlpFekhw9mhAtrwjVqUr83/ilQiyAvmg4tVX7Unkcfl1KC+i9WdaT4B6aQcg==" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log4js": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", + "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", + "dev": true, + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.5" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/log4js/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.26.2", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.2.tgz", + "integrity": "sha512-NzzlXpclt5zAbmo6h6jNc8zl2gNRGHvmsZW4IvZhTC4W7k4OlLP+S5YLussa/r3ixNT66KOQfNORlXHSOy/X4A==", + "dev": true, + "dependencies": { + "sourcemap-codec": "^1.4.8" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "devOptional": true + }, + "node_modules/make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz", + "integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-json-stream": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.2.tgz", + "integrity": "sha512-myxeeTm57lYs8pH2nxPzmEEg8DGIgW+9mv6D4JZD2pa81I/OBjeU7PtICXV6c9eRGTA5JMDsuIPUZRCyBMYNhg==", + "dev": true, + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/modern-normalize": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/modern-normalize/-/modern-normalize-1.1.0.tgz", + "integrity": "sha512-2lMlY1Yc1+CUy0gw4H95uNN7vjbpoED7NNRSBHE25nWfLBdmMzFCsPshlzbxHz+gYMcBEUN8V4pU16prcdPSgA==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/needle": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/net": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/net/-/net-1.0.2.tgz", + "integrity": "sha512-kbhcj2SVVR4caaVnGLJKmlk2+f+oLkjqdKeQlmUtz6nGzOpbcobwVIeSURNgraV/v3tlmGIX82OcPCl0K6RbHQ==" + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "optional": true + }, + "node_modules/ng-packagr": { + "version": "14.2.2", + "resolved": "https://registry.npmjs.org/ng-packagr/-/ng-packagr-14.2.2.tgz", + "integrity": "sha512-AqwHcMM6x+JkCHT++IsbulnTdyoXcC2Cr4tbPamuieacc77+fFbB195hdcqEFwsKX5410cymx/ZUyHird9rxlg==", + "dev": true, + "dependencies": { + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-node-resolve": "^13.1.3", + "ajv": "^8.10.0", + "ansi-colors": "^4.1.1", + "browserslist": "^4.20.0", + "cacache": "^16.0.0", + "chokidar": "^3.5.3", + "commander": "^9.0.0", + "dependency-graph": "^0.11.0", + "esbuild-wasm": "^0.15.0", + "find-cache-dir": "^3.3.2", + "glob": "^8.0.0", + "injection-js": "^2.4.0", + "jsonc-parser": "^3.0.0", + "less": "^4.1.2", + "ora": "^5.1.0", + "postcss": "^8.4.8", + "postcss-preset-env": "^7.4.2", + "postcss-url": "^10.1.3", + "rollup": "^2.70.0", + "rollup-plugin-sourcemaps": "^0.6.3", + "rxjs": "^7.5.5", + "sass": "^1.49.9", + "stylus": "^0.59.0" + }, + "bin": { + "ng-packagr": "cli/main.js" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "optionalDependencies": { + "esbuild": "^0.15.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^14.0.0 || ^14.0.0-next || ^14.2.0-next", + "tslib": "^2.3.0", + "typescript": ">=4.6.2 <4.9" + } + }, + "node_modules/ng-packagr/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ng-packagr/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ng-packagr/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/ng-packagr/node_modules/esbuild-wasm": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.15.18.tgz", + "integrity": "sha512-Bw80Siy8XJi6UIR9f0T5SkMIkiVgvFZgHaOZAQCDcZct6Lj5kBZtpACpDhqfdTUzoDyk7pBn4xEft/T5+0tlXw==", + "dev": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/ng-packagr/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ng-packagr/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ng-packagr/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ng-packagr/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/ng-pick-datetime-ex": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/ng-pick-datetime-ex/-/ng-pick-datetime-ex-14.0.0.tgz", + "integrity": "sha512-xH4WrxlAFyZJEnMKHtu2BO03yhTKXcX4G2h+cUmsSMczyTKwNF5IBjOPniuqnyUf/hZeepbj/6k35rtctTi1hg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/cdk": "^14.0.5", + "@angular/common": "^14.0.6", + "@angular/core": "^14.0.6" + } + }, + "node_modules/ng-terminal": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ng-terminal/-/ng-terminal-6.2.0.tgz", + "integrity": "sha512-0re4RPz4CJMAwliuvhOd2X5vqgTXllqdHcyVrWhTabGg4E9vscU8J/oWz8FsXD3D5WCdNvAU/XYF2SgGZon49g==", + "dependencies": { + "@juggle/resize-observer": "^3.4.0", + "@xterm/addon-fit": "^0.9.0", + "@xterm/xterm": "^5.5.0", + "angular-resizable-element": "^5.0.0", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^18.0.0 || ^17.0.0 || ^16.0.0", + "@angular/core": "^18.0.0 || ^17.0.0 || ^16.0.0" + } + }, + "node_modules/ng2-search-filter": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/ng2-search-filter/-/ng2-search-filter-0.5.1.tgz", + "integrity": "sha512-noN8R+Gyxo5ZuboEOvq+u0zKio6pEf1IVYQTCZfAfXm6ONmzWu/M2xK0di9oVUprDbPBQXCGUuvD5i2GD+35HA==" + }, + "node_modules/ngx-webstorage": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ngx-webstorage/-/ngx-webstorage-10.0.1.tgz", + "integrity": "sha512-OWmzAzby+/UrbRY/5d229Y4NzFn1a/u2WSEeZqzY5lwB/3d8ODZ6mlW/BZGIuuZ48Hp8tXMM3pFCz9+pEyzvDA==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": "^14.0.0", + "@angular/core": "^14.0.0" + } + }, + "node_modules/nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "!win32" + ], + "dependencies": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node_modules/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true, + "optional": true + }, + "node_modules/node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-gyp": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz", + "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.13 || ^14.13 || >=16" + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.2.tgz", + "integrity": "sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==", + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" + }, + "node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-4.0.1.tgz", + "integrity": "sha512-EBk5QKKuocMJhB3BILuKhmaPjI8vNRSpIfO9woLC6NyHVkKKdVEdAO1mrT0ZfxNR1lKwCcTkuZfmGIFdizZ8Pg==", + "dev": true, + "dependencies": { + "hosted-git-info": "^5.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize.css": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz", + "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==" + }, + "node_modules/npm-bundled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm-install-checks": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-5.0.0.tgz", + "integrity": "sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "node_modules/npm-package-arg": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.0.tgz", + "integrity": "sha512-4J0GL+u2Nh6OnhvUKXRr2ZMG4lR8qtLp+kv7UiV00Y+nGiSxtttCyIRHCt5L5BNkXQld/RceYItau3MDOoGiBw==", + "dev": true, + "dependencies": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-packlist": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-5.1.3.tgz", + "integrity": "sha512-263/0NGrn32YFYi4J533qzrQ/krmmrWwhKkzwTuM4f/07ug51odoaNjUexxO4vxlzURHcmYMH1QjvHjsNDKLVg==", + "dev": true, + "dependencies": { + "glob": "^8.0.1", + "ignore-walk": "^5.0.1", + "npm-bundled": "^2.0.0", + "npm-normalize-package-bin": "^2.0.0" + }, + "bin": { + "npm-packlist": "bin/index.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-packlist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/npm-packlist/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm-packlist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-packlist/node_modules/npm-bundled": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-2.0.1.tgz", + "integrity": "sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-packlist/node_modules/npm-normalize-package-bin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-7.0.1.tgz", + "integrity": "sha512-IA8+tuv8KujbsbLQvselW2XQgmXWS47t3CB0ZrzsRZ82DbDfkcFunOaPm4X7qNuhMfq+FmV7hQT4iFVpHqV7mg==", + "dev": true, + "dependencies": { + "npm-install-checks": "^5.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-13.3.1.tgz", + "integrity": "sha512-eukJPi++DKRTjSBRcDZSDDsGqRK3ehbxfFUcgaRd0Yp6kRwOwh2WVn0r+8rMB4nnuzvAk6rQVzl6K5CkYOmnvw==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "deprecated": "This package is no longer supported.", + "dev": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==", + "dev": true + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", + "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dev": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pacote": { + "version": "13.6.2", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-13.6.2.tgz", + "integrity": "sha512-Gu8fU3GsvOPkak2CkbojR7vjs3k3P9cA6uazKTHdsdV0gpCEQq2opelnEv30KRQWgVzP5Vd/5umjcedma3MKtg==", + "dev": true, + "dependencies": { + "@npmcli/git": "^3.0.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/promise-spawn": "^3.0.0", + "@npmcli/run-script": "^4.1.0", + "cacache": "^16.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.6", + "mkdirp": "^1.0.4", + "npm-package-arg": "^9.0.0", + "npm-packlist": "^5.1.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.1", + "proc-log": "^2.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "optional": true + }, + "node_modules/parse5-html-rewriting-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-6.0.1.tgz", + "integrity": "sha512-vwLQzynJVEfUlURxgnf51yAJDQTtVpNyGD8tKi2Za7m+akukNHxCcUQMAa/mUGLhCeicFdpy7Tlvj8ZNKadprg==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1", + "parse5-sax-parser": "^6.0.1" + } + }, + "node_modules/parse5-html-rewriting-stream/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "node_modules/parse5-sax-parser": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-6.0.1.tgz", + "integrity": "sha512-kXX+5S81lgESA0LsDuGjAlBybImAChYRMT+/uKCEXFBFOeEhS52qUCydGhU3qLRD8D9DVjaUo821WK7DM4iCeg==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-sax-parser/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "dev": true + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/piscina": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", + "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", + "dev": true, + "dependencies": { + "eventemitter-asyncresource": "^1.0.0", + "hdr-histogram-js": "^2.0.1", + "hdr-histogram-percentiles-obj": "^3.0.0" + }, + "optionalDependencies": { + "nice-napi": "^1.0.2" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss": { + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-attribute-case-insensitive": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", + "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-clamp": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", + "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=7.6.0" + }, + "peerDependencies": { + "postcss": "^8.4.6" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", + "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-color-hex-alpha": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", + "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-rebeccapurple": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", + "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-custom-media": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", + "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/postcss-custom-properties": { + "version": "12.1.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz", + "integrity": "sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-custom-selectors": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", + "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/postcss-dir-pseudo-class": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", + "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-double-position-gradients": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", + "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-env-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", + "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", + "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-within": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", + "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-font-variant": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "dev": true, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-functions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-functions/-/postcss-functions-3.0.0.tgz", + "integrity": "sha512-N5yWXWKA+uhpLQ9ZhBRl2bIAdM6oVJYpDojuI1nF2SzXBimJcdjFwiAouBVbO5VuOF3qA6BSFWFc3wXbbj72XQ==", + "dev": true, + "dependencies": { + "glob": "^7.1.2", + "object-assign": "^4.1.1", + "postcss": "^6.0.9", + "postcss-value-parser": "^3.3.0" + } + }, + "node_modules/postcss-functions/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-functions/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-functions/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/postcss-functions/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/postcss-functions/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-functions/node_modules/postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "dependencies": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/postcss-functions/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-functions/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss-functions/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-gap-properties": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", + "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-image-set-function": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", + "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-initial": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", + "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "dev": true, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-3.0.3.tgz", + "integrity": "sha512-gWnoWQXKFw65Hk/mi2+WTQTHdPD5UJdDXZmX073EY/B3BWnYjO4F4t0VneTCnCGQ5E5GsCdMkzPaTXwl3r5dJw==", + "dependencies": { + "camelcase-css": "^2.0.1", + "postcss": "^8.1.6" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-lab-function": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", + "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-load-config": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", + "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^1.10.2" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-loader": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-4.3.0.tgz", + "integrity": "sha512-M/dSoIiNDOo8Rk0mUqoj4kpGq91gcxCfb9PoyZVdZ76/AuhxylHDYZblNE8o+EQ9AMSASeMFEKxZf5aU6wlx1Q==", + "dev": true, + "dependencies": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.4", + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0", + "semver": "^7.3.4" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/postcss-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/postcss-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/postcss-logical": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", + "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-media-minmax": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", + "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", + "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-nested": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz", + "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==", + "dependencies": { + "postcss-selector-parser": "^6.0.6" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-nesting": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", + "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", + "dev": true, + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-opacity-percentage": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.3.tgz", + "integrity": "sha512-An6Ba4pHBiDtyVpSLymUUERMo2cU7s+Obz6BTrS+gxkbnSBNKSuD0AVUc+CpBMrpVPKKfoVz0WQCX+Tnst0i4A==", + "dev": true, + "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/mrcgrtz" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mrcgrtz" + } + ], + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-overflow-shorthand": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", + "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "dev": true, + "peerDependencies": { + "postcss": "^8" + } + }, + "node_modules/postcss-place": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", + "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-preset-env": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.0.tgz", + "integrity": "sha512-leqiqLOellpLKfbHkD06E04P6d9ZQ24mat6hu4NSqun7WG0UhspHR5Myiv/510qouCjoo4+YJtNOqg5xHaFnCA==", + "dev": true, + "dependencies": { + "@csstools/postcss-cascade-layers": "^1.0.5", + "@csstools/postcss-color-function": "^1.1.1", + "@csstools/postcss-font-format-keywords": "^1.0.1", + "@csstools/postcss-hwb-function": "^1.0.2", + "@csstools/postcss-ic-unit": "^1.0.1", + "@csstools/postcss-is-pseudo-class": "^2.0.7", + "@csstools/postcss-nested-calc": "^1.0.0", + "@csstools/postcss-normalize-display-values": "^1.0.1", + "@csstools/postcss-oklab-function": "^1.1.1", + "@csstools/postcss-progressive-custom-properties": "^1.3.0", + "@csstools/postcss-stepped-value-functions": "^1.0.1", + "@csstools/postcss-text-decoration-shorthand": "^1.0.0", + "@csstools/postcss-trigonometric-functions": "^1.0.2", + "@csstools/postcss-unset-value": "^1.0.2", + "autoprefixer": "^10.4.8", + "browserslist": "^4.21.3", + "css-blank-pseudo": "^3.0.3", + "css-has-pseudo": "^3.0.4", + "css-prefers-color-scheme": "^6.0.3", + "cssdb": "^7.0.0", + "postcss-attribute-case-insensitive": "^5.0.2", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^4.2.4", + "postcss-color-hex-alpha": "^8.0.4", + "postcss-color-rebeccapurple": "^7.1.1", + "postcss-custom-media": "^8.0.2", + "postcss-custom-properties": "^12.1.8", + "postcss-custom-selectors": "^6.0.3", + "postcss-dir-pseudo-class": "^6.0.5", + "postcss-double-position-gradients": "^3.1.2", + "postcss-env-function": "^4.0.6", + "postcss-focus-visible": "^6.0.4", + "postcss-focus-within": "^5.0.4", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^3.0.5", + "postcss-image-set-function": "^4.0.7", + "postcss-initial": "^4.0.1", + "postcss-lab-function": "^4.2.1", + "postcss-logical": "^5.0.4", + "postcss-media-minmax": "^5.0.0", + "postcss-nesting": "^10.1.10", + "postcss-opacity-percentage": "^1.1.2", + "postcss-overflow-shorthand": "^3.0.4", + "postcss-page-break": "^3.0.4", + "postcss-place": "^7.0.5", + "postcss-pseudo-class-any-link": "^7.1.6", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", + "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "dev": true, + "peerDependencies": { + "postcss": "^8.0.3" + } + }, + "node_modules/postcss-scss": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-3.0.5.tgz", + "integrity": "sha512-3e0qYk87eczfzg5P73ZVuuxEGCBfatRhPze6KrSaIbEKVtmnFI1RYp1Fv+AyZi+w8kcNRSPeNX6ap4b65zEkiA==", + "dev": true, + "dependencies": { + "postcss": "^8.2.7" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-selector-not": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz", + "integrity": "sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-url": { + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/postcss-url/-/postcss-url-10.1.3.tgz", + "integrity": "sha512-FUzyxfI5l2tKmXdYc6VTu3TWZsInayEKPbiyW+P6vmmIrrb4I6CGX0BFoewgYHLK+oIL5FECEK02REYRpBvUCw==", + "dev": true, + "dependencies": { + "make-dir": "~3.1.0", + "mime": "~2.5.2", + "minimatch": "~3.0.4", + "xxhashjs": "~0.2.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-url/node_modules/mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/postcss-url/node_modules/minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/prettier": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", + "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/proc-log": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/promise-retry/node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/protractor": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-7.0.0.tgz", + "integrity": "sha512-UqkFjivi4GcvUQYzqGYNe0mLzfn5jiLmO8w9nMhQoJRLhy2grJonpga2IWhI6yJO30LibWXJJtA4MOIZD2GgZw==", + "deprecated": "We have news to share - Protractor is deprecated and will reach end-of-life by Summer 2023. To learn more and find out about other options please refer to this post on the Angular blog. Thank you for using and contributing to Protractor. https://goo.gle/state-of-e2e-in-angular", + "dev": true, + "dependencies": { + "@types/q": "^0.0.32", + "@types/selenium-webdriver": "^3.0.0", + "blocking-proxy": "^1.0.0", + "browserstack": "^1.5.1", + "chalk": "^1.1.3", + "glob": "^7.0.3", + "jasmine": "2.8.0", + "jasminewd2": "^2.1.0", + "q": "1.4.1", + "saucelabs": "^1.5.0", + "selenium-webdriver": "3.6.0", + "source-map-support": "~0.4.0", + "webdriver-js-extender": "2.1.0", + "webdriver-manager": "^12.1.7", + "yargs": "^15.3.1" + }, + "bin": { + "protractor": "bin/protractor", + "webdriver-manager": "bin/webdriver-manager" + }, + "engines": { + "node": ">=10.13.x" + } + }, + "node_modules/protractor/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/protractor/node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/protractor/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/protractor/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/protractor/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "dependencies": { + "source-map": "^0.5.6" + } + }, + "node_modules/protractor/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/protractor/node_modules/webdriver-manager": { + "version": "12.1.9", + "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.9.tgz", + "integrity": "sha512-Yl113uKm8z4m/KMUVWHq1Sjtla2uxEBtx2Ue3AmIlnlPAKloDn/Lvmy6pqWCUersVISpdMeVpAaGbNnvMuT2LQ==", + "dev": true, + "dependencies": { + "adm-zip": "^0.5.2", + "chalk": "^1.1.1", + "del": "^2.2.0", + "glob": "^7.0.3", + "ini": "^1.3.4", + "minimist": "^1.2.0", + "q": "^1.4.1", + "request": "^2.87.0", + "rimraf": "^2.5.2", + "semver": "^5.3.0", + "xml2js": "^0.4.17" + }, + "bin": { + "webdriver-manager": "bin/webdriver-manager" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/protractor/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/protractor/node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/protractor/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "optional": true + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/purgecss": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-4.1.3.tgz", + "integrity": "sha512-99cKy4s+VZoXnPxaoM23e5ABcP851nC2y2GROkkjS8eJaJtlciGavd7iYAw2V84WeBqggZ12l8ef44G99HmTaw==", + "dependencies": { + "commander": "^8.0.0", + "glob": "^7.1.7", + "postcss": "^8.3.5", + "postcss-selector-parser": "^6.0.6" + }, + "bin": { + "purgecss": "bin/purgecss.js" + } + }, + "node_modules/q": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha512-/CdEdaw49VZVmyIDGUQKDDT53c7qBkO6g5CefWz91Ae+l4+cRtcDYwMTXh6me4O8TMldeGHG3N2Bl84V78Ywbg==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", + "dev": true, + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true, + "engines": { + "node": ">=0.9" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/read-cache/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-package-json": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-5.0.2.tgz", + "integrity": "sha512-BSzugrt4kQ/Z0krro8zhTwV1Kd79ue25IhNN/VtHFy1mG/6Tluyi+msc0UpwaoQzxSHa28mntAjIZY6kEgfR9Q==", + "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", + "dev": true, + "dependencies": { + "glob": "^8.0.1", + "json-parse-even-better-errors": "^2.3.1", + "normalize-package-data": "^4.0.0", + "npm-normalize-package-bin": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", + "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/read-package-json/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/read-package-json/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/read-package-json/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/read-package-json/node_modules/npm-normalize-package-bin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reduce-css-calc": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz", + "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==", + "dependencies": { + "css-unit-converter": "^1.1.1", + "postcss-value-parser": "^3.3.0" + } + }, + "node_modules/reduce-css-calc/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "node_modules/reflect-metadata": { + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", + "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==", + "dev": true + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.3.0.tgz", + "integrity": "sha512-TVILVSz2jY5D47F4mA4MppkBrafEaiUWJO/TcZHEIuI13AqoZMkK1WMA4Om1YkYbTx+9Ki1/tSUXbceyr9saRg==", + "dev": true + }, + "node_modules/regexpu-core": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.1.1.tgz", + "integrity": "sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.11.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true + }, + "node_modules/regjsparser": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.11.1.tgz", + "integrity": "sha512-1DHODs4B8p/mQHU9kr+jv8+wIC9mtG4eBHxWxIq5mhjE3D5oORhCc6deRKzTjs9DcfRFmj9BHSDguZklqCGFWQ==", + "dev": true, + "dependencies": { + "jsesc": "~3.0.2" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/remedial": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/remedial/-/remedial-1.0.8.tgz", + "integrity": "sha512-/62tYiOe6DzS5BqVsNpH/nkGlX45C/Sp6V+NtiN6JQNS1Viay7cWkazmRkrQrdFj2eshDe96SIQNIoMxqhzBOg==", + "engines": { + "node": "*" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "dev": true, + "dependencies": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/resolve-url-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/resolve-url-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==" + }, + "node_modules/rgb-regex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", + "integrity": "sha512-gDK5mkALDFER2YLqH6imYvK6g02gpNGM4ILDZ472EwWfXZnC2ZEpoB2ECXTyOVUKuk/bPJZMzwQPBYICzP+D3w==" + }, + "node_modules/rgba-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", + "integrity": "sha512-zgn5OjNQXLUTdq8m17KdaicF6w89TZs8ZU8y0AYENIU6wG8GG6LLm0yLSiPY8DmaYmHdgRW8rnApjoT0fQRfMg==" + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "2.79.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", + "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-sourcemaps": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/rollup-plugin-sourcemaps/-/rollup-plugin-sourcemaps-0.6.3.tgz", + "integrity": "sha512-paFu+nT1xvuO1tPFYXGe+XnQvg4Hjqv/eIhG8i5EspfYYPBKL57X7iVbfv55aNVASg3dzWvES9dmWsL2KhfByw==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.0.9", + "source-map-resolve": "^0.6.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "@types/node": ">=10.0.0", + "rollup": ">=0.31.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/rxjs/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/sass": { + "version": "1.54.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.54.4.tgz", + "integrity": "sha512-3tmF16yvnBwtlPrNBHw/H907j8MlOX8aTBnlNX1yrKx24RKcJGPyLhFUwkoKBKesR3unP93/2z14Ll8NicwQUA==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/sass-loader": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.0.2.tgz", + "integrity": "sha512-BbiqbVmbfJaWVeOOAu2o7DhYWtcNmTfvroVgFXa6k2hHheMxNAeDHLNoDy/Q5aoaVlz0LH+MbMktKwm9vN/j8Q==", + "dev": true, + "dependencies": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + } + } + }, + "node_modules/saucelabs": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", + "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", + "dev": true, + "dependencies": { + "https-proxy-agent": "^2.2.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/saucelabs/node_modules/agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/saucelabs/node_modules/https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "dev": true + }, + "node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selenium-webdriver": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", + "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", + "dev": true, + "dependencies": { + "jszip": "^3.1.3", + "rimraf": "^2.5.4", + "tmp": "0.0.30", + "xml2js": "^0.4.17" + }, + "engines": { + "node": ">= 6.9.0" + } + }, + "node_modules/selenium-webdriver/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/selenium-webdriver/node_modules/tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha512-HXdTB7lvMwcb55XFfrTM8CPr/IYREk4hVBFaQ4b/6nInrluSL86hfHm7vu0luYKCfyBZp2trCjpc8caC3vVM3w==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-dsl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz", + "integrity": "sha512-e8BOaTo007E3dMuQQTnPdalbKTABKNS7UxoBIDnwOqRa+QwMrCPjynB8zAlPF6xlqUfdLPPLIJ13hJNmhtq8Ng==", + "dev": true, + "dependencies": { + "semver": "^5.3.0" + } + }, + "node_modules/semver-dsl/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dev": true, + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "dev": true, + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socket.io": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.0.tgz", + "integrity": "sha512-8U6BEgGjQOfGz3HHTYaC/L1GaxDCJ/KM0XTkJly0EhZ5U/du9uNEZy4ZgYzEzIqlx2CMm25CrCqr1ck899eLNA==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.6.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "dev": true, + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.17.1" + } + }, + "node_modules/socket.io-adapter/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-adapter/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dev": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/sockjs-client": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.3.0.tgz", + "integrity": "sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg==", + "dependencies": { + "debug": "^3.2.5", + "eventsource": "^1.0.7", + "faye-websocket": "~0.11.1", + "inherits": "^2.0.3", + "json3": "^3.3.2", + "url-parse": "^1.4.3" + } + }, + "node_modules/socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "dev": true, + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/socks-proxy-agent/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.0.tgz", + "integrity": "sha512-i3KVgM3+QPAHNbGavK+VBq03YoJl24m9JWNbLgsjTj8aJzXG9M61bantBTNBt7CNwY2FYf+RJRYJ3pzalKjIrw==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.72.1" + } + }, + "node_modules/source-map-loader/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", + "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "dev": true, + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "devOptional": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead", + "dev": true + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.20", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz", + "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==", + "dev": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/spdy-transport/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sshpk/node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "node_modules/ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stompjs": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/stompjs/-/stompjs-2.3.3.tgz", + "integrity": "sha512-5l/Ogz0DTFW7TrpHF0LAETGqM/so8UxNJvYZjJKqcX31EVprSQgnGkO80tZctPC/lFBDUrSFiTG3xd0R27XAIA==", + "optionalDependencies": { + "websocket": "latest" + } + }, + "node_modules/streamroller": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", + "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", + "dev": true, + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/streamroller/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/streamroller/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/streamroller/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/streamroller/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/stylus": { + "version": "0.59.0", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.59.0.tgz", + "integrity": "sha512-lQ9w/XIOH5ZHVNuNbWW8D822r+/wBSO/d6XvtyHLF7LW4KaCIDeVbvn5DF8fGCJAUCwVhVi/h6J0NUcnylUEjg==", + "dev": true, + "dependencies": { + "@adobe/css-tools": "^4.0.1", + "debug": "^4.3.2", + "glob": "^7.1.6", + "sax": "~1.2.4", + "source-map": "^0.7.3" + }, + "bin": { + "stylus": "bin/stylus" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://opencollective.com/stylus" + } + }, + "node_modules/stylus-loader": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-7.0.0.tgz", + "integrity": "sha512-WTbtLrNfOfLgzTaR9Lj/BPhQroKk/LC1hfTXSUbrxmxgfUo3Y3LpmKRVA2R1XbjvTAvOfaian9vOyfv1z99E+A==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "klona": "^2.0.5", + "normalize-path": "^3.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "stylus": ">=0.52.4", + "webpack": "^5.0.0" + } + }, + "node_modules/stylus/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/stylus/node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "node_modules/stylus/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/tailwindcss": { + "version": "2.2.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-2.2.19.tgz", + "integrity": "sha512-6Ui7JSVtXadtTUo2NtkBBacobzWiQYVjYW0ZnKaP9S1ZCKQ0w7KVNz+YSDI/j7O7KCMHbOkz94ZMQhbT9pOqjw==", + "dependencies": { + "arg": "^5.0.1", + "bytes": "^3.0.0", + "chalk": "^4.1.2", + "chokidar": "^3.5.2", + "color": "^4.0.1", + "cosmiconfig": "^7.0.1", + "detective": "^5.2.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.7", + "fs-extra": "^10.0.0", + "glob-parent": "^6.0.1", + "html-tags": "^3.1.0", + "is-color-stop": "^1.1.0", + "is-glob": "^4.0.1", + "lodash": "^4.17.21", + "lodash.topath": "^4.5.2", + "modern-normalize": "^1.1.0", + "node-emoji": "^1.11.0", + "normalize-path": "^3.0.0", + "object-hash": "^2.2.0", + "postcss-js": "^3.0.3", + "postcss-load-config": "^3.1.0", + "postcss-nested": "5.0.6", + "postcss-selector-parser": "^6.0.6", + "postcss-value-parser": "^4.1.0", + "pretty-hrtime": "^1.0.3", + "purgecss": "^4.0.3", + "quick-lru": "^5.1.1", + "reduce-css-calc": "^2.1.8", + "resolve": "^1.20.0", + "tmp": "^0.2.1" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "autoprefixer": "^10.0.2", + "postcss": "^8.0.9" + } + }, + "node_modules/tailwindcss-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tailwindcss-dir/-/tailwindcss-dir-4.0.0.tgz", + "integrity": "sha512-G5orTODS8sDQOZqKa2Q4Ey/F4nlxK1mTZm02iKHLxZaNjpboPews/h2KUksC5KbgIVrpmOe1hqcNYZJy07ftwA==", + "dev": true, + "dependencies": { + "tailwindcss": "^1.0.1" + } + }, + "node_modules/tailwindcss-dir/node_modules/autoprefixer": { + "version": "9.8.8", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.8.tgz", + "integrity": "sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==", + "dev": true, + "dependencies": { + "browserslist": "^4.12.0", + "caniuse-lite": "^1.0.30001109", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "picocolors": "^0.2.1", + "postcss": "^7.0.32", + "postcss-value-parser": "^4.1.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + }, + "node_modules/tailwindcss-dir/node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "node_modules/tailwindcss-dir/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/tailwindcss-dir/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/tailwindcss-dir/node_modules/detective": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", + "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==", + "dev": true, + "dependencies": { + "acorn-node": "^1.8.2", + "defined": "^1.0.0", + "minimist": "^1.2.6" + }, + "bin": { + "detective": "bin/detective.js" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/tailwindcss-dir/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/tailwindcss-dir/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/tailwindcss-dir/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true + }, + "node_modules/tailwindcss-dir/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "dev": true, + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/tailwindcss-dir/node_modules/postcss-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-2.0.3.tgz", + "integrity": "sha512-zS59pAk3deu6dVHyrGqmC3oDXBdNdajk4k1RyxeVXCrcEDBUBHoIhE4QTsmhxgzXxsaqFDAkUZfmMa5f/N/79w==", + "dev": true, + "dependencies": { + "camelcase-css": "^2.0.1", + "postcss": "^7.0.18" + } + }, + "node_modules/tailwindcss-dir/node_modules/postcss-nested": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-4.2.3.tgz", + "integrity": "sha512-rOv0W1HquRCamWy2kFl3QazJMMe1ku6rCFoAAH+9AcxdbpDeBr6k968MLWuLjvjMcGEip01ak09hKOEgpK9hvw==", + "dev": true, + "dependencies": { + "postcss": "^7.0.32", + "postcss-selector-parser": "^6.0.2" + } + }, + "node_modules/tailwindcss-dir/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tailwindcss-dir/node_modules/tailwindcss": { + "version": "1.9.6", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-1.9.6.tgz", + "integrity": "sha512-nY8WYM/RLPqGsPEGEV2z63riyQPcHYZUJpAwdyBzVpxQHOHqHE+F/fvbCeXhdF1+TA5l72vSkZrtYCB9hRcwkQ==", + "dev": true, + "dependencies": { + "@fullhuman/postcss-purgecss": "^2.1.2", + "autoprefixer": "^9.4.5", + "browserslist": "^4.12.0", + "bytes": "^3.0.0", + "chalk": "^3.0.0 || ^4.0.0", + "color": "^3.1.2", + "detective": "^5.2.0", + "fs-extra": "^8.0.0", + "html-tags": "^3.1.0", + "lodash": "^4.17.20", + "node-emoji": "^1.8.1", + "normalize.css": "^8.0.1", + "object-hash": "^2.0.3", + "postcss": "^7.0.11", + "postcss-functions": "^3.0.0", + "postcss-js": "^2.0.0", + "postcss-nested": "^4.1.1", + "postcss-selector-parser": "^6.0.0", + "postcss-value-parser": "^4.1.0", + "pretty-hrtime": "^1.0.3", + "reduce-css-calc": "^2.1.6", + "resolve": "^1.14.2" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/tailwindcss-dir/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tailwindcss/node_modules/detective": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", + "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==", + "dependencies": { + "acorn-node": "^1.8.2", + "defined": "^1.0.0", + "minimist": "^1.2.6" + }, + "bin": { + "detective": "bin/detective.js" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/terser": { + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser-webpack-plugin/node_modules/terser": { + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", + "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-node": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", + "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", + "devOptional": true, + "dependencies": { + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "typescript": ">=2.7" + } + }, + "node_modules/ts-node/node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "devOptional": true + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", + "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==" + }, + "node_modules/tslint": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", + "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", + "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.3", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.13.0", + "tsutils": "^2.29.0" + }, + "bin": { + "tslint": "bin/tslint" + }, + "engines": { + "node": ">=4.8.0" + }, + "peerDependencies": { + "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev" + } + }, + "node_modules/tslint/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslint/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/tslint/node_modules/builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tslint/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslint/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/tslint/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/tslint/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/tslint/node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslint/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslint/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/tslint/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/tslint/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/tslint/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslint/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "peerDependencies": { + "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", + "optional": true + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "dev": true + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "optional": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", + "devOptional": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ua-parser-js": { + "version": "0.7.39", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.39.tgz", + "integrity": "sha512-IZ6acm6RhQHNibSt7+c09hhvsKy9WUr4DVbeq9U8o71qxyYtJpQeDxQnMrVqnIFMLcQjHO0I9wgfO2vIahht4w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "bin": { + "ua-parser-js": "script/cli.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", + "dev": true, + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/verror/node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + }, + "node_modules/void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webdriver-js-extender": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", + "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", + "dev": true, + "dependencies": { + "@types/selenium-webdriver": "^3.0.0", + "selenium-webdriver": "^3.0.1" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/webpack": { + "version": "5.76.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", + "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", + "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.0.tgz", + "integrity": "sha512-L5S4Q2zT57SK7tazgzjMiSMBdsw+rGYIX27MgPgx7LDhWO0lViPrHKoLS7jo5In06PWYAhlYu3PbyoC6yAThbw==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.0.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.4.2" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-subresource-integrity": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "dev": true, + "dependencies": { + "typed-assert": "^1.0.8" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "html-webpack-plugin": ">= 5.0.0-beta.1 < 6", + "webpack": "^5.12.0" + }, + "peerDependenciesMeta": { + "html-webpack-plugin": { + "optional": true + } + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/websocket": { + "version": "1.0.35", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.35.tgz", + "integrity": "sha512-/REy6amwPZl44DDzvRCkaI1q1bIiQB0mEFQLUrhz3z2EK91cp3n72rAjUlrTP0zV22HJIUOVHQGPxhFRjxjt+Q==", + "optional": true, + "dependencies": { + "bufferutil": "^4.0.1", + "debug": "^2.2.0", + "es5-ext": "^0.10.63", + "typedarray-to-buffer": "^3.1.5", + "utf-8-validate": "^5.0.2", + "yaeti": "^0.0.6" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "optional": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/websocket/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "optional": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/xterm": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.3.0.tgz", + "integrity": "sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg==", + "deprecated": "This package is now deprecated. Move to @xterm/xterm instead." + }, + "node_modules/xxhashjs": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz", + "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==", + "dev": true, + "dependencies": { + "cuint": "^0.2.2" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", + "optional": true, + "engines": { + "node": ">=0.10.32" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "devOptional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/zone.js": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.8.tgz", + "integrity": "sha512-82bctBg2hKcEJ21humWIkXRlLBBmrc3nN7DFh5LGGhcyycO2S7FN8NmdvlcKaGFDNVL4/9kFLmwmInTavdJERA==", + "dependencies": { + "tslib": "^2.3.0" + } + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..9242319 --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,93 @@ +{ + "name": "kc", + "version": "14.0.0", + "scripts": { + "ng": "ng", + "start": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng serve", + "build": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --configuration production --source-map=false", + "build:debug": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --configuration production --named-chunks --output-hashing none", + "build:stats": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --configuration production --named-chunks --output-hashing none --stats-json", + "analyze": "webpack-bundle-analyzer dist/kc/stats.json", + "format": "prettier --write \"**/*.{js,json,css,scss,less,md,ts,html,component.html}\"", + "check": "prettier --check \"**/*.{js,json,css,scss,less,md,ts,html,component.html}\"", + "test": "ng test", + "lint": "ng lint", + "e2e": "ng e2e" + }, + "private": true, + "dependencies": { + "@angular/animations": "14.3.0", + "@angular/cdk": "14.2.7", + "@angular/common": "14.3.0", + "@angular/compiler": "14.3.0", + "@angular/core": "14.3.0", + "@angular/flex-layout": "^14.0.0-beta.41", + "@angular/forms": "14.3.0", + "@angular/material": "14.2.7", + "@angular/platform-browser": "14.3.0", + "@angular/platform-browser-dynamic": "14.3.0", + "@angular/router": "14.3.0", + "@dagrejs/dagre": "^1.1.4", + "@iconify/icons-fa-brands": "^1.2.4", + "@iconify/icons-fa-solid": "^1.2.4", + "@iconify/icons-ic": "^1.2.13", + "@ngx-loading-bar/core": "^6.0.2", + "@ngx-loading-bar/router": "^6.0.2", + "@swimlane/ngx-charts": "^20.5.0", + "@types/pluralize": "^0.0.33", + "@visurel/iconify-angular": "^11.0.0", + "ace-builds": "^1.32.6", + "dayjs": "^1.11.10", + "file-saver": "^2.0.5", + "js-yaml": "^4.1.0", + "json2yaml": "^1.1.0", + "jwt-decode": "^3.1.2", + "moment": "^2.30.1", + "net": "1.0.2", + "ng-pick-datetime-ex": "^14.0.0", + "ng-terminal": "^6.1.0", + "ng2-search-filter": "0.5.1", + "ngx-webstorage": "^10.0.1", + "normalize.css": "8.0.1", + "pako": "1.0.11", + "pluralize": "^8.0.0", + "rxjs": "^6.6.7", + "sockjs-client": "1.3.0", + "stompjs": "2.3.3", + "tailwindcss": "^2.2.19", + "tslib": "^2.6.2", + "xterm": "^5.3.0", + "zone.js": "^0.11.8" + }, + "devDependencies": { + "@angular-builders/custom-webpack": "^14.1.0", + "@angular-devkit/build-angular": "^14.2.13", + "@angular/cli": "14.2.13", + "@angular/compiler-cli": "14.3.0", + "@angular/language-service": "14.3.0", + "@fullhuman/purgecss-loader": "1.0.0", + "@types/jasmine": "~3.6.0", + "@types/jasminewd2": "2.0.8", + "@types/node": "^12.20.55", + "@types/simplebar": "2.4.2", + "codelyzer": "^6.0.2", + "jasmine-core": "^3.8.0", + "jasmine-spec-reporter": "~5.0.0", + "karma": "~6.4.2", + "karma-chrome-launcher": "~3.1.0", + "karma-coverage-istanbul-reporter": "~3.0.2", + "karma-jasmine": "~4.0.0", + "karma-jasmine-html-reporter": "^1.7.0", + "ng-packagr": "^14.2.2", + "postcss-import": "^15.1.0", + "postcss-loader": "^4.3.0", + "postcss-scss": "^3.0.5", + "prettier": "^3.4.2", + "protractor": "~7.0.0", + "tailwindcss-dir": "4.0.0", + "ts-node": "^9.0.0", + "tslint": "~6.1.0", + "typescript": "4.6.4", + "webpack-bundle-analyzer": "^4.10.1" + } +} diff --git a/frontend/projects/cdk-ui/README.md b/frontend/projects/cdk-ui/README.md new file mode 100644 index 0000000..65f4267 --- /dev/null +++ b/frontend/projects/cdk-ui/README.md @@ -0,0 +1,25 @@ +# CdkUi + +This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 14.2.0. + +## Code scaffolding + +Run `ng generate component component-name --project cdk-ui` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project cdk-ui`. + +> Note: Don't forget to add `--project cdk-ui` or else it will be added to the default project in your `angular.json` file. + +## Build + +Run `ng build cdk-ui` to build the project. The build artifacts will be stored in the `dist/` directory. + +## Publishing + +After building your library with `ng build cdk-ui`, go to the dist folder `cd dist/cdk-ui` and run `npm publish`. + +## Running unit tests + +Run `ng test cdk-ui` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. diff --git a/frontend/projects/cdk-ui/index.ts b/frontend/projects/cdk-ui/index.ts new file mode 100644 index 0000000..e23414b --- /dev/null +++ b/frontend/projects/cdk-ui/index.ts @@ -0,0 +1,4 @@ +/* + * Public API Surface of cdk + */ +export {}; diff --git a/frontend/projects/cdk-ui/karma.conf.js b/frontend/projects/cdk-ui/karma.conf.js new file mode 100644 index 0000000..96c714d --- /dev/null +++ b/frontend/projects/cdk-ui/karma.conf.js @@ -0,0 +1,41 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + jasmine: { + // you can add configuration options for Jasmine here + // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html + // for example, you can disable the random execution with `random: false` + // or set a specific seed with `seed: 4321` + }, + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + jasmineHtmlReporter: { + suppressAll: true // removes the duplicated traces + }, + coverageReporter: { + dir: require('path').join(__dirname, '../../coverage/cdk-ui'), + subdir: '.', + reporters: [{ type: 'html' }, { type: 'text-summary' }] + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/frontend/projects/cdk-ui/ng-package.json b/frontend/projects/cdk-ui/ng-package.json new file mode 100644 index 0000000..680e1cc --- /dev/null +++ b/frontend/projects/cdk-ui/ng-package.json @@ -0,0 +1,15 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/cdk-ui", + "assets": [ + { + "input": "styles", + "glob": "**/*.scss", + "output": "styles" + } + ], + "lib": { + "entryFile": "index.ts", + "cssUrl": "inline" + } +} diff --git a/frontend/projects/cdk-ui/package.json b/frontend/projects/cdk-ui/package.json new file mode 100644 index 0000000..3f424b1 --- /dev/null +++ b/frontend/projects/cdk-ui/package.json @@ -0,0 +1,15 @@ +{ + "name": "@cdk-ui", + "version": "0.0.1", + "peerDependencies": { + "@angular/common": "^14.2.0", + "@angular/core": "^14.2.0" + }, + "dependencies": { + "tslib": "^2.3.0" + }, + "optionalDependencies": { + "@angular-slider/ngx-slider": "^2.0.4", + "moment": "^2.30.1" + } +} diff --git a/frontend/projects/cdk-ui/src/clipboard/DOCUMENTATION.md b/frontend/projects/cdk-ui/src/clipboard/DOCUMENTATION.md new file mode 100644 index 0000000..0583b99 --- /dev/null +++ b/frontend/projects/cdk-ui/src/clipboard/DOCUMENTATION.md @@ -0,0 +1,13 @@ +# API reference for Clipboard + +```ts +import { CdkClipboardModule } from '@cdk-ui/clipboard'; +``` + +## Usage + +#### component.html + +```ts + +``` diff --git a/frontend/projects/cdk-ui/src/clipboard/clipboard.component.ts b/frontend/projects/cdk-ui/src/clipboard/clipboard.component.ts new file mode 100644 index 0000000..b9489b2 --- /dev/null +++ b/frontend/projects/cdk-ui/src/clipboard/clipboard.component.ts @@ -0,0 +1,44 @@ +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; +import { MatRipple } from '@angular/material/core'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { Clipboard } from '@angular/cdk/clipboard'; + +@Component({ + selector: 'cdk-clipboard', + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [MatRipple], + template: ` + + + + `, + host: { + class: 'cdk-clipboard', + '(click)': 'copy($event)' + } +}) +export class CdkClipboardComponent { + @Input() cbContent!: string; + @Input() message?: string; + + constructor( + private _clipboard: Clipboard, + private snackbar: MatSnackBar, + private ripple: MatRipple + ) {} + + copy(e: PointerEvent): void { + this._clipboard.copy(this.cbContent); + this.snackbar.open(this.message || 'Copied to the clipboard!', 'Close', { + duration: 3000, + panelClass: ['snackbar-dark'] + }); + this.ripple.launch(e.x, e.y); + } +} diff --git a/frontend/projects/cdk-ui/src/clipboard/clipboard.module.ts b/frontend/projects/cdk-ui/src/clipboard/clipboard.module.ts new file mode 100644 index 0000000..c74f7e5 --- /dev/null +++ b/frontend/projects/cdk-ui/src/clipboard/clipboard.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core'; +import { CdkClipboardComponent } from './clipboard.component'; +import { CommonModule } from '@angular/common'; +import { MatSnackBarModule } from '@angular/material/snack-bar'; +import { MatRippleModule } from '@angular/material/core'; + +@NgModule({ + declarations: [CdkClipboardComponent], + imports: [CommonModule, MatSnackBarModule, MatRippleModule], + exports: [CdkClipboardComponent] +}) +export class CdkClipboardModule {} diff --git a/frontend/projects/cdk-ui/src/clipboard/index.ts b/frontend/projects/cdk-ui/src/clipboard/index.ts new file mode 100644 index 0000000..7e1a213 --- /dev/null +++ b/frontend/projects/cdk-ui/src/clipboard/index.ts @@ -0,0 +1 @@ +export * from './public-api'; diff --git a/frontend/projects/cdk-ui/src/clipboard/ng-package.json b/frontend/projects/cdk-ui/src/clipboard/ng-package.json new file mode 100644 index 0000000..1dc0b0b --- /dev/null +++ b/frontend/projects/cdk-ui/src/clipboard/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "index.ts" + } +} diff --git a/frontend/projects/cdk-ui/src/clipboard/public-api.ts b/frontend/projects/cdk-ui/src/clipboard/public-api.ts new file mode 100644 index 0000000..2b4c800 --- /dev/null +++ b/frontend/projects/cdk-ui/src/clipboard/public-api.ts @@ -0,0 +1,2 @@ +export { CdkClipboardModule } from './clipboard.module'; +export { CdkClipboardComponent } from './clipboard.component'; diff --git a/frontend/projects/cdk-ui/src/hint/DOCUMENTATION.md b/frontend/projects/cdk-ui/src/hint/DOCUMENTATION.md new file mode 100644 index 0000000..6991295 --- /dev/null +++ b/frontend/projects/cdk-ui/src/hint/DOCUMENTATION.md @@ -0,0 +1,13 @@ +# API reference for Hint + +```ts +import { CdkClipboardModule } from '@cdk-ui/clipboard'; +``` + +## Usage + +#### component.html + +```ts + +``` diff --git a/frontend/projects/cdk-ui/src/hint/hint.component.ts b/frontend/projects/cdk-ui/src/hint/hint.component.ts new file mode 100644 index 0000000..161cb1b --- /dev/null +++ b/frontend/projects/cdk-ui/src/hint/hint.component.ts @@ -0,0 +1,96 @@ +import { ChangeDetectionStrategy, Component, ElementRef, Inject, Input, NgZone, Optional, ViewContainerRef } from '@angular/core'; +import { + MAT_TOOLTIP_DEFAULT_OPTIONS, + MAT_TOOLTIP_SCROLL_STRATEGY, + MatTooltip, + MatTooltipDefaultOptions, + TooltipPosition +} from '@angular/material/tooltip'; +import { AriaDescriber, FocusMonitor } from '@angular/cdk/a11y'; +import { Directionality } from '@angular/cdk/bidi'; +import { Overlay, ScrollDispatcher } from '@angular/cdk/overlay'; +import { Platform } from '@angular/cdk/platform'; +import { DOCUMENT } from '@angular/common'; + +@Component({ + selector: 'cdk-hint', + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` + + `, + host: { + class: 'cdk-hint' + }, + exportAs: 'cdkHint' +}) +export class CdkHintComponent extends MatTooltip { + @Input() get hint() { + return this.message; + } + set hint(value: string) { + this.message = value; + } + + @Input() get hintPosition() { + return this.position; + } + + set hintPosition(value: TooltipPosition) { + if (value) { + this.position = value; + this.setHintOverlayClass(value); + } + } + + @Input() size: string = '1.2rem'; + @Input() color: string = 'currentColor'; + + constructor( + _overlay: Overlay, + _elementRef: ElementRef, + _scrollDispatcher: ScrollDispatcher, + _viewContainerRef: ViewContainerRef, + _ngZone: NgZone, + _platform: Platform, + _ariaDescriber: AriaDescriber, + _focusMonitor: FocusMonitor, + @Inject(MAT_TOOLTIP_SCROLL_STRATEGY) _scrollStrategy: any, + @Optional() _dir: Directionality, + @Optional() + @Inject(MAT_TOOLTIP_DEFAULT_OPTIONS) + _defaultOptions: MatTooltipDefaultOptions, + @Inject(DOCUMENT) _document: any + ) { + super( + _overlay, + _elementRef, + _scrollDispatcher, + _viewContainerRef, + _ngZone, + _platform, + _ariaDescriber, + _focusMonitor, + _scrollStrategy, + _dir, + _defaultOptions, + _document + ); + this.position = 'after'; + this.setHintOverlayClass(this.position); + } + + setHintOverlayClass(position: TooltipPosition): void { + this.tooltipClass = `cdk-hint-tooltip cdk-hint-${position}`; + } +} diff --git a/frontend/projects/cdk-ui/src/hint/hint.module.ts b/frontend/projects/cdk-ui/src/hint/hint.module.ts new file mode 100644 index 0000000..f09a775 --- /dev/null +++ b/frontend/projects/cdk-ui/src/hint/hint.module.ts @@ -0,0 +1,11 @@ +import { NgModule } from '@angular/core'; +import { CdkHintComponent } from './hint.component'; +import { CommonModule } from '@angular/common'; +import { MatTooltipModule } from '@angular/material/tooltip'; + +@NgModule({ + declarations: [CdkHintComponent], + imports: [CommonModule, MatTooltipModule], + exports: [CdkHintComponent] +}) +export class CdkHintModule {} diff --git a/frontend/projects/cdk-ui/src/hint/index.ts b/frontend/projects/cdk-ui/src/hint/index.ts new file mode 100644 index 0000000..7e1a213 --- /dev/null +++ b/frontend/projects/cdk-ui/src/hint/index.ts @@ -0,0 +1 @@ +export * from './public-api'; diff --git a/frontend/projects/cdk-ui/src/hint/ng-package.json b/frontend/projects/cdk-ui/src/hint/ng-package.json new file mode 100644 index 0000000..1dc0b0b --- /dev/null +++ b/frontend/projects/cdk-ui/src/hint/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "index.ts" + } +} diff --git a/frontend/projects/cdk-ui/src/hint/public-api.ts b/frontend/projects/cdk-ui/src/hint/public-api.ts new file mode 100644 index 0000000..42ec652 --- /dev/null +++ b/frontend/projects/cdk-ui/src/hint/public-api.ts @@ -0,0 +1,2 @@ +export { CdkHintModule } from './hint.module'; +export { CdkHintComponent } from './hint.component'; diff --git a/frontend/projects/cdk-ui/src/horizontal-stepper/horizontal-stepper.component.html b/frontend/projects/cdk-ui/src/horizontal-stepper/horizontal-stepper.component.html new file mode 100644 index 0000000..949ac1e --- /dev/null +++ b/frontend/projects/cdk-ui/src/horizontal-stepper/horizontal-stepper.component.html @@ -0,0 +1,28 @@ +
+
+

{{ header }}

+
+
+ +
+
+ + +
+
diff --git a/frontend/projects/cdk-ui/src/horizontal-stepper/horizontal-stepper.component.ts b/frontend/projects/cdk-ui/src/horizontal-stepper/horizontal-stepper.component.ts new file mode 100644 index 0000000..8030114 --- /dev/null +++ b/frontend/projects/cdk-ui/src/horizontal-stepper/horizontal-stepper.component.ts @@ -0,0 +1,15 @@ +import { Component, Input } from '@angular/core'; +import { CdkStepper } from '@angular/cdk/stepper'; + +@Component({ + selector: 'cdk-horizontal-stepper', + templateUrl: './horizontal-stepper.component.html', + providers: [{ provide: CdkStepper, useExisting: CdkHorizontalStepperComponent }] +}) +export class CdkHorizontalStepperComponent extends CdkStepper { + @Input() header!: string; + + onClick(index: number): void { + this.selectedIndex = index; + } +} diff --git a/frontend/projects/cdk-ui/src/horizontal-stepper/horizontal-stepper.module.ts b/frontend/projects/cdk-ui/src/horizontal-stepper/horizontal-stepper.module.ts new file mode 100644 index 0000000..b11e734 --- /dev/null +++ b/frontend/projects/cdk-ui/src/horizontal-stepper/horizontal-stepper.module.ts @@ -0,0 +1,13 @@ +// Imports from @angular +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { CdkStepperModule } from '@angular/cdk/stepper'; +// Component +import { CdkHorizontalStepperComponent } from './horizontal-stepper.component'; + +@NgModule({ + declarations: [CdkHorizontalStepperComponent], + imports: [CommonModule, CdkStepperModule], + exports: [CdkHorizontalStepperComponent] +}) +export class CdkHorizontalStepperModule {} diff --git a/frontend/projects/cdk-ui/src/horizontal-stepper/index.ts b/frontend/projects/cdk-ui/src/horizontal-stepper/index.ts new file mode 100644 index 0000000..7e1a213 --- /dev/null +++ b/frontend/projects/cdk-ui/src/horizontal-stepper/index.ts @@ -0,0 +1 @@ +export * from './public-api'; diff --git a/frontend/projects/cdk-ui/src/horizontal-stepper/ng-package.json b/frontend/projects/cdk-ui/src/horizontal-stepper/ng-package.json new file mode 100644 index 0000000..1dc0b0b --- /dev/null +++ b/frontend/projects/cdk-ui/src/horizontal-stepper/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "index.ts" + } +} diff --git a/frontend/projects/cdk-ui/src/horizontal-stepper/public-api.ts b/frontend/projects/cdk-ui/src/horizontal-stepper/public-api.ts new file mode 100644 index 0000000..5b0e637 --- /dev/null +++ b/frontend/projects/cdk-ui/src/horizontal-stepper/public-api.ts @@ -0,0 +1,2 @@ +export { CdkHorizontalStepperModule } from './horizontal-stepper.module'; +export { CdkHorizontalStepperComponent } from './horizontal-stepper.component'; diff --git a/frontend/projects/cdk-ui/src/icon/DOCUMENTATION.md b/frontend/projects/cdk-ui/src/icon/DOCUMENTATION.md new file mode 100644 index 0000000..d4a1744 --- /dev/null +++ b/frontend/projects/cdk-ui/src/icon/DOCUMENTATION.md @@ -0,0 +1,21 @@ +# API reference for VPC Card + +```ts +import { CdkIconModule } from '@cdk-ui/clipboard'; +``` + +## Usage + +#### component.html + +```ts + + + + + + + + + +``` diff --git a/frontend/projects/cdk-ui/src/icon/icon.component.ts b/frontend/projects/cdk-ui/src/icon/icon.component.ts new file mode 100644 index 0000000..f1f2335 --- /dev/null +++ b/frontend/projects/cdk-ui/src/icon/icon.component.ts @@ -0,0 +1,41 @@ +import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core'; +import { IconType } from './icon.interfaces'; + +@Component({ + selector: 'cdk-icon', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` + + + + + + + + + + + `, + host: { + class: 'cdk-icon', + '[class.cdk-icon-regular]': "type === 'regular'", + '[class.cdk-icon-check]': "type === 'check'", + // Style + '[style.background]': 'backgroundColor', + '[style.width]': 'width', + '[style.height]': 'height', + '[style.borderRadius]': 'borderRadius' + } +}) +export class CdkIconComponent { + @Input() type: IconType = 'regular'; + // Icon Img + @Input() src?: string; + @Input() alt?: string; + // Styles + @Input() backgroundColor?: string; + @Input() width?: string; + @Input() height?: string; + @Input() borderRadius?: string; +} diff --git a/frontend/projects/cdk-ui/src/icon/icon.interfaces.ts b/frontend/projects/cdk-ui/src/icon/icon.interfaces.ts new file mode 100644 index 0000000..bca88f3 --- /dev/null +++ b/frontend/projects/cdk-ui/src/icon/icon.interfaces.ts @@ -0,0 +1 @@ +export type IconType = 'regular' | 'check'; diff --git a/frontend/projects/cdk-ui/src/icon/icon.module.ts b/frontend/projects/cdk-ui/src/icon/icon.module.ts new file mode 100644 index 0000000..2b2a891 --- /dev/null +++ b/frontend/projects/cdk-ui/src/icon/icon.module.ts @@ -0,0 +1,10 @@ +import { NgModule } from '@angular/core'; +import { CdkIconComponent } from './icon.component'; +import { CommonModule } from '@angular/common'; + +@NgModule({ + declarations: [CdkIconComponent], + imports: [CommonModule], + exports: [CdkIconComponent] +}) +export class CdkIconModule {} diff --git a/frontend/projects/cdk-ui/src/icon/index.ts b/frontend/projects/cdk-ui/src/icon/index.ts new file mode 100644 index 0000000..7e1a213 --- /dev/null +++ b/frontend/projects/cdk-ui/src/icon/index.ts @@ -0,0 +1 @@ +export * from './public-api'; diff --git a/frontend/projects/cdk-ui/src/icon/ng-package.json b/frontend/projects/cdk-ui/src/icon/ng-package.json new file mode 100644 index 0000000..1dc0b0b --- /dev/null +++ b/frontend/projects/cdk-ui/src/icon/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "index.ts" + } +} diff --git a/frontend/projects/cdk-ui/src/icon/public-api.ts b/frontend/projects/cdk-ui/src/icon/public-api.ts new file mode 100644 index 0000000..cc37aad --- /dev/null +++ b/frontend/projects/cdk-ui/src/icon/public-api.ts @@ -0,0 +1,3 @@ +export { CdkIconModule } from './icon.module'; +export { CdkIconComponent } from './icon.component'; +export * from './icon.interfaces'; diff --git a/frontend/projects/cdk-ui/src/test.ts b/frontend/projects/cdk-ui/src/test.ts new file mode 100644 index 0000000..59f2f3c --- /dev/null +++ b/frontend/projects/cdk-ui/src/test.ts @@ -0,0 +1,25 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js'; +import 'zone.js/testing'; +import { getTestBed } from '@angular/core/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; + +declare const require: { + context( + path: string, + deep?: boolean, + filter?: RegExp + ): { + (id: string): T; + keys(): string[]; + }; +}; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting()); + +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().forEach(context); diff --git a/frontend/projects/cdk-ui/src/tooltip/DOCUMENTATION.md b/frontend/projects/cdk-ui/src/tooltip/DOCUMENTATION.md new file mode 100644 index 0000000..cc000aa --- /dev/null +++ b/frontend/projects/cdk-ui/src/tooltip/DOCUMENTATION.md @@ -0,0 +1,18 @@ +# API reference for Tooltip (HTML Structure tooltip) + +```ts +import { CdkTooltipDirective } from '@cdk-ui/tooltip'; +``` + +## Usage + +#### component.html + +```html +
Hover me for tooltip
+ + + Hello K. +

Nice to meet you

+
+``` diff --git a/frontend/projects/cdk-ui/src/tooltip/index.ts b/frontend/projects/cdk-ui/src/tooltip/index.ts new file mode 100644 index 0000000..7e1a213 --- /dev/null +++ b/frontend/projects/cdk-ui/src/tooltip/index.ts @@ -0,0 +1 @@ +export * from './public-api'; diff --git a/frontend/projects/cdk-ui/src/tooltip/ng-package.json b/frontend/projects/cdk-ui/src/tooltip/ng-package.json new file mode 100644 index 0000000..1dc0b0b --- /dev/null +++ b/frontend/projects/cdk-ui/src/tooltip/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "index.ts" + } +} diff --git a/frontend/projects/cdk-ui/src/tooltip/public-api.ts b/frontend/projects/cdk-ui/src/tooltip/public-api.ts new file mode 100644 index 0000000..e40f271 --- /dev/null +++ b/frontend/projects/cdk-ui/src/tooltip/public-api.ts @@ -0,0 +1,3 @@ +export { CdkTooltipDirective } from './tooltip.directive'; +export { CdkTooltipContentComponent } from './tooltip-content.component'; +export { CdkTooltipModule } from './tooltip.module'; diff --git a/frontend/projects/cdk-ui/src/tooltip/tooltip-content.component.ts b/frontend/projects/cdk-ui/src/tooltip/tooltip-content.component.ts new file mode 100644 index 0000000..1bcb436 --- /dev/null +++ b/frontend/projects/cdk-ui/src/tooltip/tooltip-content.component.ts @@ -0,0 +1,40 @@ +import { Component, HostBinding, HostListener, Input } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { trigger, transition, style, animate } from '@angular/animations'; + +@Component({ + selector: 'cdk-tooltip-content', + standalone: true, + imports: [CommonModule], + template: `
+ +
`, + animations: [ + trigger('tooltipAnimation', [ + transition(':enter', [ + style({ opacity: 0, transform: 'scale(0.9)' }), + animate('200ms ease-out', style({ opacity: 1, transform: 'scale(1)' })) + ]), + transition(':leave', [animate('200ms ease-in', style({ opacity: 0, transform: 'scale(0.9)' }))]) + ]) + ], + host: { + class: 'cdk-tooltip-container' + } +}) +export class CdkTooltipContentComponent { + @Input() contentTemplate!: any; + + isHovered = false; + + @HostBinding('@tooltipAnimation') animation = true; + + @HostListener('mouseenter') onMouseEnter() { + this.isHovered = true; + } + + @HostListener('mouseleave') onMouseLeave() { + this.isHovered = false; + console.log('leaved', this.isHovered); + } +} diff --git a/frontend/projects/cdk-ui/src/tooltip/tooltip.directive.ts b/frontend/projects/cdk-ui/src/tooltip/tooltip.directive.ts new file mode 100644 index 0000000..fd2edfd --- /dev/null +++ b/frontend/projects/cdk-ui/src/tooltip/tooltip.directive.ts @@ -0,0 +1,88 @@ +import { ComponentRef, Directive, ElementRef, HostListener, inject, Input, TemplateRef } from '@angular/core'; +import { ConnectedPosition, Overlay, OverlayRef, PositionStrategy } from '@angular/cdk/overlay'; +import { ComponentPortal } from '@angular/cdk/portal'; +import { CdkTooltipContentComponent } from './tooltip-content.component'; + +/** + * @description HTML structure tooltip + */ +@Directive({ + selector: '[cdkTooltip]', + standalone: true +}) +export class CdkTooltipDirective { + private overlay = inject(Overlay); + private elementRef = inject(ElementRef); + + @Input('cdkTooltip') template!: TemplateRef; + @Input() tooltipPosition: 'above' | 'below' | 'start' | 'end' = 'below'; // Default position + + private overlayRef!: OverlayRef; + private tooltipContentInstance!: ComponentRef; + private selfVisiting = false; + + @HostListener('mouseenter') show() { + this.selfVisiting = true; + + if (!this.template || this.overlayRef?.hasAttached()) return; + + const positionStrategy = this.getPositionStrategy(); + this.overlayRef = this.overlay.create({ positionStrategy }); + + const componentPortal = new ComponentPortal(CdkTooltipContentComponent); + this.tooltipContentInstance = this.overlayRef.attach(componentPortal); + + // Pass the template to the tooltip content component + this.tooltipContentInstance.instance.contentTemplate = this.template; + + // Listen for mouseenter and mouseleave on the overlay + const tooltipElement = this.tooltipContentInstance.location.nativeElement; + tooltipElement.addEventListener('mouseleave', () => { + setTimeout(() => { + if (!this.selfVisiting) this.hide(); + }, 50); + }); + } + + @HostListener('mouseleave') hide() { + this.selfVisiting = false; + // Delay hiding if the tooltip is hovered + setTimeout(() => { + if (this.tooltipContentInstance && !this.tooltipContentInstance.instance.isHovered) { + this.overlayRef.detach(); + } + }, 100); + } + + private getPositionStrategy(): PositionStrategy { + const positions: { [key: string]: ConnectedPosition } = { + above: { + originX: 'center', + originY: 'top', + overlayX: 'center', + overlayY: 'bottom' + }, + below: { + originX: 'center', + originY: 'bottom', + overlayX: 'center', + overlayY: 'top' + }, + start: { + originX: 'start', + originY: 'center', + overlayX: 'end', + overlayY: 'center' + }, + end: { + originX: 'end', + originY: 'center', + overlayX: 'start', + overlayY: 'center' + } + }; + + const selectedPosition = positions[this.tooltipPosition]; + return this.overlay.position().flexibleConnectedTo(this.elementRef).withPositions([selectedPosition]); + } +} diff --git a/frontend/projects/cdk-ui/src/tooltip/tooltip.module.ts b/frontend/projects/cdk-ui/src/tooltip/tooltip.module.ts new file mode 100644 index 0000000..01fee84 --- /dev/null +++ b/frontend/projects/cdk-ui/src/tooltip/tooltip.module.ts @@ -0,0 +1,9 @@ +import { NgModule } from '@angular/core'; +import { CdkTooltipDirective } from './tooltip.directive'; +import { CdkTooltipContentComponent } from './tooltip-content.component'; + +@NgModule({ + imports: [CdkTooltipDirective, CdkTooltipContentComponent], + exports: [CdkTooltipDirective, CdkTooltipContentComponent] +}) +export class CdkTooltipModule {} diff --git a/frontend/projects/cdk-ui/styles/all-components.scss b/frontend/projects/cdk-ui/styles/all-components.scss new file mode 100644 index 0000000..7ffbfdb --- /dev/null +++ b/frontend/projects/cdk-ui/styles/all-components.scss @@ -0,0 +1,5 @@ +@import './clipboard'; +@import './icon'; +@import './hint'; +@import './horizontal-stepper'; +@import './tooltip'; diff --git a/frontend/projects/cdk-ui/styles/clipboard.scss b/frontend/projects/cdk-ui/styles/clipboard.scss new file mode 100644 index 0000000..68332f4 --- /dev/null +++ b/frontend/projects/cdk-ui/styles/clipboard.scss @@ -0,0 +1,54 @@ +$clipboard: cdk-clipboard; + +.#{$clipboard} { + display: inline-flex; + cursor: pointer; + width: auto; + height: auto; + position: relative; + overflow: hidden; + border-radius: 50%; + vertical-align: bottom; + + &__icon { + height: 1.5rem; + width: 1.5rem; + min-width: 1.5rem; + + &__color { + fill: var(--text-color); + } + &__bg { + transition: fill 0.1.5s ease-in; + } + } + + // &:hover { + // .#{$clipboard}__icon { + // &__bg { + // fill: var(--color-primary-300); + // } + // } + // } +} + +.kc-style { + &-dark { + .#{$clipboard} { + &__icon { + &__bg { + fill: #24395e; + } + } + } + } + &-light { + .#{$clipboard} { + &__icon { + &__bg { + fill: var(--color-primary-100); + } + } + } + } +} diff --git a/frontend/projects/cdk-ui/styles/hint.scss b/frontend/projects/cdk-ui/styles/hint.scss new file mode 100644 index 0000000..f51b443 --- /dev/null +++ b/frontend/projects/cdk-ui/styles/hint.scss @@ -0,0 +1,15 @@ +.cdk-hint { + font-size: 10px; + display: inline-block; + vertical-align: middle; + line-height: normal; + &-tooltip { + --bg-hint-tooltip: var(--background-info-name-box) !important; + background: var(--bg-hint-tooltip); + overflow: visible !important; + box-shadow: + 0 1px 3px 0 rgb(250 250 250 / 0.1), + 0 1px 2px -1px rgb(250 250 250 / 0.1); + border: 1px solid var(--border); + } +} diff --git a/frontend/projects/cdk-ui/styles/horizontal-stepper.scss b/frontend/projects/cdk-ui/styles/horizontal-stepper.scss new file mode 100644 index 0000000..3f7daef --- /dev/null +++ b/frontend/projects/cdk-ui/styles/horizontal-stepper.scss @@ -0,0 +1,183 @@ +@mixin visibleArrow($paddingLeft) { + padding-left: $paddingLeft; + border-color: transparent; + + .#{$progress}__step { + &__arrow { + display: block; + } + } +} + +@mixin visibleNumber() { + justify-content: left; + + .#{$progress}__step { + &__text { + text-align: left; + } + &__number { + display: inline-block; + } + } +} + +$progress: progress; + +.#{$progress} { + &__header { + h3 { + font-style: normal; + color: var(--text-color); + font-weight: 600; + font-size: 18px; + letter-spacing: 0.3px; + } + } + + &__navbar { + min-width: max-content; + padding-bottom: 2px; + + &__scroll { + overflow-x: auto; + } + } + + &__nav { + display: flex; + border-radius: 10px; + background: var(--background-kc-stepper); + border: 1px solid var(--border); + list-style: none; + overflow: hidden; + font-size: 0.875rem; + font-weight: 600; + counter-reset: li; + } + + // Step + &__step { + $height: 5.153rem; + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + text-align: left; + border-right: 1px solid var(--border); + height: $height; + padding-left: 20px; + padding-right: 20px; + font-size: 0.75rem; + background: inherit; + cursor: pointer; + + &:last-child { + border-right: 0; + } + + &__text { + position: relative; + z-index: 3; + text-align: center; + } + + // Count + &__number { + display: none; + &::before { + content: counter(li) ' '; + counter-increment: li; + margin-right: 15px; + background: var(--background-kc-step-number); + color: var(--color-kc-step-number); + border-radius: 50%; + height: 1.875rem; + line-height: 1.875rem; + text-align: center; + width: 1.875rem; + display: inline-block; + } + } + + &__arrow { + width: $height; + height: 100%; + background: inherit; + position: absolute; + -webkit-clip-path: polygon(0% 0%, 100% 100%, 0% 100%); + clip-path: polygon(0% 0%, 100% 100%, 0% 100%); + -webkit-transform: rotate(225deg); + border-radius: 0 0 0 10px; + z-index: 2; + top: 50%; + left: 100%; + transform: rotate(224.5deg) translate(67px, -8px); + border: 1px solid var(--border); + display: none; + } + + // Active + &--current { + background: var(--step-active-bg); + color: var(--step-active-text); + font-weight: 600 !important; + + .#{$progress}__step { + &__number::before { + background: var(--background-kc-step-number-active); + color: var(--color-kc-step-number-active); + } + } + } + } + + &__step--1 { + padding-left: 7%; + border-color: transparent; + + @include visibleNumber(); + } + + // Media + @media (min-width: 576px) { + // Visible Number + &__step--2, + &__step--3 { + @include visibleNumber(); + } + } + + @media (min-width: 768px) { + // Visible Arrow + &__step--2 { + @include visibleArrow(7%); + } + + // Visible Number + &__step--4, + &__step--5 { + @include visibleNumber(); + } + } + + @media (min-width: 1024px) { + // Visible Arrow + &__step--3 { + @include visibleArrow(7%); + } + } + + @media (min-width: 1440px) { + &__step--3 { + padding-left: 6%; + } + + // Visible Arrow + &__step--4, + &__step--5 { + @include visibleArrow(5%); + } + } +} diff --git a/frontend/projects/cdk-ui/styles/icon.scss b/frontend/projects/cdk-ui/styles/icon.scss new file mode 100644 index 0000000..cfe1c60 --- /dev/null +++ b/frontend/projects/cdk-ui/styles/icon.scss @@ -0,0 +1,22 @@ +.cdk-icon { + display: inline-flex; + align-items: center; + justify-content: center; + height: 38px; + width: 38px; + border-radius: 10px; + background: var(--cdk-icon-bg); + // Modifier + &-check { + border-radius: 50%; + height: 25px; + width: 25px; + } + + // Element + img, + svg { + max-width: 100%; + height: auto; + } +} diff --git a/frontend/projects/cdk-ui/styles/tooltip.scss b/frontend/projects/cdk-ui/styles/tooltip.scss new file mode 100644 index 0000000..a1569fa --- /dev/null +++ b/frontend/projects/cdk-ui/styles/tooltip.scss @@ -0,0 +1,23 @@ +.cdk-tooltip { + &-container { + padding: 8px; + } + &-content { + background: var(--background-info-name-box); + box-shadow: + 0 1px 3px 0 rgba(250, 250, 250, 0.1), + 0 1px 2px -1px rgba(250, 250, 250, 0.1); + border: 1px solid var(--border); + padding: 10px; + border-radius: 4px; + z-index: 1000; + font-size: 11px; + overflow: auto; + + code { + font-size: 11px; + line-height: 21px; + padding: 5px 7px; + } + } +} diff --git a/frontend/projects/cdk-ui/tsconfig.lib.json b/frontend/projects/cdk-ui/tsconfig.lib.json new file mode 100644 index 0000000..305b0b9 --- /dev/null +++ b/frontend/projects/cdk-ui/tsconfig.lib.json @@ -0,0 +1,12 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": ["src/test.ts", "**/*.spec.ts"] +} diff --git a/frontend/projects/cdk-ui/tsconfig.lib.prod.json b/frontend/projects/cdk-ui/tsconfig.lib.prod.json new file mode 100644 index 0000000..06de549 --- /dev/null +++ b/frontend/projects/cdk-ui/tsconfig.lib.prod.json @@ -0,0 +1,10 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.lib.json", + "compilerOptions": { + "declarationMap": false + }, + "angularCompilerOptions": { + "compilationMode": "partial" + } +} diff --git a/frontend/projects/cdk-ui/tsconfig.spec.json b/frontend/projects/cdk-ui/tsconfig.spec.json new file mode 100644 index 0000000..fafd1e1 --- /dev/null +++ b/frontend/projects/cdk-ui/tsconfig.spec.json @@ -0,0 +1,10 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": ["jasmine"] + }, + "files": ["src/test.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] +} diff --git a/frontend/projects/core-ui/README.md b/frontend/projects/core-ui/README.md new file mode 100644 index 0000000..abab921 --- /dev/null +++ b/frontend/projects/core-ui/README.md @@ -0,0 +1,25 @@ +# CoreUi + +This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 14.2.0. + +## Code scaffolding + +Run `ng generate component component-name --project core-ui` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project core-ui`. + +> Note: Don't forget to add `--project core-ui` or else it will be added to the default project in your `angular.json` file. + +## Build + +Run `ng build core-ui` to build the project. The build artifacts will be stored in the `dist/` directory. + +## Publishing + +After building your library with `ng build core-ui`, go to the dist folder `cd dist/core-ui` and run `npm publish`. + +## Running unit tests + +Run `ng test core-ui` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. diff --git a/frontend/projects/core-ui/index.ts b/frontend/projects/core-ui/index.ts new file mode 100644 index 0000000..6dc56ac --- /dev/null +++ b/frontend/projects/core-ui/index.ts @@ -0,0 +1,4 @@ +/* + * Public API Surface of core-ui + */ +export * from './src/initializer.module'; diff --git a/frontend/projects/core-ui/karma.conf.js b/frontend/projects/core-ui/karma.conf.js new file mode 100644 index 0000000..22432dc --- /dev/null +++ b/frontend/projects/core-ui/karma.conf.js @@ -0,0 +1,41 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + jasmine: { + // you can add configuration options for Jasmine here + // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html + // for example, you can disable the random execution with `random: false` + // or set a specific seed with `seed: 4321` + }, + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + jasmineHtmlReporter: { + suppressAll: true // removes the duplicated traces + }, + coverageReporter: { + dir: require('path').join(__dirname, '../../coverage/core-ui'), + subdir: '.', + reporters: [{ type: 'html' }, { type: 'text-summary' }] + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/frontend/projects/core-ui/ng-package.json b/frontend/projects/core-ui/ng-package.json new file mode 100644 index 0000000..737839b --- /dev/null +++ b/frontend/projects/core-ui/ng-package.json @@ -0,0 +1,8 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/core-ui", + "lib": { + "entryFile": "index.ts" + }, + "deleteDestPath": false +} diff --git a/frontend/projects/core-ui/package.json b/frontend/projects/core-ui/package.json new file mode 100644 index 0000000..9a5d316 --- /dev/null +++ b/frontend/projects/core-ui/package.json @@ -0,0 +1,13 @@ +{ + "name": "@core-ui", + "version": "0.0.1", + "peerDependencies": { + "@angular/common": "^14.2.0", + "@angular/core": "^14.2.0", + "tailwindcss": "^2.2.19", + "ngx-webstorage": "^10.0.1" + }, + "dependencies": { + "tslib": "^2.3.0" + } +} diff --git a/frontend/projects/core-ui/src/constants/constants.injection-token.ts b/frontend/projects/core-ui/src/constants/constants.injection-token.ts new file mode 100644 index 0000000..e677b4a --- /dev/null +++ b/frontend/projects/core-ui/src/constants/constants.injection-token.ts @@ -0,0 +1 @@ +export const APP_ENV = 'HOST_ENV'; diff --git a/frontend/projects/core-ui/src/constants/index.ts b/frontend/projects/core-ui/src/constants/index.ts new file mode 100644 index 0000000..092df84 --- /dev/null +++ b/frontend/projects/core-ui/src/constants/index.ts @@ -0,0 +1 @@ +export * from './constants.injection-token'; diff --git a/frontend/projects/core-ui/src/constants/ng-package.json b/frontend/projects/core-ui/src/constants/ng-package.json new file mode 100644 index 0000000..1dc0b0b --- /dev/null +++ b/frontend/projects/core-ui/src/constants/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "index.ts" + } +} diff --git a/frontend/projects/core-ui/src/directives/has-any-authority.directive.ts b/frontend/projects/core-ui/src/directives/has-any-authority.directive.ts new file mode 100644 index 0000000..896a7cc --- /dev/null +++ b/frontend/projects/core-ui/src/directives/has-any-authority.directive.ts @@ -0,0 +1,39 @@ +import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core'; +import { PermissionService } from '@core-ui/services'; + +/** + * @whatItDoes Conditionally includes an HTML element if current user has any + * of the authorities passed as the `expression`. + * @howToUse + * ``` + * ... + * ... + * ``` + */ +@Directive({ + standalone: true, + selector: '[hasAnyAuthority]' +}) +export class HasAnyAuthorityDirective { + private permissions: string | string[] = []; + + constructor( + private permissionSvc: PermissionService, + private templateRef: TemplateRef, + private viewContainerRef: ViewContainerRef + ) {} + + @Input() + set hasAnyAuthority(value: string | string[]) { + this.permissions = value; + this.updateView(); + } + + private updateView(): void { + const hasAnyAuthority = this.permissionSvc.hasAuthorities(this.permissions); + this.viewContainerRef.clear(); + if (hasAnyAuthority) { + this.viewContainerRef.createEmbeddedView(this.templateRef); + } + } +} diff --git a/frontend/projects/core-ui/src/directives/index.ts b/frontend/projects/core-ui/src/directives/index.ts new file mode 100644 index 0000000..7085cbd --- /dev/null +++ b/frontend/projects/core-ui/src/directives/index.ts @@ -0,0 +1 @@ +export * from './has-any-authority.directive'; diff --git a/frontend/projects/core-ui/src/directives/ng-package.json b/frontend/projects/core-ui/src/directives/ng-package.json new file mode 100644 index 0000000..1dc0b0b --- /dev/null +++ b/frontend/projects/core-ui/src/directives/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "index.ts" + } +} diff --git a/frontend/projects/core-ui/src/guards/admin.guard.ts b/frontend/projects/core-ui/src/guards/admin.guard.ts new file mode 100644 index 0000000..706af37 --- /dev/null +++ b/frontend/projects/core-ui/src/guards/admin.guard.ts @@ -0,0 +1,76 @@ +import { Injectable } from '@angular/core'; +import { AuthGuard } from './auth.guard'; +import { ActivatedRouteSnapshot, CanLoad, Route, Router, RouterStateSnapshot, UrlSegment, UrlTree } from '@angular/router'; +import { Observable } from 'rxjs'; +import { RequesterService } from '@core-ui/services'; + +/** + * @description + * This is Admin guard. This guard implement with canActivate, canActivateChild and canLoad interface. + * This guard is extends auth + * + * @status injected in appModule + * @pubicApi + */ +@Injectable({ + providedIn: 'root' +}) +export class AdminGuard extends AuthGuard implements CanLoad { + constructor( + protected override requesterService: RequesterService, + protected override router: Router + ) { + super(requesterService, router); + } + + // canActivate for current guard + override canActivate( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): boolean | UrlTree | Observable | Promise { + super.canActivate(route, state); + if (this.checkAdmin()) { + return true; + } + return this.router.createUrlTree(['/403'], { + /* Removed unsupported properties by Angular migration: skipLocationChange. */ queryParams: { + url: state.url + } + }); + } + + // CanActivate for child route guard + override canActivateChild( + childRoute: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): boolean | UrlTree | Observable | Promise { + super.canActivateChild(childRoute, state); + if (this.checkAdmin()) { + return true; + } + return this.router.createUrlTree(['/403'], { + /* Removed unsupported properties by Angular migration: skipLocationChange. */ queryParams: { + url: state.url + } + }); + } + + // Can Load For feature module load + canLoad(route: Route, segments: UrlSegment[]): boolean | Promise | Observable { + if (this.checkAdmin()) { + return true; + } + this.router.navigate(['**'], { + skipLocationChange: true, + queryParams: { + url: route.path + } + }); + return false; + } + + protected checkAdmin(): boolean { + const requester = this.requesterService.get(); + return ['ADMIN', 'SUPER_ADMIN'].includes(requester?.userInfo?.user_type); + } +} diff --git a/frontend/projects/core-ui/src/guards/auth.guard.ts b/frontend/projects/core-ui/src/guards/auth.guard.ts new file mode 100644 index 0000000..4fc6860 --- /dev/null +++ b/frontend/projects/core-ui/src/guards/auth.guard.ts @@ -0,0 +1,54 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, Router, RouterStateSnapshot, UrlTree } from '@angular/router'; +import { RequesterService } from '@core-ui/services'; +import { Observable } from 'rxjs'; + +/** + * @description + * This is authentication guard. This guard implement with canActivate and canActivateChild interface. + * + * @status injected in appModule + * @pubicApi + */ +@Injectable({ + providedIn: 'root' +}) +export class AuthGuard implements CanActivate, CanActivateChild { + constructor( + protected requesterService: RequesterService, + protected router: Router + ) {} + + canActivate( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): boolean | UrlTree | Observable | Promise { + return this.checkAuthentication(state.url); + } + + canActivateChild( + childRoute: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): boolean | UrlTree | Observable | Promise { + return this.checkAuthentication(state.url); + } + + protected checkAuthentication(stateUrl?: string): boolean { + const requester = this.requesterService.get(); + + // Checking Authorization + if (!this.requesterService.isAuthenticated()) { + this.router.navigate(['/auth/login']); + return false; + } + + // Checking User Is Verification + // ? Don't place it requester service. + if (requester?.userInfo?.is_verified !== true) { + this.router.navigate(['/email-verification']); + return false; + } + + return true; + } +} diff --git a/frontend/projects/core-ui/src/guards/index.ts b/frontend/projects/core-ui/src/guards/index.ts new file mode 100644 index 0000000..5c443fe --- /dev/null +++ b/frontend/projects/core-ui/src/guards/index.ts @@ -0,0 +1,4 @@ +export * from './admin.guard'; +export * from './auth.guard'; +export * from './role.guard'; +export * from './role-guard.service'; diff --git a/frontend/projects/core-ui/src/guards/ng-package.json b/frontend/projects/core-ui/src/guards/ng-package.json new file mode 100644 index 0000000..1dc0b0b --- /dev/null +++ b/frontend/projects/core-ui/src/guards/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "index.ts" + } +} diff --git a/frontend/projects/core-ui/src/guards/role-guard.service.ts b/frontend/projects/core-ui/src/guards/role-guard.service.ts new file mode 100644 index 0000000..b20d317 --- /dev/null +++ b/frontend/projects/core-ui/src/guards/role-guard.service.ts @@ -0,0 +1,102 @@ +import { Injectable } from '@angular/core'; +import { + Router, + CanActivate, + ActivatedRouteSnapshot, + UrlTree, + RouterStateSnapshot, + CanActivateChild, + CanLoad, + Route, + UrlSegment +} from '@angular/router'; +import { Observable } from 'rxjs'; +import { map, take } from 'rxjs/operators'; +import { RequesterService, PermissionService } from '@core-ui/services'; +import { USER_ADMIN_ROLES } from '@core-ui/models'; + +/** + * @description Route Guard, Stable for CanActivate, CanActivateChild, CanLoad is Oon deployment + * @implements {CanActivate, CanActivateChild, CanLoad} + */ +@Injectable({ + providedIn: 'root' +}) +export class RoleGuardService implements CanActivate, CanActivateChild, CanLoad { + constructor( + private requesterService: RequesterService, + private permissionService: PermissionService, + private router: Router + ) {} + + canActivate( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): Observable | Promise | boolean | UrlTree { + return this._checkAuthorization(route, state); + } + + canActivateChild( + childRoute: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): boolean | UrlTree | Observable | Promise { + return this._checkAuthorization(childRoute, state); + } + + // !!! On Development Mode + canLoad(route: Route, segments: UrlSegment[]): boolean | Observable | Promise { + // console.log(route); + // console.log(segments); + return this._checkRolePermission(this.requesterService.get()?.userInfo?.user_type || '', route.data?.['permissions'] || []); + } + + /** + * @description checking authentication, + */ + private _checkAuthorization( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): Observable | Promise | boolean | UrlTree { + const requester = this.requesterService.get(); + // Checking Authorization + if (!this.requesterService.isAuthenticated()) { + this.router.navigate(['/auth/login']); + return false; + } + + // TODO: optimize it when userProfile data fetch + // Checking User Is Verification + // Don't place it requester service. + if (requester?.userInfo?.is_verified !== true) { + return this.router.navigate(['/email-verification']); + } + + // Check Permission + return this._checkRolePermission(requester.userInfo?.user_type || '', route.data['permissions'] || [], state.url); + } + + /** + * @description checking role and permissions + * @param userType: string, + * @param routePermission: string[] + * @param stateUrl: string + * @returns boolean || Observable + */ + private _checkRolePermission(userType: string, routePermission: string[], stateUrl?: string): boolean | Observable { + if (USER_ADMIN_ROLES.some(r => r === userType)) return true; + // Checking Non Admin Permission + return this.permissionService.getPermissions().pipe( + take(1), + map(permissions => { + if (routePermission.some((perm: string) => permissions.includes(perm))) return true; + this.router.navigate(['/403'], { + skipLocationChange: true, + queryParams: { + url: stateUrl + } + }); + return false; + }) + ); + } +} diff --git a/frontend/projects/core-ui/src/guards/role.guard.ts b/frontend/projects/core-ui/src/guards/role.guard.ts new file mode 100644 index 0000000..a536f3b --- /dev/null +++ b/frontend/projects/core-ui/src/guards/role.guard.ts @@ -0,0 +1,61 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router, RouterStateSnapshot, UrlTree } from '@angular/router'; +import { map, take } from 'rxjs/operators'; +import { Observable } from 'rxjs'; +import { AdminGuard } from './admin.guard'; +import { PermissionService } from '@core-ui/services'; +import { RequesterService } from '@core-ui/services'; + +/** + * @description + * This is Admin guard. This guard implement with canActivate, canActivateChild and canLoad interface. + * This guard is extends auth + * + * @status It's not used and not injected yet + * @development + */ +@Injectable({ + providedIn: 'root' +}) +export class RoleGuard extends AdminGuard { + constructor( + protected override requesterService: RequesterService, + protected override router: Router, + private permissionService: PermissionService + ) { + super(requesterService, router); + } + + override canActivate( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): boolean | UrlTree | Observable | Promise { + super.canActivate(route, state); + return this.checkRolePermission(route, state); + } + + override canActivateChild( + childRoute: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): boolean | UrlTree | Observable | Promise { + super.canActivateChild(childRoute, state); + return this.checkRolePermission(childRoute, state); + } + + checkRolePermission(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | Observable { + const validPermissions: string[] = route.data['permissions'] || []; + return this.permissionService.getPermissions().pipe( + take(1), + map((permissions: string[]) => { + if (validPermissions.some((perm: string) => permissions.includes(perm))) { + return true; + } + return this.router.createUrlTree(['/403'], { + /* Removed unsupported properties by Angular migration: skipLocationChange. */ queryParams: { + url: state.url + } + }); + }) + ); + } +} diff --git a/frontend/projects/core-ui/src/initializer.module.ts b/frontend/projects/core-ui/src/initializer.module.ts new file mode 100644 index 0000000..ff7a1d4 --- /dev/null +++ b/frontend/projects/core-ui/src/initializer.module.ts @@ -0,0 +1,18 @@ +import { HttpClient, HttpClientModule } from '@angular/common/http'; +import { APP_INITIALIZER, NgModule } from '@angular/core'; +import { CoreConfigService } from '@core-ui/services'; + +@NgModule({ + imports: [HttpClientModule], + providers: [ + { + provide: APP_INITIALIZER, + useFactory: (coreConfigService: CoreConfigService) => { + return () => coreConfigService.loadConfigurationData(); + }, + deps: [CoreConfigService, HttpClient], + multi: true + } + ] +}) +export class InitializerModule {} diff --git a/frontend/projects/core-ui/src/interceptors/auth.interceptor.ts b/frontend/projects/core-ui/src/interceptors/auth.interceptor.ts new file mode 100644 index 0000000..23b8f46 --- /dev/null +++ b/frontend/projects/core-ui/src/interceptors/auth.interceptor.ts @@ -0,0 +1,68 @@ +import { Inject, Injectable, Optional } from '@angular/core'; +import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { filter, switchMap, take } from 'rxjs/operators'; +import { APP_ENV } from '@core-ui/constants'; +import { IAppEnv } from '@core-ui/interfaces'; +import { RequesterService } from '@core-ui/services'; + +const MC_REFRESH_TOKEN = '/v1/auth/refresh-token'; + +@Injectable() +export class AuthInterceptor implements HttpInterceptor { + isRefreshing: boolean = false; // Prevent for multiple refresh token request + + constructor( + private requester: RequesterService, + @Optional() @Inject(APP_ENV) private _env: IAppEnv + ) {} + + intercept(request: HttpRequest, next: HttpHandler): Observable> { + const data = this.requester.get(); + if (data?.token) { + // INFO: APIs to ignore token request + if (request.url.includes(MC_REFRESH_TOKEN)) { + return next.handle(request); + } + + // INFO: Authentication APIs request + const accessToken = data.token; + if (this.requester.isAuthTokenValid(accessToken)) { + return next.handle(this.getAuthorizeRequest(request, accessToken)); + } + if (!this.isRefreshing) { + // Request For Refresh Token + this.isRefreshing = true; + return this.requester.getNewByRefreshToken().pipe( + take(1), + switchMap((res: any) => { + this.isRefreshing = false; + return next.handle(this.getAuthorizeRequest(request, res['data']?.accessToken)); + }) + ); + } + + // Pending For New Token + return this.requester.userData$.pipe( + filter(data => data?.token && typeof data?.token === 'string'), + take(1), + switchMap(data => { + return next.handle(this.getAuthorizeRequest(request, data?.token)); + }) + ); + } + return next.handle(request); + } + + /** + * @definition Middle man to pass token on request + * @param request HttpRequest + * @param accessToken accessToken + * @returns HttpRequest + */ + private getAuthorizeRequest(request: HttpRequest, accessToken: string): HttpRequest { + return request.clone({ + headers: request.headers.append('Authorization', `Bearer ${accessToken}`) + }); + } +} diff --git a/frontend/projects/core-ui/src/interceptors/errors.interceptor.ts b/frontend/projects/core-ui/src/interceptors/errors.interceptor.ts new file mode 100644 index 0000000..65148fb --- /dev/null +++ b/frontend/projects/core-ui/src/interceptors/errors.interceptor.ts @@ -0,0 +1,72 @@ +import { Injectable } from '@angular/core'; +import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'; +import { Observable, throwError } from 'rxjs'; +import { catchError } from 'rxjs/operators'; +import { Router } from '@angular/router'; +import { PermissionService, RequesterService } from '@core-ui/services'; + +@Injectable() +export class ErrorsInterceptor implements HttpInterceptor { + constructor( + private requesterSvc: RequesterService, + private permissionSvc: PermissionService, + private router: Router + ) {} + + intercept(request: HttpRequest, next: HttpHandler): Observable> { + return next.handle(request).pipe(catchError(res => this.errorHandler(res))); + } + + private errorHandler(response: any): Observable { + console.log('errorHandler: ', response); + const status: number = response.status; + let message = 'Bad Request'; // Default Message + switch (true) { + case status === 401: { + this.throwLogout(); + break; + } + case status === 403: { + const currentUser = this.requesterSvc.get(); + if (currentUser?.userInfo?.user_type === 'NON_ADMIN') { + if (response?.error?.path !== '/api/v1/current-user/permissions') { + // TODO: Need to handle 403 error from api error + // this.router.navigate(["/403"]); + this.permissionSvc.fetchUserPermissions().subscribe(); + break; + } + } + this.throwLogout(); + break; + } + case 500 <= status && status < 600: { + message = 'Internal Server Error'; + break; + } + } + + let error = response.error; + // eslint-disable-next-line no-prototype-builtins + while (error?.hasOwnProperty('error')) { + error = error.error; + } + if (error instanceof Blob) { + message = 'Something is wrong!!!'; + error = null; // Stop Next Checking + } + if (typeof error === 'object' && error !== null) { + const keys = Object.keys(error); + if (keys.some(item => item === 'message')) { + message = error['message']; + } + } else if (typeof error === 'string') { + message = error; + } + return throwError({ error: { message }, status, message }); + } + + private throwLogout(): void { + this.requesterSvc.clear(); + this.router.navigate(['/auth/login']); + } +} diff --git a/frontend/projects/core-ui/src/interceptors/index.ts b/frontend/projects/core-ui/src/interceptors/index.ts new file mode 100644 index 0000000..e6a7174 --- /dev/null +++ b/frontend/projects/core-ui/src/interceptors/index.ts @@ -0,0 +1,2 @@ +export * from './auth.interceptor'; +export * from './errors.interceptor'; diff --git a/frontend/projects/core-ui/src/interceptors/ng-package.json b/frontend/projects/core-ui/src/interceptors/ng-package.json new file mode 100644 index 0000000..1dc0b0b --- /dev/null +++ b/frontend/projects/core-ui/src/interceptors/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "index.ts" + } +} diff --git a/frontend/projects/core-ui/src/interfaces/deep-partial.type.ts b/frontend/projects/core-ui/src/interfaces/deep-partial.type.ts new file mode 100644 index 0000000..3b64e05 --- /dev/null +++ b/frontend/projects/core-ui/src/interfaces/deep-partial.type.ts @@ -0,0 +1,7 @@ +export type DeepPartial = { + [P in keyof T]?: T[P] extends Array + ? Array> + : T[P] extends ReadonlyArray + ? ReadonlyArray> + : DeepPartial; +}; diff --git a/frontend/projects/core-ui/src/interfaces/environment.ts b/frontend/projects/core-ui/src/interfaces/environment.ts new file mode 100644 index 0000000..9e93a76 --- /dev/null +++ b/frontend/projects/core-ui/src/interfaces/environment.ts @@ -0,0 +1,5 @@ +export interface IAppEnv { + production: boolean; + // Endpoints + apiEndPoint: string; +} diff --git a/frontend/projects/core-ui/src/interfaces/index.ts b/frontend/projects/core-ui/src/interfaces/index.ts new file mode 100644 index 0000000..06497c3 --- /dev/null +++ b/frontend/projects/core-ui/src/interfaces/index.ts @@ -0,0 +1,2 @@ +export * from './deep-partial.type'; +export * from './environment'; diff --git a/frontend/projects/core-ui/src/interfaces/ng-package.json b/frontend/projects/core-ui/src/interfaces/ng-package.json new file mode 100644 index 0000000..1dc0b0b --- /dev/null +++ b/frontend/projects/core-ui/src/interfaces/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "index.ts" + } +} diff --git a/frontend/projects/core-ui/src/models/index.ts b/frontend/projects/core-ui/src/models/index.ts new file mode 100644 index 0000000..2685a6f --- /dev/null +++ b/frontend/projects/core-ui/src/models/index.ts @@ -0,0 +1 @@ +export * from './user-role'; diff --git a/frontend/projects/core-ui/src/models/ng-package.json b/frontend/projects/core-ui/src/models/ng-package.json new file mode 100644 index 0000000..1dc0b0b --- /dev/null +++ b/frontend/projects/core-ui/src/models/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "index.ts" + } +} diff --git a/frontend/projects/core-ui/src/models/user-role.ts b/frontend/projects/core-ui/src/models/user-role.ts new file mode 100644 index 0000000..422784b --- /dev/null +++ b/frontend/projects/core-ui/src/models/user-role.ts @@ -0,0 +1 @@ +export const USER_ADMIN_ROLES = ['ADMIN', 'SUPER_ADMIN'] as const; diff --git a/frontend/projects/core-ui/src/services/core-config/core-config.interfaces.ts b/frontend/projects/core-ui/src/services/core-config/core-config.interfaces.ts new file mode 100644 index 0000000..0c1016b --- /dev/null +++ b/frontend/projects/core-ui/src/services/core-config/core-config.interfaces.ts @@ -0,0 +1,33 @@ +export enum Theme { + DARK = 'DARK', + LIGHT = 'LIGHT', + LIGHT_PINK = 'LIGHT_PINK' +} + +export interface ISsoConfig { + type: string; + authorizeURI: string; + clientID: string; + clientSecret: string; + publicKey: string; +} + +export interface ICoreConfig { + id: string; + updateDate: string; + updatedBy: string; + status: string; + // SSO + ssoEnabled: boolean; + sso: ISsoConfig | null; + //? System Setting + // - Theme + webTheme: Theme; + // - Logo + logoUrl: string | null; + favicon: string | null; + name: string | null; + // - Other Config + passwordLength: number; + domains?: string[] | null; +} diff --git a/frontend/projects/core-ui/src/services/core-config/core-config.service.ts b/frontend/projects/core-ui/src/services/core-config/core-config.service.ts new file mode 100644 index 0000000..1dec36c --- /dev/null +++ b/frontend/projects/core-ui/src/services/core-config/core-config.service.ts @@ -0,0 +1,45 @@ +import { Inject, Injectable, Optional } from '@angular/core'; +import { BehaviorSubject, Observable, of } from 'rxjs'; +import { filter } from 'rxjs/operators'; + +import { DeepPartial } from '@core-ui/interfaces'; +import { mergeDeep } from '@core-ui/utils'; +import { APP_ENV } from '@core-ui/constants'; +import { IAppEnv } from '@core-ui/interfaces'; + +import { ICoreConfig, Theme } from './core-config.interfaces'; +import { CoreConfig } from './core-config'; +import { LOCAL_STORAGE_KEY } from '../requester.service'; + +@Injectable({ providedIn: 'root' }) +export class CoreConfigService { + private _generalInfoSubject = new BehaviorSubject(null); + readonly generalInfo$: Observable = this._generalInfoSubject.asObservable().pipe(filter(config => !!config)); + + constructor(@Optional() @Inject(APP_ENV) private _env: IAppEnv) {} + + // Core Config + updateGeneralInfo(data: DeepPartial): void { + this._generalInfoSubject.next(mergeDeep(this._generalInfoSubject.value, data, true)); + } + get generalInfoSnapshot(): ICoreConfig | null { + return this._generalInfoSubject.value; + } + // Theming + updateTheme(theme: Theme): void { + this.updateGeneralInfo({ webTheme: theme }); + } + + loadConfigurationData(): Observable { + const _conf = new CoreConfig(); + const loc = localStorage.getItem(LOCAL_STORAGE_KEY); + if (loc) { + const currentUser = JSON.parse(loc as string); + _conf.webTheme = currentUser?.userInfo?.webThemePreference; + } else { + _conf.webTheme = Theme.DARK; + } + this.updateGeneralInfo(_conf); + return of(_conf); + } +} diff --git a/frontend/projects/core-ui/src/services/core-config/core-config.ts b/frontend/projects/core-ui/src/services/core-config/core-config.ts new file mode 100644 index 0000000..00d3b6c --- /dev/null +++ b/frontend/projects/core-ui/src/services/core-config/core-config.ts @@ -0,0 +1,21 @@ +import { ICoreConfig, ISsoConfig, Theme } from './core-config.interfaces'; + +export class CoreConfig implements ICoreConfig { + id: string = ''; + updateDate!: string; + updatedBy!: string; + status!: string; + // Theme + webTheme!: Theme; + // SSO + ssoEnabled: boolean = false; + sso: ISsoConfig | null = null; + // System Setting + // - Logo + logoUrl: string = ''; + favicon: string = ''; + name: string = ''; + // - Other Config + passwordLength: number = 8; + // domains: string[] = []; +} diff --git a/frontend/projects/core-ui/src/services/core-config/index.ts b/frontend/projects/core-ui/src/services/core-config/index.ts new file mode 100644 index 0000000..7b21085 --- /dev/null +++ b/frontend/projects/core-ui/src/services/core-config/index.ts @@ -0,0 +1,3 @@ +export * from './core-config'; +export * from './core-config.interfaces'; +export * from './core-config.service'; diff --git a/frontend/projects/core-ui/src/services/http.service.ts b/frontend/projects/core-ui/src/services/http.service.ts new file mode 100644 index 0000000..1a32d71 --- /dev/null +++ b/frontend/projects/core-ui/src/services/http.service.ts @@ -0,0 +1,71 @@ +import { Inject, Injectable, Optional } from '@angular/core'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { APP_ENV } from '@core-ui/constants'; +import { IAppEnv } from '@core-ui/interfaces'; + +/** + * @description Http Service is MultiCluster http entrypoint + */ +@Injectable({ + providedIn: 'root' +}) +export class HttpService { + apiBaseUrl: string; + + constructor( + private http: HttpClient, + @Optional() @Inject(APP_ENV) private _env: IAppEnv + ) { + this.apiBaseUrl = _env?.apiEndPoint; + } + + get(url: string, queryParams?: any, responseType?: any): Observable { + const queryParameters = queryParams ? queryParams : {}; + const responseTypes = responseType ? responseType : null; + + const httpOptions = { + headers: new HttpHeaders({ 'Content-Type': 'application/json' }), + params: queryParameters, + responseType: responseTypes + }; + + return this.http.get(this.apiBaseUrl + url, httpOptions); + } + + post(url: string, data: any, queryParams?: any): Observable { + const httpOptions = { + headers: new HttpHeaders({ 'Content-Type': 'application/json' }), + params: queryParams || {} + }; + const body = JSON.stringify(data); + return this.http.post(this.apiBaseUrl + url, body, httpOptions); + } + + put(url: string, data: any, queryParams?: any): Observable { + const queryParameters = queryParams ? queryParams : {}; + const httpOptions = { + headers: new HttpHeaders({ 'Content-Type': 'application/json' }), + params: queryParameters + }; + const body = JSON.stringify(data); + return this.http.put(this.apiBaseUrl + url, body, httpOptions); + } + + delete(url: string, queryParams?: any): Observable { + const queryParameters = queryParams ? queryParams : {}; + const httpOptions = { + headers: new HttpHeaders({ 'Content-Type': 'application/json' }), + params: queryParameters + }; + return this.http.delete(this.apiBaseUrl + url, httpOptions); + } + + upload(url: string, payload: any): Observable { + const httpOptions = { + headers: new HttpHeaders({ Accept: 'application/json' }) + }; + const body = JSON.stringify(payload); + return this.http.post(this.apiBaseUrl + url, body, httpOptions); + } +} diff --git a/frontend/projects/core-ui/src/services/index.ts b/frontend/projects/core-ui/src/services/index.ts new file mode 100644 index 0000000..7e1a213 --- /dev/null +++ b/frontend/projects/core-ui/src/services/index.ts @@ -0,0 +1 @@ +export * from './public-api'; diff --git a/frontend/projects/core-ui/src/services/ng-package.json b/frontend/projects/core-ui/src/services/ng-package.json new file mode 100644 index 0000000..1dc0b0b --- /dev/null +++ b/frontend/projects/core-ui/src/services/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "index.ts" + } +} diff --git a/frontend/projects/core-ui/src/services/permission.service.ts b/frontend/projects/core-ui/src/services/permission.service.ts new file mode 100644 index 0000000..698f82a --- /dev/null +++ b/frontend/projects/core-ui/src/services/permission.service.ts @@ -0,0 +1,68 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, Observable, of } from 'rxjs'; +import { map, switchMap } from 'rxjs/operators'; +import { RequesterService } from './requester.service'; +import { HttpService } from './http.service'; + +@Injectable({ + providedIn: 'root' +}) +export class PermissionService { + private userPermissions = new BehaviorSubject([]); + userPermissions$: Observable = this.userPermissions.asObservable(); + + constructor( + private _httpService: HttpService, + private _requesterService: RequesterService + ) {} + + getPermissions(force: boolean = false): Observable { + return this.userPermissions$.pipe( + switchMap((permissions: string[]) => { + if (!permissions.length || force) { + return this.fetchUserPermissions(); + } + return of(permissions); + }) + ); + } + + get userPermissionsSnapshot(): string[] { + return this.userPermissions.value; + } + + loadUserPermissions(permissions: string[]): void { + this.userPermissions.next(permissions); + } + + /** + * @description checking authorites for admin and non-admin permission + * @param {string | string[]} permission - permission name + * @return {boolean} boolean + */ + hasAuthorities(permission: string[] | string): boolean { + if (this._requesterService.isAdmin) return true; + // Check permission + const userPermissions = this.userPermissionsSnapshot; + if (typeof permission === 'string') return userPermissions.includes(permission); + return permission.some((perm: string) => userPermissions.includes(perm)); + } + + // Dep + fetchUserPermissions(): Observable { + return this._httpService.get('/v1//permissions/users').pipe( + map(res => { + const _permissions: string[] = ['*']; + Object.entries(res).map(([_, value]) => { + if (value instanceof Array && value.length) { + value.forEach(item => { + _permissions.push(item.name); + }); + } + }); + this.loadUserPermissions(_permissions); + return _permissions; + }) + ); + } +} diff --git a/frontend/projects/core-ui/src/services/public-api.ts b/frontend/projects/core-ui/src/services/public-api.ts new file mode 100644 index 0000000..ca330ab --- /dev/null +++ b/frontend/projects/core-ui/src/services/public-api.ts @@ -0,0 +1,7 @@ +// Config +export * from './core-config'; +// User Data +export * from './requester.service'; +export * from './permission.service'; +// Fetch Data +export * from './http.service'; diff --git a/frontend/projects/core-ui/src/services/requester.service.ts b/frontend/projects/core-ui/src/services/requester.service.ts new file mode 100644 index 0000000..278b0d1 --- /dev/null +++ b/frontend/projects/core-ui/src/services/requester.service.ts @@ -0,0 +1,175 @@ +import { Injectable } from '@angular/core'; +import { Observable, BehaviorSubject, of } from 'rxjs'; +import jwtDecode from 'jwt-decode'; +import { map } from 'rxjs/operators'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { Router } from '@angular/router'; +import { USER_ADMIN_ROLES } from '@core-ui/models'; +import { HttpService } from './http.service'; + +const MC_USER_INFO = '/v1/users/profile'; +const MC_REFRESH_TOKEN = '/auth/refresh-token'; + +export const LOCAL_STORAGE_KEY = 'ngx-webstorage|kc-requester'; + +@Injectable({ + providedIn: 'root' +}) +export class RequesterService { + private userDataSubject = new BehaviorSubject(null); + userData$: Observable = this.userDataSubject.asObservable(); + + timeoutId: any; + + constructor( + private httpService: HttpService, + private snackBar: MatSnackBar, + private router: Router + ) { + const loc = localStorage.getItem(LOCAL_STORAGE_KEY); + if (loc) { + const currentUser = JSON.parse(loc as string); + if (currentUser) { + // ? Checking User Status + if (currentUser?.userInfo?.user_is_active === false) { + if (currentUser?.userInfo?.user_type === 'NON_ADMIN') { + this.snackBar.open('Your account is deactivated. Please contact your admin', 'Close', { + duration: 10000 + }); + } else { + this.snackBar.open('Your account is deactivated', 'Close', { + duration: 10000 + }); + } + this.clear(); + this.router.navigate(['/auth/login']); + return; + } + + this.tokenExpireSetTimeout(currentUser); + this.userDataSubject.next(currentUser); + } + } + } + + get() { + return this.userDataSubject.value; + } + + save(user: any): void { + localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(user)); + this.loadUserData(user); + if (user?.refreshToken) { + this.tokenExpireSetTimeout(user); + } else { + if (this.timeoutId) { + clearTimeout(this.timeoutId); + } + } + } + + clear() { + localStorage.removeItem(LOCAL_STORAGE_KEY); + this.loadUserData(null); + if (this.timeoutId) { + clearTimeout(this.timeoutId); + } + } + + /** + * @param {any} data - User authentication data + */ + loadUserData(data: any): void { + this.userDataSubject.next(data); + } + + isAuthTokenValid(accessToken: string): boolean { + return this._getTokenExpireTime(accessToken) * 1000 > Date.now(); + } + /** + * @param {string} token - JWT ACCESS Token + * @returns {any} {username: string, userType: string} + */ + getUserDataFromToken(token: string): any { + const decoded: any = jwtDecode(token); + const data = { + username: decoded.username + // userType: decoded.authorities + }; + return data; + } + + /** + * @param {string} token - JWT ACCESS Token + * @return {number} expire time as millisecond + */ + _getTokenExpireTime(token: string): number { + try { + const decoded: any = jwtDecode(token); + // default decoded exp format is second + return decoded.exp; + } catch (err) { + console.log('err', err); + } + return 0; + } + + tokenExpireSetTimeout(user: any): void { + if (this.timeoutId) { + clearTimeout(this.timeoutId); + } + const token = user.token; + const refreshToken = user.refreshToken; + if (refreshToken) { + const expireTime = this._getTokenExpireTime(token); + // console.log(new Date(expireTime * 1000)) + const duration = expireTime * 1000 - new Date().getTime(); + this.timeoutId = setTimeout(() => { + this.getNewByRefreshToken().subscribe(); + }, duration); + } + } + + get isAdmin(): boolean { + const userType = this.get()?.userInfo?.user_type; + return USER_ADMIN_ROLES.some(r => r === userType); + } + + public isAuthenticated(): boolean { + return !!this.userDataSubject.value?.token; + } + + // APIs + getNewByRefreshToken(): Observable { + const currentData = this.get(); + if (!currentData?.refreshToken) { + if (this.timeoutId) { + clearTimeout(this.timeoutId); + } + return of(false); + } + const refresh_token = currentData.refreshToken; + const expireTime = this._getTokenExpireTime(refresh_token); + if (new Date().getTime() > expireTime * 1000) { + this.snackBar.open('Your session has been expired! Please Sign In Again.', 'close', { + duration: 5000, + panelClass: ['snackbar-dark'] + }); + this.clear(); + this.router.navigate(['/auth/login']); + return of(false); + } + return this.httpService.post(MC_REFRESH_TOKEN, { refresh_token }).pipe( + map((res: any) => { + currentData['token'] = res.access_token; + if (res.refresh_token) currentData['refreshToken'] = res.refresh_token; + this.save(currentData); + return res; + }) + ); + } + + getUserProfile(): Observable { + return this.httpService.get(MC_USER_INFO); + } +} diff --git a/frontend/projects/core-ui/src/test.ts b/frontend/projects/core-ui/src/test.ts new file mode 100644 index 0000000..59f2f3c --- /dev/null +++ b/frontend/projects/core-ui/src/test.ts @@ -0,0 +1,25 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js'; +import 'zone.js/testing'; +import { getTestBed } from '@angular/core/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; + +declare const require: { + context( + path: string, + deep?: boolean, + filter?: RegExp + ): { + (id: string): T; + keys(): string[]; + }; +}; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting()); + +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().forEach(context); diff --git a/frontend/projects/core-ui/src/utils/flatten-deep.ts b/frontend/projects/core-ui/src/utils/flatten-deep.ts new file mode 100644 index 0000000..cb212c9 --- /dev/null +++ b/frontend/projects/core-ui/src/utils/flatten-deep.ts @@ -0,0 +1,3 @@ +export function flattenDeep(array: T[]): T[] { + return array.reduce((acc: T[], val) => (Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val)), []); +} diff --git a/frontend/projects/core-ui/src/utils/flatten-object.ts b/frontend/projects/core-ui/src/utils/flatten-object.ts new file mode 100644 index 0000000..1cb1bec --- /dev/null +++ b/frontend/projects/core-ui/src/utils/flatten-object.ts @@ -0,0 +1,29 @@ +export function flattenObject(obj: { [key: string | number]: any }, parentKey = '', result = {}) { + // Iterate through each property in the object + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + // Create a new key combining the parent key with the current key + const newKey = parentKey ? `${parentKey}.${key}` : key; + + // Check if the value is an object + if (typeof obj[key] === 'object' && obj[key] !== null) { + // Handle arrays and objects recursively + if (Array.isArray(obj[key])) { + obj[key].forEach((item, index) => { + if (typeof item === 'string') { + result[`${newKey}[${index}]`] = item; + } else { + flattenObject(item, `${newKey}[${index}]`, result); + } + }); + } else { + flattenObject(obj[key], newKey, result); + } + } else { + // Otherwise, directly assign the key-value pair to the result + result[newKey] = obj[key]; + } + } + } + return result; +} diff --git a/frontend/projects/core-ui/src/utils/index.ts b/frontend/projects/core-ui/src/utils/index.ts new file mode 100644 index 0000000..7880a9f --- /dev/null +++ b/frontend/projects/core-ui/src/utils/index.ts @@ -0,0 +1,6 @@ +export { flattenObject } from './flatten-object'; +export * from './flatten-deep'; +export * from './merge-deep'; +export * from './track-by'; +export * from './to-query'; +export * from './to-params'; diff --git a/frontend/projects/core-ui/src/utils/merge-deep.ts b/frontend/projects/core-ui/src/utils/merge-deep.ts new file mode 100644 index 0000000..275de6e --- /dev/null +++ b/frontend/projects/core-ui/src/utils/merge-deep.ts @@ -0,0 +1,32 @@ +/** + * Performs a deep merge of `source` into `target`. + * Mutates `target` only but not its objects and arrays. + * + * @author inspired by [jhildenbiddle](https://stackoverflow.com/a/48218209). + */ +export function mergeDeep(target: any, source: any, onlyNewArray: boolean = false) { + const isObject = (obj: any) => obj && typeof obj === 'object'; + + if (!isObject(target) || !isObject(source)) { + return source; + } + + Object.keys(source).forEach(key => { + const targetValue = target[key]; + const sourceValue = source[key]; + + if (Array.isArray(targetValue) && Array.isArray(sourceValue)) { + if (onlyNewArray) { + target[key] = sourceValue; + } else { + target[key] = targetValue.concat(sourceValue); + } + } else if (isObject(targetValue) && isObject(sourceValue)) { + target[key] = mergeDeep(Object.assign({}, targetValue), sourceValue); + } else { + target[key] = sourceValue; + } + }); + + return target; +} diff --git a/frontend/projects/core-ui/src/utils/ng-package.json b/frontend/projects/core-ui/src/utils/ng-package.json new file mode 100644 index 0000000..1dc0b0b --- /dev/null +++ b/frontend/projects/core-ui/src/utils/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "index.ts" + } +} diff --git a/frontend/projects/core-ui/src/utils/to-params.ts b/frontend/projects/core-ui/src/utils/to-params.ts new file mode 100644 index 0000000..27754e8 --- /dev/null +++ b/frontend/projects/core-ui/src/utils/to-params.ts @@ -0,0 +1,11 @@ +export function toParams(query: string) { + const q = query.replace(/^\??\//, ''); + + return q.split('&').reduce((values: any, param) => { + const [key, value] = param.split('='); + + values[key] = value; + + return values; + }, {}); +} diff --git a/frontend/projects/core-ui/src/utils/to-query.ts b/frontend/projects/core-ui/src/utils/to-query.ts new file mode 100644 index 0000000..76c16b8 --- /dev/null +++ b/frontend/projects/core-ui/src/utils/to-query.ts @@ -0,0 +1,13 @@ +export function toQuery(params: any, delimiter = '&') { + const keys = Object.keys(params); + + return keys.reduce((str, key, index) => { + let query = `${str}${key}=${params[key]}`; + + if (index < keys.length - 1) { + query += delimiter; + } + + return query; + }, ''); +} diff --git a/frontend/projects/core-ui/src/utils/track-by.ts b/frontend/projects/core-ui/src/utils/track-by.ts new file mode 100644 index 0000000..8abe1f4 --- /dev/null +++ b/frontend/projects/core-ui/src/utils/track-by.ts @@ -0,0 +1,25 @@ +import { KeyValue } from '@angular/common'; + +export function trackByRoute(index: number, item: T) { + return item.route; +} + +export function trackById(index: number, item: T) { + return item.id; +} + +export function trackByKey(index: number, item: KeyValue) { + return item.key; +} + +export function trackByValue(index: number, value: string) { + return value; +} + +export function trackByLabel(index: number, value: T) { + return value.label; +} + +export function trackByIndex(index: number, item: T) { + return index; +} diff --git a/frontend/projects/core-ui/tsconfig.lib.json b/frontend/projects/core-ui/tsconfig.lib.json new file mode 100644 index 0000000..305b0b9 --- /dev/null +++ b/frontend/projects/core-ui/tsconfig.lib.json @@ -0,0 +1,12 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": ["src/test.ts", "**/*.spec.ts"] +} diff --git a/frontend/projects/core-ui/tsconfig.lib.prod.json b/frontend/projects/core-ui/tsconfig.lib.prod.json new file mode 100644 index 0000000..06de549 --- /dev/null +++ b/frontend/projects/core-ui/tsconfig.lib.prod.json @@ -0,0 +1,10 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.lib.json", + "compilerOptions": { + "declarationMap": false + }, + "angularCompilerOptions": { + "compilationMode": "partial" + } +} diff --git a/frontend/projects/core-ui/tsconfig.spec.json b/frontend/projects/core-ui/tsconfig.spec.json new file mode 100644 index 0000000..fafd1e1 --- /dev/null +++ b/frontend/projects/core-ui/tsconfig.spec.json @@ -0,0 +1,10 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": ["jasmine"] + }, + "files": ["src/test.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] +} diff --git a/frontend/projects/sdk-ui/README.md b/frontend/projects/sdk-ui/README.md new file mode 100644 index 0000000..5fb285f --- /dev/null +++ b/frontend/projects/sdk-ui/README.md @@ -0,0 +1,25 @@ +# SdkUi + +This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 14.2.0. + +## Code scaffolding + +Run `ng generate component component-name --project sdk-ui` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project sdk-ui`. + +> Note: Don't forget to add `--project sdk-ui` or else it will be added to the default project in your `angular.json` file. + +## Build + +Run `ng build sdk-ui` to build the project. The build artifacts will be stored in the `dist/` directory. + +## Publishing + +After building your library with `ng build sdk-ui`, go to the dist folder `cd dist/sdk-ui` and run `npm publish`. + +## Running unit tests + +Run `ng test sdk-ui` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. diff --git a/frontend/projects/sdk-ui/assets/images/favicon_klovercloud.ico b/frontend/projects/sdk-ui/assets/images/favicon_klovercloud.ico new file mode 100644 index 0000000000000000000000000000000000000000..0018102d3d121f982444799946627f6389313f54 GIT binary patch literal 1150 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 + + + + + + + + + + + + + + + diff --git a/frontend/projects/sdk-ui/assets/images/logo-favicon.ico b/frontend/projects/sdk-ui/assets/images/logo-favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..9435f094498d86e810939f0f33b40cca677fb1ce GIT binary patch literal 93062 zcmeHQ349bq)^7->=<4cv0Fsl0gxm*5AdrJ397!Mv;Ru9FNJ6;p8xk&I{Qw076ggHA zPy`ef{Qa2-m6!y zUP)3N{9C(L!vFr#gwb`R`y@#U#SbJYqK=M^L+P<0_`|z-IpF1hmjhl7csbxC4xBo5 zO1kjdZ&FHHnom|vPJ_~sBX7&>)~$ZK_U(PX`26!aA0IvHq&IsXTbnqrV9_FJ`HB@j zz){mS?b@Zb3JV(%6%(`EKQQpw7Jhzvuz&qQU*BDR0Rh`0qoY@bwr)KxzD=9VPRYr> zlc!8+&?`4r`kxnTwFwe7*M(#bV@%5F+4EjtsAq7iR%?NukAS0Jnzv|i4L_#vyMgO| z1I~`M3<=p95gA#OlA7wfaPi{0z?scu^4?f;IWT(cSYG(lE?w@6jEX7^Y}xVIVd>z71&_O2ooY-p#;lqs!?)}ScIWTSdbn9X7|2!&>{e){yjL2i_duFhVs7Q`WHTn_d`X)9$K7*LJ;?YOlmY3dw={PWT+BA+S zv{^pdu1b}hg3il~j$(iBm&Nh)6YydVOO|MaF~Zl;hjQ7})FkN70H%|D%Jvt0XKy5@ zrZ$J3_BNjzb6{jynRNZywK{rCol=XbzHQ>z2Sa*t`D6(@YUqT=Gb8iZx||Fa71GM8 zUWBc66=RI^wr<^8ci^BwZp>NFE!vEkGo|ClkJpV$NFX_-3R7rTHn4qL_Mc%rA#b$F zC`&lg>CN73dqEEt4QyGHTcoEG+O~}f2@REg{q-Mj0SjT+^K-1W>N4IMU2 zdU(ka!qgByfB$c-VT#(AP3icMst?x(XvpHQl@%Jf}i{c?Vr=+xk-15vu zbhBDNgg!drr8uS_r&M981u!+bb4PX@egdb+Dd0)SEqeZ^!*f}7Y_y`SMRrzrWF&Wt zkUsZr)yIM2k`ign+O?W7H5QoqqNKOeF(t4?zKU(VyRjhnSe5i4#;13}=hk>&QBn0V z)x+ORV>7wAxfJJ8tVK>4FeQ^IqWztfR^=6JN3Xnc z60B0w(#V&f$)3_-D%tJil#o|vfve$G>?_2-@5?VJXhgc-yE&Ev9g~uzF6rqFT8D?L z?)SMnrbr)uQJl}Z#>6Pv?da=nLOi0+`~?df%Ty14TD!zV3G<*D8Xc-(liy-jUp+g>y1jkjM#_};IxDhZl5B;Hw!e4G_PnZfu z49XJ3m%E#dE_9#RQ!MF<9%~9TIu29FWgsC=gyfWJOoartWGk{V*msCU zai@Ntz>?Tg**=F3%!-XsjA_u14~BSSWgLSm(tWVg2~*{2$1v7|pMpFIQhG*)HaS(JFqMZG=UmnW^K@vwk0qUs z@98q;4wVoT=FXev!HBTG>X=V1WpwST4O7s4HAPO5{`hSPy;z`Oz`nS08f)CgEHCUGUe^o@{ior)mI@wbsr)Z3MU3MD!tB4U*(0_y}|A2rK@Y#jK zU&r$X+Q(hbyqo;!dHMO;Fja%>DZ&+DYJE;B3sr$B$m%Qbg-)Tl*)wO)_DoRNS!;@Q z>0MBuJ}!aeR1L$_kHFM3xf!f=%a)3Ey3qIN1Mb6^&AqU#?BuRz-cGu&Pv5@k;}Q(I zuV(lXgs*B#UIyl(hCufz#w>6<9=7@k_(40|jr@UMR#kZ>Fzl!`@(*Z>9X4R9X4q5Q zrh<>^dCYH)Q89O(WEJ$^PlydIBK=pa&wFDBi#_gEl2gcOuFam}{l1!oshxeYSwdKA zRk{zD`W5+XC&MPFN8g-x)5ZbKHafoJFxXS8vNIXQl(_TQjL>`JOW)mBJ*F_0egXc^ zS<|LXYuK-Ue{Br)UM-Q0UZBB7C*44ClzrN^HxiB+@?dzY-zAV;_ zvsKqTEg_%8o-lO)n4%n!O5-!4ZqR)f;ZImH?4gHl_vS;^2q;{x)kYV5m+#3pO>ITF zVkyUG2x4J+#>KFenAiC~6mav7<+pMSN$S+; zFUT9OjiKJFbvC+&`F&ckWbS&x7v-2;(LII73^*HGwqOdmL$^Ri-G{g`Y1#7SUZiN? z0L3L>yic_s-5f@2rO|kro%&SsfW5vuxqgel~) zdJ%pWUvIu4?cYg{tSo7GadCb4jmH2}=at&t+&Pjp4>ZTGnSL)jCLL!jUP=B;x)$~^ z8`3_3ee#gw^3T#7ntu<;VZG27wK7Lp#O)ELc6aU8&9})NcX(r7G{S1i)Tul_I`R$| zA*b2*@-|jFrmv@r1KY;3k2$vN>nqAJr558PrwCK`H*G5I+OYt9L>ydw;0yeh3>dbpy8f0px%QM%<^gXz^mt28j)| z?*N+$@j~~*E`7xkj^uR0Q(&MUD=z534sRIBem^{wu@7hKen)0;JQ1dhen)iY31`QF zzY5@sFxeEcPX265$E34z6kFnNVDR$0GuZysMJyvJ(rQev;oZPiPFx)37?Ulp zPA8I$F6=3lx{u2#fvHWKH+wcfY^*)jpOWB@iGlvJx;7SJs#BZR?Dchnxqf3Lg9KKz z?g@*y|KlB{tUv58wKf;Yt&Hdx_U52oRW6n(H{*K&)KEWX& zD}+q2w5N6_Op)GWTIG`x<{-OH?j6kvv)X9Vi5y!+ge~*AYHh$2)7w*_4>W5gjh{Ht zHl}*-lHgAue^mtfe~Pv``47TFgV@U}2RIf}0&g5!V_^R$!f)lP${#^GEfwR62Mc@L zBDZY86l}}NPRYsPwEp<{^XI+ju#p36*RA7s0$Z~nqi$G|Q$!~p!m^3o*_HQZ*sk{k zhAi!Yt#9^^XJ!48RAY-|Xy=G0{3~YUOZ~_|#f2vxYNVa_E z@YYz{G@ZvpsKgZ0V=DSjcikn?Sc7-7j{_r$i}?evUdTB37Oq>u75UM-b&BHcY**h; zD+YnB?_Zt3#sgcVgVp#?2}^#+!A2y*TV<#<3A>`MR-5?VAWvDwEUL-HrP{j>d^Xz zUQ{@U10%7{V#&yncOqZ?Tb6iFbkc#ZtRBeNM|SwBY{8Vc2iW@Utto8j*sd%PWpMzu zjBND5-kekpLX_??VHod1Kd>omtB)<=irO$HBA9)$bENBRD}g8ZUWP5gxgFTjVG1_7 zPlE;&U*=GrdLJfnzZLq`!LY4PTf!CTz$ExV&!F$`Qrk+7DRB&JT{twA`#NmYiG-<2 z^i!hmy8CXadygJo7&w6gm_sQcr(SENxIMyEN@4^%_r@gW_(BC{)b4?;Ki;0kmQU=# z<88FaE&ss4V~F#N#T<7DF)vQwsP~b?fk-X5dYy1pP4<;3=1`7{25hOf&sGtuF<(7A{)k zG~RmhgRz#igx>?;^-)W>B0Uq;x+VMXbEVa5x0}i=8MfBU$YHH9ZmBjFf@3Qofy*uL zT7ZuK0;Wx$E=`^~^$z$MUbloRqLaV-xut#F4_6#pvv>^GQ}c2;wzSAC#9HT&P8>CQ zwBwoU!B2eSjW>8KJI3&zP{I}Y+b0c5W>=j#-fT`Dsih%a=kmMLd5j^+EnBcPWy%x} zMuKCjK5^0{{=lf1m=f4n*DPU+^h*cKcc8d+9v7;%yjKVeTul2$NiH%`oUhE!e_bQ|{EldIpYRt_MG*N}p3TA~JF~bm1j)m=ZMd zk@oGDz~^eYtv)n^Ee-b8G0YoDAvk!)ckKTtXdRmlNl6dFAN`@gkkX!FIVm>E{jp_} zEpNb9X<3>5%=O?W^wsCWM2sKBVJXTi!dnZ(LX9u#jM%7&H40lAbmB3L^`sCaX3XMC zQF<^s?5jG~2b8+?=s|N*|DhzS=p4n)5w<22C9|`y0bA}ezGKejx80WiROm$Fjd!z+ z10r@bEYQg9;|W3zkH5nIP}8ub)|SUS-6OGaaq$EXZ~UL_9|^4!o7kblU!V_n zS<{DHCjwiPABM2?TaA!g+HHBnY#m0-RvdA4w%6XW8C;Y%1^GY1;M1zqg01D4TS&1{ z?ynQ&*ix0FkLK(g#&}{J&DrtJ1G5cUoB#GVeq%zLHu1zyU`uhns$6cZnB1d=U~2|@ za!xPSGDv-l4R~<~{+MWDjyDd1Lqzj`**Q5N~2O-nQ-XfiN6I<0V zf5%*(&>Ri@#6RAdu8%ua9~%f>{G&^HdN?uki6@`b%vbLXk~9H1FB;u;8|6ffAbtw` zDD920HJy*ExbJwPJf>MSwkUtmYsj<4v32z5Q7=?%;K1`cc1V;@6ZTdF?5#JIFeT3M zej@Y>>6yzETLanP&e*yc(@Z*1oxKHY9faHpLjT4)_s|Ah(JjY5{gmISx3}IF_)*$Z z`-CG8-^TJh9(PxBu%%vZ;XB)#k(n8A_h0@ZZQZ)nM(%p{ZN2rmFwiGTfc^SUB}|EP zG;U(RRt=C_za#%C`Aam+Pox~ldy+bLZh>#kvjJj9?X&bbF$h~2qgExijIaftx4X+N z8|GEhoW$o4$Myi_5%X@gaUd%@TWSbf9%E-ohy^?*WRudqCSq&Jn66sn)^%WOJABIb zd9h_1uIR2Z{X7F;D-GB>u7oLZPGIYA^YeNBZFiSjlqY=B;1tz4l2Fg9u;o`{jjBIm z?wquF(y^zF-QuN7Mnm@~FzVQ+Q?x!v6zTiwI}I zI_#^un2T;JwrJe|x5pOpZ;eI%Enr4fzEfOx5pyyhE-5W-LcZnNv|YP)jaTQh&pz{+ zTVCD}KJzB1?;Xf{eA^?-mNmS7{dyg7jlK02u}Q#II?eYKdQWLjI#I|ix5pN8yM2q? zmm=S(QoY1E@cKfl(9nrRg9iBs{@Bas>bQT-+_}=OojdFF>DTX1upOiDD@6ZyHsW12 z!H#?hzPndZ=flwd`|U+e)wTq*jg?3tX{cNih_MOc*u~(ZQ8bt z2VQ0ZKd+%(&)|ExB5y-;$GC=M`|pS^`T`i-iQF>9@WTWyUcA_6`ivQx>qK*>Y3?w5 z5H?}U?d>hdtyBBPvH_G|9`e>4Pfcm)Bff+6i~VWMg_^KYUlzGAZ-dVy6La9V0!uXa z&tiU1)B2kG8yLF`pVX(2aZ5TTB}FV+w8&@Z(4m^xQ95#@4qNf@wH8|^_l{wOJyc`s z2K2%skmvQ>Id>_oUs_U9QWtoNg-+W9S*w`C*c^UT(5^#5-l7gE`Tvt4Z_G30t++-oiYQ<2%b(PAaX5Xm+`ezi;NYjw-WTk_i`IMby`4h*=%{fMCN$2$+-SAiT=XSs zwcG->4q=U;HZiTNVhcR{3Ts-$BM*jJ_Br*sAJ3kZ?z#6~sa^Z_p};)NbGOTe(uyf@ zJ@oA_$n7@|V>q{`rKb~KRMneuwAh0!cemwlAn*7SvwLBEb3co6U+@ri>s(?QtsPpO zTQ|%rf*z94*9${G?*PiDTJMo;exO-%tc%r5a zLjDO~y_~X&DY796NB#l+EFmtE_0P{_3#Sib8&^zbFRY)#c5j%=wy>)-4^!rj03N zIo&(6@bFf^3w%k)yP(7qaSn3pH~1r_PM9>Qen0&jX*J*8>^XBdw$R_`2m94x?q%^F z+RL%!*0wzS5BspbS#Zk$MLQn4@H^<8ILf_QU0ZT$s?@unfb!^V1dpv^swwak7!=6* z=BBglYiF_(ht{);CthIe>%EM9^LPCAG4?Hfv_JiKcH^r(?EJ^iu_OCeu}2q_vE-yS z99L@O7qInXbZjhNn5alYK7GhJX~l{aK8RBqSgWuFne_wad}qUkr~GsBZ$o}e{UF#^ zLqV$+SY=^MiS!1>MaG~k7v*I$Jti6TAinMFZk^ap$fTc-Zs)jRr-7%h_b>+hSo{&@ z^cXw&_C~h6yp$!xM_RQ(sSNOQ9YOyvjPi7A*~qq7wrpAL!xrXc%*Q$_O1L7vK~5|s zer?;nT?^YBaxLCXc6tKj=I5q3lK)MzB_J?>&6-fePQANHhbO{{5|%8T0}ij9dWpTg zXE`hA*+q@rbpz#GS6oukC^s)pQ@zRF+O};QVXMd%x#gDj7Ifj>M+>dm?~oPSpWU{t zzKAo@#5g-HruA@#4IkbZZT2@ghD?tIrv5som|ZvyeMj=i5@xi}A-}$SdjlI#kZDzJ zK_C7Q6Bm~O{A;c;#`>iV8#mS-YynsQdS*Ba4GC1Vu^{IU!p6MKmE$_YM~skYJz?1E znPkJ5VoCf>x{u@(Vd~;%J9Rdc7VKEN7TBtKcO&fn46AYrC@Qik9)#+gsgg6V93&b=D30Eg0Rc2 z;l!5nz}9~bKF&HO#wqp{A*+6X&Q3+YL3;f0$2C`-Z29H2!ImdnVO^?-u$FFzEAqu6 zZY2(FWifv&`2(^tli103HabrCDd29)>S?^6skH7W#Ydu_QFqBwZjx%o7TNODPlSG` zx&1`o>isPv)ayZw{T!;7*NWfp9P4^z_8n$h^BtsB|$+qZAGStnMzEe~A1vT7jX^TW_imh=ql_UExq zdwr2>%vOG>y>IlGG1ADgvfJSUeZ^9l$mdzmGmZU3z64wQeM&eocMka7_so12)Drfn z1%8pQ6n1D9jSY}L*VYYvOKHv8wLTP+2$@~u{PIgM@6ei`0qwh(`190;4YsmL(|zzW zN{JmihA8n9?Z=*8iM)8OkW~U>!0&e-Zef{eiI7>%Eq;fHsaZf39sz9Fvr&!~^4-}I z2eG*#zk23XBS*k5Z%$?fUE>vT1wC{P`e+2?hCM9ObT9d=&=1T7cK$FYuV_r8Z9+6V z@z#2m*i~{Jd*jp|HXA-N8dEe^Hljfn?m{egg8>5vYO1%ni_2}qmSJACtLMH#2U1*v zZv7O?IuLDpwoSWsZ6LGERomgT{rmUxX98OjEVUc8Xwa`0YaF%5IM54E z&St&}WA^YjeAvIR@BzfhJA^;8kQ0yO7QQu2ai=cF7Ujf6uA|9=ldbyuU?;qdv6Opg z9R^oy6$=({y974MDkWUa95;ZE>&az_OOBy;kL+K~Lc>BV`m>gL4z3+!RaQ~EqTjrP>`zzC{URSb=3do9?A)^!aRu9E)uJ)3wXKA_gD?M!!%wl; zm~e}@g6;4l;{S0ncP4=ee|^&q8u;F%OXD}Ty1)^ z`f&Bbf1c%iLM2>buAEbFMeMS*pXd~90aI5X2iGG`G$dF#=8D=7^5PfprYGg5L)@B4 z>pSmH$VZCbtB-iXopLP6kExIU#3NXbhGMB)C8xxDpa)N4ELtgs2J-4x@Q%+paTcd$ z%$#YTPIN>+5tzD$b@H}9+=qp=3bbmgQyW4TJ&U~fP0}+noy8in&&50q>Gz8l>mrtE zgB(lpW0Dg~W{q&2KU83f_ORPOdE*Hd5fQ3nU!8$n8t(4|Jt$`ye8)O$X`G*EkXv@z zTi4&8$zELEpT%LlJc=oiw~@JH*qf)|i|dH*PF@X{9BhXJq(^JRr_w+@#5q?UP$JVv8{K(uzVBA047fP611o zVW&^qv2$l#k$cCPd@+6Y*QZZQWMiQWLs1s9YvGc-BD?wQN6)%mW7oOU%B5V(Hr_CMLqh zGaGkBGPhN$U{<;FuP(Q-D8_4OVGl)rJ9Oas*DEXQBKNe}`ZX$0`l_BuHXZU!rww8`5?yeR3agR;OQnfCI z0aFTdBINIaujMFgDlVjk=;KrzRbQ>oS+sbubo}`7y7=zb$;&7|CR|aU?7y$AahZRV zFg$PaV8!ngw&`hF+k?i=t7D_MQ<4ej_fY;VRXHh1{u{50f!HH6Yf@;%6!8M~3?Ha* zhdJ}lJo5}+*8%b3z3~12D#w%jnD{Y$Y$3b!#V+TM6Y6DEJmw^`cwBp7h24X zPVF0pak@R5E1YY;!^eK^f7@8e;GT+@!Z&aQ>y3|~dQcp7b#AaD`0F7rQq{|?Td_s{ zse_Lfv9$KEr&Q`bypQIP6uuOK!*K zlsY9A3z)k6<%?_?<`dFdyYhFN9%BsZ2y!R+B6jSS`cwyDB76|EL2lWEtzVG?+2Bji zfGMndISOkDH9$;9byVBxJ1LeI`Q2JTX1#CPhVsA3|K7DrBKzpTYRB4I98a=NA>*lHpM2xRiok;7&6(FY-`8>&%mGj%uG07>y)XZ74+!j;B zcgpQU8~RrzkXdG9{6rlITNKCn*6#mfSE-K(OxQKX1AB^e-y?HNxURLvTVVf9tUJ`a zZM$~7%{*S<%&PoH$3lATUvfsOhzY}9<>1Ln~>lN~lc zTa3qP!ImXHo6-fQNKPS6*5)$0@j^{O&Dl_9JIZ2(iqLl zqB-^4$Hnt~V4NDb;j)b68DY*q-;24@JJ|cLJjP}qW-vNBT$P&Lb}KAjzUaT)vg^|kEle{E)`@jHci%#=gsz_!JFY=-7EM@EEkJXw=b;+@ccdodPx zzq{D#*7!?nbJFGrYza&u-q5Y>DJ7mz{#?Wz)dRLhS{mOGZ7ttZf04$i31c)rD=IRK zC1KujQiph!*e;fZh6ZDvgD!4}u2YLAdIvC72{{@{<4!}XIq#ej?@Z5$vf85)1*VWI zzkxgFHa4xhxxdjjl#qL|A?62-LA}10<45f=;fAm#eroMf)8`YWI(6Ff_b zm@BSZ(_}hPweM8$fOwC7Um0PlCfMj|8iI8AlxfrIBmQqN@*tlQb#>LA>?w?+?!j11 zD3!N5$5GYrOX(Ww6VawcZb4U^!5Gz`$5yVaM{{Ru(?&5zFTeb9U0^F2ZTt^l%IbO& zj=&vwdM-39?5~;Ky4??bT%$21@F2zo)Yw~kOcm|jv&V<#2i3-H=gytHT8O`Bj=4Jv zA)85dna$;3FQy=)E(5=B(Rd}sPaDt}Q*GLiGn`jPNp69^B&Uj=e)?%2T1TU{Z#1VE zc4Ixrt^~x6t=8kqA^Ep~r%SM--XnVsu~bcomyfMlRV!I4a-*8V7Ua}dkk5Tru3YIO z{P(qz31%uqbMN~V7B)b>dCIZ70C@N}`0)#5l_rdl{RC`&6V$Th4)Ag)bYAo0Cr;Es zUMe$htz9I_O4F4|8HtAZsQ=hi!o@ zdk;K1f!`V6<`?)_f5rZ1;OHwHe~k050h_BaW;7VFs*xBoZA`EI;K&gTZ?E~6%Hklp z;M;s1-)J87O$5E>*Urm^{LL>{WYAG-r{>X;N^gq16~ez zIp9e8MKPuEqM#!3d#m_$ z#56Ae(-jZQlHIE-o-wUT_YR}$D$UR;%+Pcsqvz?1 zXGGH%&!~L*;u+EO#WSK+>E9veL8YE1=V^r*nw}(Y4^cdMTZ-bzX`*;?9Ejq{@lqw; zA;VRrpvmx8A!zJodkB&Y&xYd3aBnD{?E5ej@6MagGZatuZB>bP$iBf!K`Xy`Z-t<- zn>0Z}@kE*B#k+-u;t86e$S9tm8H(&@hL(JjW~fHF85&69dEz=Mo}g9f%M9+_LZjlD zUPr|fv`YQGer9ONW@zPRXhbr39xt8=O($^m-=%nO`K|YoAJgQt)Xrj@d$%aDf^cLNAr=id~*-4LY$SUwZZ8};Nj(iMU z)zKS#og3>rY|6;Rq^@)v=#iom{zGjiT0?{9~uti zw3`JmoYohRx0~T!T>VEIiNeSDQvDrQWhx9PBZiOvEr zj2A{u!?%K)gl#5@r7H}|g!1WV$+(URqx+6@Mdh>#N%G^@>9IlART}I>+(D)rwkp2I z^K`{05>*}l3mVA*Dj@BNR*74=K*L``Zr~|EHf=Zfo~|PXQq{2WJ<+Jpew@TAXiqdM rV7ZP~nXIQ#VRR%`RW4{%`d8r5bdK)D&B=6(?HBrw)9669si*xvcwg6a literal 0 HcmV?d00001 diff --git a/frontend/projects/sdk-ui/assets/images/logo-inverse.png b/frontend/projects/sdk-ui/assets/images/logo-inverse.png new file mode 100644 index 0000000000000000000000000000000000000000..1457c9b25fa8cca19cf38cc86b050e5f5b3c0e14 GIT binary patch literal 1970 zcmV;j2Tk~iP) zDinr|iMQ%DG{{M~-VkiBUi$GDmo%Xe>FC}=!(fjp6oy@^pSnRA6JN7xH%J4yh!h9{ z@~A>#SYJGPyeobiSq+1;XPmq5zw;#RdR`*M5W06hyl{0=iy#OvK56bfVV1qvbyxhj zeCmtqT~X(V<2KjzM4gt$%(50~^c--^Hn?9uWlY=RS}#RjTanded0AUm_>8eWR1COJ zPpyOllu2Y3@)Jqh&-Py|YqY}{RqNo%119YuxA8@3@+C*P2lW%lWI6B|+=R<5$PjIA ziV0L5wd>rkCrU3xw6uI!WF78D$I^K;{@n2~`{Ji57a1HNpEPi4Z!d9QD@NqYX0Jd< z!V`nO@z9X7plXkyoGls=30XZZKG&hms%RTduILACZu2#lH99WWrO~`>P%#X6EIuF0 zF|Er6wiN`oH3WG{abN)={eyjLp&*eUQ0;qJ*OVqeE(qYJD6>M=0+(5FzCa^VI|^~C zHo6IN7nS3r&}+p?Mkk>ytimjpw|Sglzj8eG%>L^kg?FZfgp z>q_64lrH5!Y)^xnCDyt_@O}vME$gLrdP?15g7_BydU-5H2Gqsj;*SlD!{ibrdX)a~ z^>A$B-!zeI>f}VNq^x9JND}->a+nO&tg4y}II5}TMIzhiSU*#!zD~HH!VC~kZu3hK zPX<DZ=>kSXKdWi{5+CQ}dzwLU3C%2*QNL>P;SN$llxGBzoi z{BV1TJ3ld~rc)&W3rRJ#GS}>L;|-#8WXp| zbs%(|@}a9ELlBL@EU1CH-`%%pMJkX!K(uy-0uAF&8I6=5d3gEe0n4l;Sd4l*5RrqJ0&hf z$$&|4MB67y0wQZ08L<5AgfT*f>O}cTUTN%E(y*eW{>Gj=_RNQ4GBLB68?{Pg*eMM= zA76W*^~NPH*u<$xjddjk)RrO2JVhGkr!@0KnYU81OfgdnWNBq?#GW}cx1p8M6#!FP zs|Ts^<$r(d(%w&h9TIt@^Aa>vF+GDMCnaW@!Zwr4RXDB`hl#aXYH66K&2Wt5eQKzY zHqHiRTL9@3OnmOKXC?!r5&G=$(~!tXD9hwlNQV)bfZM+3oH>84KXdN111)_1=f8>C znA}-K=rmzWCICXMn%x(7J7kE8(CHx;nLtJ8$%BbEdjwwhvL74_o5E%F$q;$GTsRJ* zz-!y(SkTx@7Wb^FaaoT05!Y=65io|9p$N!8?siQ%&k9qLWUO)jJ3J>2>T{C`95bN^ z++j%&LLjl8=Ziko+cbjmc?$BO7zaLg!9<#-IMM$(<=i22Kn6k|%mcp53ghWQWCF)X zXj_yHr}DN7B-Zl+TDU0_+njU7drFty3^(GuE3j;;+e| zVYxKDWQ1cVg-oCbp~7hCB*{IB-i|c5teR$e80TdUl+4hjD0kcDe6357wsy%39z}0x z98TW*ln*lBjO}M&n$F8a0YV$@*LSk^9_$bJkZFg@o=#RK2DEo6dfQ;+KyhDq^>&^6 z$0Qnm4ajDClV!je%kyF#V_Bq;9}&J1%pICcLY}ZC2o4s!TUUBiAva3ZOo?0?YOZA! zVwj3%N@#1SAiaO<^I57;2vgBa30(~h4y+;{WL02Hl}sQa^wfMnNB_wsL_h-(nl!!c zXPNIxD`aD;W;PD@+C3LP6j%+y=ZV7?J+FJU+AB-K|I?%C)9dNN1ONa407*qoM6N<$ Eg6x8tiU0rr literal 0 HcmV?d00001 diff --git a/frontend/projects/sdk-ui/assets/images/logo-klovercloud-01.png b/frontend/projects/sdk-ui/assets/images/logo-klovercloud-01.png new file mode 100644 index 0000000000000000000000000000000000000000..e77a3e21456424787665478ee951270b25d9dc8a GIT binary patch literal 32419 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 ZgQlaC0;AdeQHT=b%V)3Uik=$!{y(1;k{tj5 literal 0 HcmV?d00001 diff --git a/frontend/projects/sdk-ui/assets/images/logo-light.svg b/frontend/projects/sdk-ui/assets/images/logo-light.svg new file mode 100644 index 0000000..9d9efd1 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/images/logo-light.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/frontend/projects/sdk-ui/assets/images/logo_klovercloud.png b/frontend/projects/sdk-ui/assets/images/logo_klovercloud.png new file mode 100644 index 0000000000000000000000000000000000000000..a45dffc6e4ea90c8cf9f210a5e4f0fde126ee35c GIT binary patch literal 9539 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 YHlPh!96D_UDB!3nX(^T~Jbw9q0Enk?jsO4v literal 0 HcmV?d00001 diff --git a/frontend/projects/sdk-ui/assets/images/toastr/icon-error.svg b/frontend/projects/sdk-ui/assets/images/toastr/icon-error.svg new file mode 100644 index 0000000..b728de8 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/images/toastr/icon-error.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/projects/sdk-ui/assets/images/toastr/icon-notification.svg b/frontend/projects/sdk-ui/assets/images/toastr/icon-notification.svg new file mode 100644 index 0000000..593e8dc --- /dev/null +++ b/frontend/projects/sdk-ui/assets/images/toastr/icon-notification.svg @@ -0,0 +1,2 @@ + + diff --git a/frontend/projects/sdk-ui/assets/images/toastr/icon-success.svg b/frontend/projects/sdk-ui/assets/images/toastr/icon-success.svg new file mode 100644 index 0000000..3d6710e --- /dev/null +++ b/frontend/projects/sdk-ui/assets/images/toastr/icon-success.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/projects/sdk-ui/assets/images/toastr/icon-warn.svg b/frontend/projects/sdk-ui/assets/images/toastr/icon-warn.svg new file mode 100644 index 0000000..0b0da3e --- /dev/null +++ b/frontend/projects/sdk-ui/assets/images/toastr/icon-warn.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/projects/sdk-ui/assets/scss/argo/variables.scss b/frontend/projects/sdk-ui/assets/scss/argo/variables.scss new file mode 100644 index 0000000..1052999 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/scss/argo/variables.scss @@ -0,0 +1,43 @@ +$argo-color-gray-1: #f8fbfb; +$argo-color-gray-2: #eff3f5; +$argo-color-gray-3: #dee6eb; +$argo-color-gray-4: #ccd6dd; +$argo-color-gray-5: #8fa4b1; +$argo-color-gray-6: #6d7f8b; +$argo-color-gray-7: #495763; +$argo-color-gray-8: #363c4a; +$argo-color-gray-9: #000000; + +$argo-color-teal-1: #f5fbfd; +$argo-color-teal-2: #dff6f9; +$argo-color-teal-3: #bdecf2; +$argo-color-teal-4: #99e1ea; +$argo-color-teal-5: #1fbdd0; +$argo-color-teal-6: #00a2b3; +$argo-color-teal-7: #006f8a; +$argo-color-teal-8: #004c67; + +$white-color: #ffffff; +$dark-theme-background-1: #100f0f; +$dark-theme-background-2: #303237; +$dark-theme-sliding-panel: #28292a; +// Status colors +$argo-failed-color: #e96d76; +$argo-failed-color-dark: #c04b4f; +$argo-failed-color-light: #ff6262; +$argo-status-failed-color: #ef0b28; +$argo-color-red: #f00052; + +$argo-success-color: #18be94; +$argo-success-color-dark: #3f946d; +$argo-success-color-light: #95d58f; +$argo-status-success-color: #0d8d38; +$argo-color-green: #7ed321; + +$argo-status-warning-color: #f4c030; +$argo-color-yellow: #ffd100; + +$argo-running-color-dark: #378398; +$argo-running-color-light: #02c4d3; +$argo-running-color: #0dadea; +$argo-suspended-color: #766f94; diff --git a/frontend/projects/sdk-ui/assets/styles/_base.scss b/frontend/projects/sdk-ui/assets/styles/_base.scss new file mode 100644 index 0000000..fad66d0 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/_base.scss @@ -0,0 +1,54 @@ +input { + background: transparent; +} + +button { + &:disabled { + opacity: 0.4; + } + + &:focus { + outline: unset !important; + } +} + +input, +textarea { + box-sizing: content-box; + line-height: 1.5; +} + +input:-webkit-autofill, +input:-webkit-autofill:hover, +input:-webkit-autofill:focus, +textarea:-webkit-autofill, +textarea:-webkit-autofill:hover, +textarea:-webkit-autofill:focus, +select:-webkit-autofill, +select:-webkit-autofill:hover, +select:-webkit-autofill:focus { + -webkit-text-fill-color: var(--text-color); + -webkit-box-shadow: 0 0 0px 1000px var(--background-1) inset; + transition: background-color 5000s ease-in-out 0s; +} + +code { + background: var(--background-app-bar); + border-radius: var(--border-radius); + color: var(--text-color); + font-size: 85%; + padding: 0.2em 0.4em; +} + +blockquote { + background: var(--color-primary-50); + border-left: 3px solid var(--color-primary-500); + color: rgba(0, 0, 0, 0.87); + font-style: normal; + margin: 1em 0 1.5em; + padding: 1em 1.5em; + + > * { + margin: 0; + } +} diff --git a/frontend/projects/sdk-ui/assets/styles/_fonticon.scss b/frontend/projects/sdk-ui/assets/styles/_fonticon.scss new file mode 100644 index 0000000..ef58546 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/_fonticon.scss @@ -0,0 +1,351 @@ +$kcicon-font-family: 'klovercloud-icon' !default; +$kcicon-font-path: '/assets/webfonts' !default; + +$icon-layer: '\e90d'; +$icon-canary: '\e90e'; +$icon-scaling: '\e90f'; +$icon-vpc: '\e910'; +$icon-cpu-2: '\e911'; +$icon-memory: '\e912'; +$icon-storage: '\e913'; +$icon-code: '\e915'; +$icon-external-url: '\e916'; +$icon-dev: '\e917'; +$icon-test: '\e918'; +$icon-qa: '\e919'; +$icon-pre-prod: '\e91a'; +$icon-prod: '\e91b'; +$icon-bar-chart: '\e91c'; +$icon-backup: '\e90c'; +$icon-success: '\e904'; +$icon-wrong: '\e907'; +$icon-explore: '\e905'; +$icon-chart: '\e909'; +$icon-camera: '\e90a'; +$icon-settings: '\e90b'; +$icon-upload: '\e902'; +$icon-close: '\e903'; +$icon-cpu: '\e901'; +$icon-package: '\e900'; +$icon-warn: '\e908'; +$icon-notification: '\e906'; +$icon-document: '\e926'; +$icon-folder: '\e92f'; +$icon-search: '\e986'; +$icon-enlarge2: '\e98b'; +$icon-minus: '\ea0b'; +$icon-circle-outline: '\ea56'; +$icon-git-organization: '\e914'; +$icon-git-repository: '\e91d'; +$icon-calender: '\e91e'; +$icon-clock: '\e91f'; +$icon-network-policy: '\e922'; +$icon-download: '\e934'; + +@font-face { + font-family: '#{$kcicon-font-family}'; + src: url('#{$kcicon-font-path}/#{$kcicon-font-family}.eot?i0enwr'); + src: + url('#{$kcicon-font-path}/#{$kcicon-font-family}.eot?i0enwr#iefix') format('embedded-opentype'), + url('#{$kcicon-font-path}/#{$kcicon-font-family}.ttf?i0enwr') format('truetype'), + url('#{$kcicon-font-path}/#{$kcicon-font-family}.woff?i0enwr') format('woff'), + url('#{$kcicon-font-path}/#{$kcicon-font-family}.svg?i0enwr##{$kcicon-font-family}') format('svg'); + font-weight: normal; + font-style: normal; + font-display: block; +} + +i { + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: '#{$kcicon-font-family}' !important; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-success { + &:before { + content: $icon-success; + } +} +.icon-warn { + &:before { + content: $icon-warn; + } +} +.icon-error { + &:before { + content: $icon-wrong; + } +} +.kc-upload { + &:before { + content: $icon-upload; + } +} +.kc-close { + &:before { + content: $icon-close; + } +} +.kc-cpu { + &:before { + content: $icon-cpu; + } +} +.kc-package { + &:before { + content: $icon-package; + } +} +.icon-notification { + &:before { + content: $icon-notification; + } +} +.icon-document { + &:before { + content: $icon-document; + } +} +.icon-folder { + &:before { + content: $icon-folder; + } +} +.kc-search { + &:before { + content: $icon-search; + } +} +.kc-enlarge2 { + &:before { + content: $icon-enlarge2; + } +} +.kc-minus { + &:before { + content: $icon-minus; + } +} + +.icon-layer { + &:before { + content: $icon-layer; + } +} +.icon-canary { + &:before { + content: $icon-canary; + } +} +.icon-scaling { + &:before { + content: $icon-scaling; + } +} +.icon-vpc { + &:before { + content: $icon-vpc; + } +} +.icon-cpu-2 { + &:before { + content: $icon-cpu-2; + } +} +.icon-memory { + &:before { + content: $icon-memory; + } +} +.icon-storage { + &:before { + content: $icon-storage; + } +} +.icon-code { + &:before { + content: $icon-code; + } +} +.icon-external-url { + &:before { + content: $icon-external-url; + } +} + +.icon-dev, +.ico-dev { + &:before { + content: $icon-dev; + } +} +.icon-test, +.icon-tes { + &:before { + content: $icon-test; + } +} +.icon-staging, +.icon-sta { + &:before { + content: $icon-layer; + } +} +.icon-qa, +.icon-qua { + &:before { + content: $icon-qa; + } +} +.icon-pre-prod, +.icon-pre { + &:before { + content: $icon-pre-prod; + } +} +.icon-prod, +.icon-pro { + &:before { + content: $icon-prod; + } +} +.icon-bar-chart { + &:before { + content: $icon-bar-chart; + } +} +.icon-backup { + &:before { + content: $icon-backup; + } +} +.icon-success { + &:before { + content: $icon-success; + } +} +.icon-wrong { + &:before { + content: $icon-wrong; + } +} +.icon-explore { + &:before { + content: $icon-explore; + } +} +.icon-chart { + &:before { + content: $icon-chart; + } +} +.icon-camera { + &:before { + content: $icon-camera; + } +} +.icon-settings { + &:before { + content: $icon-settings; + } +} +.icon-upload { + &:before { + content: $icon-upload; + } +} +.icon-close { + &:before { + content: $icon-close; + } +} +.icon-cpu { + &:before { + content: $icon-cpu; + } +} +.icon-package { + &:before { + content: $icon-package; + } +} +.icon-warn { + &:before { + content: $icon-warn; + } +} +.icon-notification { + &:before { + content: $icon-notification; + } +} +.icon-document { + &:before { + content: $icon-document; + } +} +.icon-folder { + &:before { + content: $icon-folder; + } +} +.icon-search { + &:before { + content: $icon-search; + } +} +.icon-enlarge2 { + &:before { + content: $icon-enlarge2; + } +} +.icon-minus { + &:before { + content: $icon-minus; + } +} +.icon-circle-outline { + &:before { + content: $icon-circle-outline; + } +} +.icon-git-organization { + &:before { + content: $icon-git-organization; + } +} +.icon-git-repository { + &:before { + content: $icon-git-repository; + } +} +.icon-calender { + &:before { + content: $icon-calender; + } +} +.icon-clock { + &:before { + content: $icon-clock; + } +} +.icon-network-policy { + &:before { + content: $icon-network-policy; + } +} +.icon-download { + &:before { + content: $icon-download; + color: var(--text-color); + } +} diff --git a/frontend/projects/sdk-ui/assets/styles/_root.scss b/frontend/projects/sdk-ui/assets/styles/_root.scss new file mode 100644 index 0000000..e2c3570 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/_root.scss @@ -0,0 +1,504 @@ +@use '@angular/material' as mat; + +:root { + // Generic + --padding-page: 1rem; + --padding: 1.5rem; + --padding-16: 1rem; + --padding-12: 0.75rem; + --padding-8: 0.5rem; + --padding-4: 0.25rem; + + @screen xl { + --padding-page: 1.5rem; + } + + // Typography + --font: 'Open Sans', sans-serif; + --font-weight-medium: 500; + --font-caption: #{mat.font-weight($config, caption) #{mat.font-size($config, caption)}/#{mat.line-height($config, caption)} + mat.font-family($config, caption)}; + --font-body-1: #{mat.font-weight($config, body-1) #{mat.font-size($config, body-1)}/#{mat.line-height($config, body-1)} + mat.font-family($config, body-1)}; + --font-body-2: #{mat.font-weight($config, body-2) #{mat.font-size($config, body-2)}/#{mat.line-height($config, body-2)} + mat.font-family($config, body-2)}; + --font-subheading-1: #{mat.font-weight($config, subheading-1) + #{mat.font-size($config, subheading-1)}/#{mat.line-height($config, subheading-1)} mat.font-family($config, subheading-1)}; + --font-subheading-2: #{mat.font-weight($config, subheading-2) + #{mat.font-size($config, subheading-2)}/#{mat.line-height($config, subheading-2)} mat.font-family($config, subheading-2)}; + --font-headline: #{mat.font-weight($config, headline) #{mat.font-size($config, headline)}/#{mat.line-height($config, headline)} + mat.font-family($config, headline)}; + --font-title: #{mat.font-weight($config, title) #{mat.font-size($config, title)}/#{mat.line-height($config, title)} + mat.font-family($config, title)}; + --font-display-1: #{mat.font-weight($config, display-1) #{mat.font-size($config, display-1)}/#{mat.line-height($config, display-1)} + mat.font-family($config, display-1)}; + --font-display-2: #{mat.font-weight($config, display-2) #{mat.font-size($config, display-2)}/#{mat.line-height($config, display-2)} + mat.font-family($config, display-2)}; + --font-display-3: #{mat.font-weight($config, display-3) #{mat.font-size($config, display-3)}/#{mat.line-height($config, display-3)} + mat.font-family($config, display-3)}; + --font-display-4: #{mat.font-weight($config, display-4) #{mat.font-size($config, display-4)}/#{mat.line-height($config, display-4)} + mat.font-family($config, display-4)}; + + // Transitions + --trans-ease-in-out: all var(--trans-ease-in-out-duration) var(--trans-ease-in-out-timing-function); + --trans-ease-in-out-duration: #{$swift-ease-in-out-duration}; + --trans-ease-in-out-timing-function: #{$swift-ease-in-out-timing-function}; + --trans-ease-out: all var(--trans-ease-out-duration) var(--trans-ease-out-timing-function); + --trans-ease-out-duration: #{$swift-ease-out-duration}; + --trans-ease-out-timing-function: #{$swift-ease-out-timing-function}; + --trans-ease-in: all var(--trans-ease-in-duration) var(--trans-ease-in-timing-function); + --trans-ease-in-duration: #{$swift-ease-in-duration}; + --trans-ease-in-timing-function: #{$swift-ease-in-timing-function}; + --trans-shadow-duration: #{280ms}; + --trans-shadow-timing-function: #{cubic-bezier(0.4, 0, 0.2, 1)}; + --trans-shadow: box-shadow var(--trans-shadow-duration) var(--trans-shadow-timing-function); + + --text-color: #{$dark-primary-text}; + --text-color-light: #{$light-primary-text}; + --text-secondary: #{$dark-secondary-text}; + --text-secondary-light: #{$light-secondary-text}; + --text-hint: #{$dark-disabled-text}; + --text-hint-light: #{$light-disabled-text}; + + // Foreground + --foreground-divider: #{map-get(map-get($kc-theme, foreground), divider)}; + + // Background + --background-base: rgb(245, 245, 248); + --background-card: #{map-get(map-get($kc-theme, background), card)}; + --background-app-bar: #{map-get(map-get($kc-theme, background), app-bar)}; + --background-hover: #{map-get(map-get($kc-theme, background), hover)}; + + // Elevation + --elevation-default: var(--elevation-z6); + --elevation-z0: none; + --elevation-z1: #{kc-elevation(1)}; + --elevation-z3: #{kc-elevation(3)}; + --elevation-z4: #{kc-elevation(4)}; + --elevation-z5: #{kc-elevation(5)}; + --elevation-z6: #{kc-elevation(6)}; + --elevation-z7: #{kc-elevation(7)}; + --elevation-z8: #{kc-elevation(8)}; + --elevation-z9: #{kc-elevation(9)}; + --elevation-z10: #{kc-elevation(10)}; + --elevation-z11: #{kc-elevation(11)}; + --elevation-z12: #{kc-elevation(12)}; + --elevation-z13: #{kc-elevation(13)}; + --elevation-z14: #{kc-elevation(14)}; + --elevation-z15: #{kc-elevation(15)}; + --elevation-z16: #{kc-elevation(16)}; + --elevation-z17: #{kc-elevation(17)}; + --elevation-z18: #{kc-elevation(18)}; + --elevation-z19: #{kc-elevation(19)}; + --elevation-z20: #{kc-elevation(20)}; + + // Sidenav + --sidenav-width: 260px; + --sidenav-collapsed-width: 72px; + --sidenav-background: #{$sidenav-background}; + --sidenav-color: white; + + // Sidenav Item + --sidenav-item-padding: var(--padding); + --sidenav-toolbar-background: #{darken($sidenav-background, 1.5)}; + --sidenav-item-background-active: #{darken($sidenav-background, 2)}; + --sidenav-item-color: #a1a2b6; + --sidenav-item-color-active: #{$light-primary-text}; + --sidenav-item-icon-color: #494b74; + --sidenav-item-icon-color-active: var(--color-primary-500); + --sidenav-item-icon-gap: 16px; + --sidenav-item-icon-size: 24px; + --sidenav-item-dropdown-background: #{darken($sidenav-background, 2)}; + --sidenav-item-dropdown-background-hover: #{darken($sidenav-background, 3)}; + --sidenav-item-dropdown-gap: 12px; + + // Toolbar + --toolbar-height: 80px; + --toolbar-background: rgb(245, 245, 248); + --toolbar-color: #{$dark-primary-text}; + --toolbar-icon-color: var(--color-primary-500); + + // Secondary Toolbar + --secondary-toolbar-background: var(--background-card); + + // Navigation + --navigation-height: 64px; + --navigation-background: var(--background-card); + --navigation-color: var(--text-secondary); + + // Footer + --footer-height: 56px; + --footer-z-index: 100; + --footer-background: var(--background-card); + --footer-color: var(--text-color); + --footer-elevation: 0 -10px 30px 0 rgba(82, 63, 104, 0.06); + + // Page Layouts + --page-layout-header-height: 200px; + --page-layout-toolbar-height: 64px; + + // Misc + --blink-scrollbar-width: 12px; + --default-icon-size: 24px; + --border-radius: 4px; + + // Primary + --color-primary-50: rgb(236, 239, 255); + --color-primary-100: rgb(206, 215, 255); + --color-primary-200: rgb(174, 188, 255); + --color-primary-300: rgb(142, 161, 255); + --color-primary-400: rgb(117, 140, 255); + --color-primary-500: rgb(92, 119, 255); + --color-primary-600: rgb(85, 112, 255); + --color-primary-700: rgb(75, 101, 255); + --color-primary-800: rgb(65, 91, 255); + --color-primary-900: rgb(48, 72, 255); + --color-primary-A100: rgb(128, 216, 255); + --color-primary-A200: rgb(64, 196, 255); + --color-primary-A400: rgb(219, 223, 255); + --color-primary-A700: rgb(194, 200, 255); + --color-primary-contrast-50: #{$dark-primary-text}; + --color-primary-contrast-100: #{$dark-primary-text}; + --color-primary-contrast-200: #{$dark-primary-text}; + --color-primary-contrast-300: #{$dark-primary-text}; + --color-primary-contrast-400: #{$dark-primary-text}; + --color-primary-contrast-500: #{$light-primary-text}; + --color-primary-contrast-600: #{$light-primary-text}; + --color-primary-contrast-700: #{$light-primary-text}; + --color-primary-contrast-800: #{$light-primary-text}; + --color-primary-contrast-900: #{$light-primary-text}; + --color-primary-contrast-A100: #{$dark-primary-text}; + --color-primary-contrast-A200: #{$dark-primary-text}; + --color-primary-contrast-A400: #{$dark-primary-text}; + --color-primary-contrast-A700: #{$dark-primary-text}; + + // Red + --color-red-50: #ffebee; + --color-red-100: #ffcdd2; + --color-red-200: #ef9a9a; + --color-red-300: #e57373; + --color-red-400: #ef5350; + --color-red-500: #f44336; + --color-red-600: #e53935; + --color-red-700: #d32f2f; + --color-red-800: #c62828; + --color-red-900: #b71c1c; + --color-red-A100: #ff8a80; + --color-red-A200: #ff5252; + --color-red-A400: #ff1744; + --color-red-A700: #d50000; + --color-red-contrast-50: #{$dark-primary-text}; + --color-red-contrast-100: #{$dark-primary-text}; + --color-red-contrast-200: #{$dark-primary-text}; + --color-red-contrast-300: #{$dark-primary-text}; + --color-red-contrast-400: #{$dark-primary-text}; + --color-red-contrast-500: #{$light-primary-text}; + --color-red-contrast-600: #{$light-primary-text}; + --color-red-contrast-700: #{$light-primary-text}; + --color-red-contrast-800: #{$light-primary-text}; + --color-red-contrast-900: #{$light-primary-text}; + --color-red-contrast-A100: #{$dark-primary-text}; + --color-red-contrast-A200: #{$light-primary-text}; + --color-red-contrast-A400: #{$light-primary-text}; + --color-red-contrast-A700: #{$light-primary-text}; + + // Green + --color-green-50: #e8f5e9; + --color-green-100: #c8e6c9; + --color-green-200: #a5d6a7; + --color-green-300: #81c784; + --color-green-400: #66bb6a; + --color-green-500: #4caf50; + --color-green-600: #43a047; + --color-green-700: #388e3c; + --color-green-800: #2e7d32; + --color-green-900: #1b5e20; + --color-green-A100: #b9f6ca; + --color-green-A200: #69f0ae; + --color-green-A400: #00e676; + --color-green-A700: #00c853; + --color-green-contrast-50: #{$dark-primary-text}; + --color-green-contrast-100: #{$dark-primary-text}; + --color-green-contrast-200: #{$dark-primary-text}; + --color-green-contrast-300: #{$dark-primary-text}; + --color-green-contrast-400: #{$dark-primary-text}; + --color-green-contrast-500: #{$dark-primary-text}; + --color-green-contrast-600: #{$light-primary-text}; + --color-green-contrast-700: #{$light-primary-text}; + --color-green-contrast-800: #{$light-primary-text}; + --color-green-contrast-900: #{$light-primary-text}; + --color-green-contrast-A100: #{$dark-primary-text}; + --color-green-contrast-A200: #{$dark-primary-text}; + --color-green-contrast-A400: #{$dark-primary-text}; + --color-green-contrast-A700: #{$dark-primary-text}; + + // Amber + --color-amber-50: #fff8e1; + --color-amber-100: #ffecb3; + --color-amber-200: #ffe082; + --color-amber-300: #ffd54f; + --color-amber-400: #ffca28; + --color-amber-500: #ffc107; + --color-amber-600: #ffb300; + --color-amber-700: #ffa000; + --color-amber-800: #ff8f00; + --color-amber-900: #ff6f00; + --color-amber-A100: #ffe57f; + --color-amber-A200: #ffd740; + --color-amber-A400: #ffc400; + --color-amber-A700: #ffab00; + --color-amber-contrast-50: #{$dark-primary-text}; + --color-amber-contrast-100: #{$dark-primary-text}; + --color-amber-contrast-200: #{$dark-primary-text}; + --color-amber-contrast-300: #{$dark-primary-text}; + --color-amber-contrast-400: #{$dark-primary-text}; + --color-amber-contrast-500: #{$dark-primary-text}; + --color-amber-contrast-600: #{$dark-primary-text}; + --color-amber-contrast-700: #{$dark-primary-text}; + --color-amber-contrast-800: #{$dark-primary-text}; + --color-amber-contrast-900: #{$dark-primary-text}; + --color-amber-contrast-A100: #{$dark-primary-text}; + --color-amber-contrast-A200: #{$dark-primary-text}; + --color-amber-contrast-A400: #{$dark-primary-text}; + --color-amber-contrast-A700: #{$dark-primary-text}; + + // Orange + --color-orange-50: #fff3e0; + --color-orange-100: #ffe0b2; + --color-orange-200: #ffcc80; + --color-orange-300: #ffb74d; + --color-orange-400: #ffa726; + --color-orange-500: #ff9800; + --color-orange-600: #fb8c00; + --color-orange-700: #f57c00; + --color-orange-800: #ef6c00; + --color-orange-900: #e65100; + --color-orange-A100: #ffd180; + --color-orange-A200: #ffab40; + --color-orange-A400: #ff9100; + --color-orange-A700: #ff6d00; + --color-orange-contrast-50: #{$dark-primary-text}; + --color-orange-contrast-100: #{$dark-primary-text}; + --color-orange-contrast-200: #{$dark-primary-text}; + --color-orange-contrast-300: #{$dark-primary-text}; + --color-orange-contrast-400: #{$dark-primary-text}; + --color-orange-contrast-500: #{$dark-primary-text}; + --color-orange-contrast-600: #{$dark-primary-text}; + --color-orange-contrast-700: #{$dark-primary-text}; + --color-orange-contrast-800: #{$light-primary-text}; + --color-orange-contrast-900: #{$light-primary-text}; + --color-orange-contrast-A100: #{$dark-primary-text}; + --color-orange-contrast-A200: #{$dark-primary-text}; + --color-orange-contrast-A400: #{$dark-primary-text}; + --color-orange-contrast-A700: black; + + // Deep Orange + --color-deep-orange-50: #fbe9e7; + --color-deep-orange-100: #ffccbc; + --color-deep-orange-200: #ffab91; + --color-deep-orange-300: #ff8a65; + --color-deep-orange-400: #ff7043; + --color-deep-orange-500: #ff5722; + --color-deep-orange-600: #f4511e; + --color-deep-orange-700: #e64a19; + --color-deep-orange-800: #d84315; + --color-deep-orange-900: #bf360c; + --color-deep-orange-A100: #ff9e80; + --color-deep-orange-A200: #ff6e40; + --color-deep-orange-A400: #ff3d00; + --color-deep-orange-A700: #dd2c00; + --color-deep-orange-contrast-50: #{$dark-primary-text}; + --color-deep-orange-contrast-100: #{$dark-primary-text}; + --color-deep-orange-contrast-200: #{$dark-primary-text}; + --color-deep-orange-contrast-300: #{$dark-primary-text}; + --color-deep-orange-contrast-400: #{$dark-primary-text}; + --color-deep-orange-contrast-500: #{$light-primary-text}; + --color-deep-orange-contrast-600: #{$light-primary-text}; + --color-deep-orange-contrast-700: #{$light-primary-text}; + --color-deep-orange-contrast-800: #{$light-primary-text}; + --color-deep-orange-contrast-900: #{$light-primary-text}; + --color-deep-orange-contrast-A100: #{$dark-primary-text}; + --color-deep-orange-contrast-A200: #{$dark-primary-text}; + --color-deep-orange-contrast-A400: #{$light-primary-text}; + --color-deep-orange-contrast-A700: #{$light-primary-text}; + + // Purple + --color-purple-50: #f3e5f5; + --color-purple-100: #e1bee7; + --color-purple-200: #ce93d8; + --color-purple-300: #ba68c8; + --color-purple-400: #ab47bc; + --color-purple-500: #9c27b0; + --color-purple-600: #8e24aa; + --color-purple-700: #7b1fa2; + --color-purple-800: #6a1b9a; + --color-purple-900: #4a148c; + --color-purple-A100: #ea80fc; + --color-purple-A200: #e040fb; + --color-purple-A400: #d500f9; + --color-purple-A700: #aa00ff; + --color-purple-contrast-50: #{$dark-primary-text}; + --color-purple-contrast-100: #{$dark-primary-text}; + --color-purple-contrast-200: #{$dark-primary-text}; + --color-purple-contrast-300: #{$light-primary-text}; + --color-purple-contrast-400: #{$light-primary-text}; + --color-purple-contrast-500: #{$light-primary-text}; + --color-purple-contrast-600: #{$light-primary-text}; + --color-purple-contrast-700: #{$light-primary-text}; + --color-purple-contrast-800: #{$light-primary-text}; + --color-purple-contrast-900: #{$light-primary-text}; + --color-purple-contrast-A100: #{$dark-primary-text}; + --color-purple-contrast-A200: #{$light-primary-text}; + --color-purple-contrast-A400: #{$light-primary-text}; + --color-purple-contrast-A700: #{$light-primary-text}; + + // Deep Purple + --color-deep-purple-50: #ede7f6; + --color-deep-purple-100: #d1c4e9; + --color-deep-purple-200: #b39ddb; + --color-deep-purple-300: #9575cd; + --color-deep-purple-400: #7e57c2; + --color-deep-purple-500: #673ab7; + --color-deep-purple-600: #5e35b1; + --color-deep-purple-700: #512da8; + --color-deep-purple-800: #4527a0; + --color-deep-purple-900: #311b92; + --color-deep-purple-A100: #b388ff; + --color-deep-purple-A200: #7c4dff; + --color-deep-purple-A400: #651fff; + --color-deep-purple-A700: #6200ea; + --color-deep-purple-contrast-50: #{$dark-primary-text}; + --color-deep-purple-contrast-100: #{$dark-primary-text}; + --color-deep-purple-contrast-200: #{$dark-primary-text}; + --color-deep-purple-contrast-300: #{$light-primary-text}; + --color-deep-purple-contrast-400: #{$light-primary-text}; + --color-deep-purple-contrast-500: #{$light-primary-text}; + --color-deep-purple-contrast-600: #{$light-primary-text}; + --color-deep-purple-contrast-700: #{$light-primary-text}; + --color-deep-purple-contrast-800: #{$light-primary-text}; + --color-deep-purple-contrast-900: #{$light-primary-text}; + --color-deep-purple-contrast-A100: #{$dark-primary-text}; + --color-deep-purple-contrast-A200: #{$light-primary-text}; + --color-deep-purple-contrast-A400: #{$light-primary-text}; + --color-deep-purple-contrast-A700: #{$light-primary-text}; + + // Cyan + --color-cyan-50: #e0f7fa; + --color-cyan-100: #b2ebf2; + --color-cyan-200: #80deea; + --color-cyan-300: #4dd0e1; + --color-cyan-400: #26c6da; + --color-cyan-500: #00bcd4; + --color-cyan-600: #00acc1; + --color-cyan-700: #0097a7; + --color-cyan-800: #00838f; + --color-cyan-900: #006064; + --color-cyan-A100: #84ffff; + --color-cyan-A200: #18ffff; + --color-cyan-A400: #00e5ff; + --color-cyan-A700: #00b8d4; + --color-cyan-contrast-50: #{$dark-primary-text}; + --color-cyan-contrast-100: #{$dark-primary-text}; + --color-cyan-contrast-200: #{$dark-primary-text}; + --color-cyan-contrast-300: #{$dark-primary-text}; + --color-cyan-contrast-400: #{$dark-primary-text}; + --color-cyan-contrast-500: #{$light-primary-text}; + --color-cyan-contrast-600: #{$light-primary-text}; + --color-cyan-contrast-700: #{$light-primary-text}; + --color-cyan-contrast-800: #{$light-primary-text}; + --color-cyan-contrast-900: #{$light-primary-text}; + --color-cyan-contrast-A100: #{$dark-primary-text}; + --color-cyan-contrast-A200: #{$dark-primary-text}; + --color-cyan-contrast-A400: #{$dark-primary-text}; + --color-cyan-contrast-A700: #{$dark-primary-text}; + + // Teal + --color-teal-50: #e0f2f1; + --color-teal-100: #b2dfdb; + --color-teal-200: #80cbc4; + --color-teal-300: #4db6ac; + --color-teal-400: #26a69a; + --color-teal-500: #009688; + --color-teal-600: #00897b; + --color-teal-700: #00796b; + --color-teal-800: #00695c; + --color-teal-900: #004d40; + --color-teal-A100: #a7ffeb; + --color-teal-A200: #64ffda; + --color-teal-A400: #1de9b6; + --color-teal-A700: #00bfa5; + --color-teal-contrast-50: #{$dark-primary-text}; + --color-teal-contrast-100: #{$dark-primary-text}; + --color-teal-contrast-200: #{$dark-primary-text}; + --color-teal-contrast-300: #{$dark-primary-text}; + --color-teal-contrast-400: #{$dark-primary-text}; + --color-teal-contrast-500: #{$light-primary-text}; + --color-teal-contrast-600: #{$light-primary-text}; + --color-teal-contrast-700: #{$light-primary-text}; + --color-teal-contrast-800: #{$light-primary-text}; + --color-teal-contrast-900: #{$light-primary-text}; + --color-teal-contrast-A100: #{$dark-primary-text}; + --color-teal-contrast-A200: #{$dark-primary-text}; + --color-teal-contrast-A400: #{$dark-primary-text}; + --color-teal-contrast-A700: #{$dark-primary-text}; + + // Gray + --color-gray-50: #fafafa; + --color-gray-100: #f5f5f5; + --color-gray-200: #eeeeee; + --color-gray-300: #e0e0e0; + --color-gray-400: #bdbdbd; + --color-gray-500: #9e9e9e; + --color-gray-600: #757575; + --color-gray-700: #616161; + --color-gray-800: #424242; + --color-gray-900: #212121; + --color-gray-A100: #ffffff; + --color-gray-A200: #eeeeee; + --color-gray-A400: #bdbdbd; + --color-gray-A700: #616161; + --color-gray-contrast-50: #{$dark-primary-text}; + --color-gray-contrast-100: #{$dark-primary-text}; + --color-gray-contrast-200: #{$dark-primary-text}; + --color-gray-contrast-300: #{$dark-primary-text}; + --color-gray-contrast-400: #{$dark-primary-text}; + --color-gray-contrast-500: #{$dark-primary-text}; + --color-gray-contrast-600: #{$light-primary-text}; + --color-gray-contrast-700: #{$light-primary-text}; + --color-gray-contrast-800: #{$light-primary-text}; + --color-gray-contrast-900: #{$light-primary-text}; + --color-gray-contrast-A100: #{$dark-primary-text}; + --color-gray-contrast-A200: #{$dark-primary-text}; + --color-gray-contrast-A400: #{$dark-primary-text}; + --color-gray-contrast-A700: #{$light-primary-text}; + + // Light Green + --color-light-green-50: #f1f8e9; + --color-light-green-100: #dcedc8; + --color-light-green-200: #c5e1a5; + --color-light-green-300: #aed581; + --color-light-green-400: #9ccc65; + --color-light-green-500: #8bc34a; + --color-light-green-600: #7cb342; + --color-light-green-700: #689f38; + --color-light-green-800: #558b2f; + --color-light-green-900: #33691e; + --color-light-green-A100: #ccff90; + --color-light-green-A200: #b2ff59; + --color-light-green-A400: #76ff03; + --color-light-green-A700: #64dd17; + --color-light-green-contrast-50: #{$dark-primary-text}; + --color-light-green-contrast-100: #{$dark-primary-text}; + --color-light-green-contrast-200: #{$dark-primary-text}; + --color-light-green-contrast-300: #{$dark-primary-text}; + --color-light-green-contrast-400: #{$dark-primary-text}; + --color-light-green-contrast-500: #{$dark-primary-text}; + --color-light-green-contrast-600: #{$dark-primary-text}; + --color-light-green-contrast-700: #{$light-primary-text}; + --color-light-green-contrast-800: #{$light-primary-text}; + --color-light-green-contrast-900: #{$light-primary-text}; + --color-light-green-contrast-A100: #{$dark-primary-text}; + --color-light-green-contrast-A200: #{$dark-primary-text}; + --color-light-green-contrast-A400: #{$dark-primary-text}; + --color-light-green-contrast-A700: #{$dark-primary-text}; +} diff --git a/frontend/projects/sdk-ui/assets/styles/_utilities.scss b/frontend/projects/sdk-ui/assets/styles/_utilities.scss new file mode 100644 index 0000000..011757f --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/_utilities.scss @@ -0,0 +1,112 @@ +.card { + border-radius: 0.25rem; + // box-shadow: var(--elevation-z8); + background-color: var(--background-card); +} + +.list-item { + border-radius: 0.25rem; + cursor: pointer; + height: 3rem; + padding-left: 1rem; + padding-right: 1rem; + &:hover { + background-color: var(--background-hover); + } +} + +.bg-pattern { + background: + linear-gradient( + 135deg, + var(--background-base) 22px, + var(--background-hover) 22px, + var(--background-hover) 24px, + transparent 24px, + transparent 67px, + var(--background-hover) 67px, + var(--background-hover) 69px, + transparent 69px + ), + linear-gradient( + 225deg, + var(--background-base) 22px, + var(--background-hover) 22px, + var(--background-hover) 24px, + transparent 24px, + transparent 67px, + var(--background-hover) 67px, + var(--background-hover) 69px, + transparent 69px + ) + 0 64px; + background-color: var(--background-base); + background-size: 64px 128px; +} + +// Transitions + +.trans-ease-out { + transition: var(--trans-ease-out); +} + +.trans-shadow { + transition: var(--trans-shadow); +} + +// Typography + +.display-4 { + font: var(--font-display-4); +} + +.display-3 { + font: var(--font-display-3); +} + +.display-2 { + font: var(--font-display-2); +} + +.display-1, +h1 { + font: var(--font-display-1); +} + +.headline, +h2 { + font: var(--font-headline); +} + +.title, +h3 { + font: var(--font-title); +} + +.subheading-2, +h4 { + font: var(--font-subheading-2); +} + +.subheading-1, +h5 { + font: var(--font-subheading-1); +} + +.body-2, +h6 { + font: var(--font-body-2); +} + +.body-1, +p { + font: var(--font-body-1); +} + +.caption { + font: var(--font-caption); +} + +.text-hint { + color: var(--text-hint); +} diff --git a/frontend/projects/sdk-ui/assets/styles/_var.scss b/frontend/projects/sdk-ui/assets/styles/_var.scss new file mode 100644 index 0000000..ac483ad --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/_var.scss @@ -0,0 +1,343 @@ +@use '@angular/material' as mat; +@import './partials/_mixins.scss'; + +$sidenav-background: #1a202e; + +$config: mat.define-typography-config( + $font-family: var(--font), + $display-4: mat.define-typography-level(112px, 112px, 300, $letter-spacing: -0.05em), + $display-3: mat.define-typography-level(56px, 56px, 400, $letter-spacing: -0.02em), + $display-2: mat.define-typography-level(45px, 48px, 400, $letter-spacing: -0.005em), + $display-1: mat.define-typography-level(34px, 40px, 400), + $headline: mat.define-typography-level(24px, 32px, 400), + $title: mat.define-typography-level(18px, 26px, 500), + $subheading-2: mat.define-typography-level(16px, 28px, 400), + $subheading-1: mat.define-typography-level(15px, 24px, 400), + $body-2: mat.define-typography-level(14px, 24px, 500), + $body-1: mat.define-typography-level(14px, 20px, 400), + $caption: mat.define-typography-level(12px, 20px, 400), + $button: mat.define-typography-level(14px, 14px, 500), + $input: mat.define-typography-level(14px, 1.125, 400) +); + +// Define the palettes for your theme using the Material Design palettes available in palette.scss +// (imported above). For each palette, you can optionally specify a default, lighter, and darker +// hue. Available color palettes: https://material.io/design/color/ +$kc-primary: mat.define-palette( + ( + 50: #e8eaf6, + 100: #c5cae9, + 200: #9fa8da, + 300: #7986cb, + 400: #5c6bc0, + 500: #3f51b5, + 600: #3949ab, + 700: #303f9f, + 800: #283593, + 900: #1a237e, + A100: #8c9eff, + A200: #536dfe, + A400: #3d5afe, + A700: #304ffe, + contrast: ( + 50: #000000, + 100: #000000, + 200: #000000, + 300: #ffffff, + 400: #ffffff, + 500: #ffffff, + 600: #ffffff, + 700: #ffffff, + 800: #ffffff, + 900: #ffffff, + A100: #000000, + A200: #ffffff, + A400: #ffffff, + A700: #ffffff + ) + ) +); + +$kc-success: mat.define-palette( + ( + 50: #e0f8ea, + 100: #b3efcb, + 200: #80e4a8, + 300: #4dd985, + 400: #26d06b, + 500: #00c851, + 600: #00c24a, + 700: #00bb40, + 800: #00b437, + 900: #00a727, + A100: #d1ffd8, + A200: #9effae, + A400: #6bff83, + A700: #52ff6d, + contrast: ( + 50: #000000, + 100: #000000, + 200: #000000, + 300: #000000, + 400: #000000, + 500: #ffffff, + 600: #ffffff, + 700: #ffffff, + 800: #ffffff, + 900: #ffffff, + A100: #000000, + A200: #000000, + A400: #000000, + A700: #000000 + ) + ) +); + +$kc-warn: mat.define-palette( + ( + 50: #fff7e7, + 100: #ffebc2, + 200: #ffdd99, + 300: #ffcf70, + 400: #ffc552, + 500: #ffbb33, + 600: #ffb52e, + 700: #ffac27, + 800: #ffa420, + 900: #ff9614, + A100: #ffffff, + A200: #fffdfb, + A400: #ffe4c8, + A700: #ffd8ae, + contrast: ( + 50: #000000, + 100: #000000, + 200: #000000, + 300: #000000, + 400: #000000, + 500: #000000, + 600: #000000, + 700: #000000, + 800: #000000, + 900: #000000, + A100: #000000, + A200: #000000, + A400: #000000, + A700: #000000 + ) + ) +); + +$kc-accent: mat.define-palette( + ( + 50: #ebf8fa, + 100: #cdeef3, + 200: #ace3ec, + 300: #8ad8e4, + 400: #71cfde, + 500: #58c7d8, + 600: #50c1d4, + 700: #47bace, + 800: #3db3c8, + 900: #2da6bf, + A100: #ffffff, + A200: #cef6ff, + A400: #9bedff, + A700: #81e9ff, + contrast: ( + 50: #000000, + 100: #000000, + 200: #000000, + 300: #000000, + 400: #000000, + 500: #000000, + 600: #000000, + 700: #000000, + 800: #000000, + 900: #000000, + A100: #000000, + A200: #000000, + A400: #000000, + A700: #000000 + ) + ) +); + +$kc-danger: mat.define-palette( + ( + 50: #fde0f1, + 100: #f9b3dd, + 200: #f680c6, + 300: #f24daf, + 400: #ef269d, + 500: #ec008c, + 600: #ea0084, + 700: #e70079, + 800: #e4006f, + 900: #df005c, + A100: #ffffff, + A200: #ffd3e2, + A400: #ffa0c1, + A700: #ff86b0, + contrast: ( + 50: #000000, + 100: #000000, + 200: #000000, + 300: #000000, + 400: #ffffff, + 500: #ffffff, + 600: #ffffff, + 700: #ffffff, + 800: #ffffff, + 900: #ffffff, + A100: #000000, + A200: #000000, + A400: #000000, + A700: #000000 + ) + ) +); + +/* Theme Pink */ +$kc-primary-pink: mat.define-palette( + ( + 50: #fde0f1, + 100: #f9b3dd, + 200: #f680c6, + 300: #f24daf, + 400: #ef269d, + 500: #ec008c, + 600: #ea0084, + 700: #e70079, + 800: #e4006f, + 900: #df005c, + A100: #ffffff, + A200: #ffd3e2, + A400: #ffa0c1, + A700: #ff86b0, + contrast: ( + 50: #000000, + 100: #000000, + 200: #000000, + 300: #ffffff, + 400: #ffffff, + 500: #ffffff, + 600: #ffffff, + 700: #ffffff, + 800: #ffffff, + 900: #ffffff, + A100: #000000, + A200: #ffffff, + A400: #ffffff, + A700: #ffffff + ) + ) +); + +$kc-accent-pink: mat.define-palette( + ( + 50: #e8f6fc, + 100: #c5e9f7, + 200: #9edbf2, + 300: #77cdec, + 400: #5ac2e8, + 500: #3db7e4, + // Main Color + 600: #37b0e1, + 700: #2fa7dd, + 800: #279fd9, + 900: #1a90d1, + A100: #ffffff, + A200: #d2eeff, + A400: #9fdaff, + A700: #85d1ff, + contrast: ( + 50: #000000, + 100: #000000, + 200: #000000, + 300: #000000, + 400: #000000, + 500: #000000, + 600: #000000, + 700: #000000, + 800: #000000, + 900: #ffffff, + A100: #000000, + A200: #000000, + A400: #000000, + A700: #000000 + ) + ) +); + +// The warn palette is optional (defaults to red). +$kc-warn: mat.define-palette(mat.$red-palette); + +$kc-theme-foreground: ( + elevation: #000, + divider: rgba(82, 63, 105, 0.06) +); + +$kc-theme-background: ( + app-bar: #ebebee +); + +// Create the theme object (a Sass map containing all of the palettes). +// 01. Light Theme +$kc-theme: ( + primary: $kc-primary, + accent: $kc-accent, + success: $kc-success, + warn: $kc-warn, + danger: $kc-danger, + is-dark: false, + foreground: map_merge(mat.$light-theme-foreground-palette, $kc-theme-foreground), + background: map_merge(mat.$light-theme-background-palette, $kc-theme-background) +); + +// 02. Dark Theme +$kc-dark-theme-background: ( + background: lighten($sidenav-background, 5), + card: $sidenav-background, + app-bar: darken($sidenav-background, 5), + dialog: $sidenav-background, + status-bar: darken($sidenav-background, 5) +); + +$kc-dark-theme: ( + primary: $kc-primary, + accent: $kc-accent, + success: $kc-success, + warn: $kc-warn, + danger: $kc-danger, + is-dark: true, + foreground: mat.$dark-theme-foreground-palette, + background: map_merge(mat.$dark-theme-background-palette, $kc-dark-theme-background) +); + +// 03. pink Theme +$kc-light-pink-theme: mat.define-light-theme($kc-primary-pink, $kc-accent-pink); + +// Extend Material varibles that was remove on 13 version +$swift-ease-in-out-duration: 500ms; +$swift-ease-in-out-timing-function: cubic-bezier(0.35, 0, 0.25, 1); +$swift-ease-out-duration: 400ms; +$swift-ease-out-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1); +$swift-ease-in-duration: 300ms; +$swift-ease-in-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + +$dark-primary-text: rgba(0, 0, 0, 0.87); +$light-primary-text: #fff; +$dark-secondary-text: rgba(0, 0, 0, 0.54); +$light-secondary-text: hsla(0, 0%, 100%, 0.7); +$dark-disabled-text: rgba(0, 0, 0, 0.38); +$light-disabled-text: hsla(0, 0%, 100%, 0.5); + +.kc-style-dark { + $dark-primary-text: #fff; + $light-primary-text: rgba(0, 0, 0, 0.87); + $dark-secondary-text: rgba(0, 0, 0, 0.54); + $light-secondary-text: hsla(0, 0%, 100%, 0.7); + $dark-disabled-text: rgba(0, 0, 0, 0.38); + $light-disabled-text: hsla(0, 0%, 100%, 0.5); +} diff --git a/frontend/projects/sdk-ui/assets/styles/components/_btn.scss b/frontend/projects/sdk-ui/assets/styles/components/_btn.scss new file mode 100644 index 0000000..7b4d2a5 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/components/_btn.scss @@ -0,0 +1,166 @@ +$primary: #4164a9; +$info: #b9d4ff; +$warn: #ffbb33; +$warn-dark: #ff8800; +$success: #00c851; +$success-dark: #007e33; +$error: #ff4444; +$error-dark: #cc0000; +$grey: rgb(82, 81, 81); +$grey-dark: #212121; + +.btn { + font-size: 14px; + font-weight: 500; + color: #ffffff !important; + + &.btn-default { + background: var(--background-close-btn) !important; + color: var(--text-color) !important; + } + + &.btn-primary { + background: var(--brand) !important; + } + + &.btn-accent { + background: var(--color-primary) !important; + } + + &.btn-danger { + background: var(--color-danger); + color: #ffffff; + } + + &.btn-default-outline { + border: 2px solid var(--background-close-btn) !important; + color: var(--background-close-btn) !important; + } + + &.btn-primary-outline { + border: 2px solid var(--brand) !important; + color: var(--brand) !important; + } + + &.btn-accent-outline { + border: 2px solid var(--color-primary) !important; + color: var(--color-primary) !important; + } + + &.btn-danger-outline { + border: 2px solid $error-dark !important; + color: $error-dark !important; + } + + &.round { + border-radius: 27px !important; + } +} + +%btn { + color: $grey-dark; + background-color: rgba(65, 100, 169, 0.07); + font-weight: 500; + border-radius: 2px; + justify-content: center; + align-items: center; + border-radius: 3px; + line-height: 36px; + padding: 0px 12px; + display: flex; + height: 36px; +} + +// Button +.btn { + &-primary { + @extend %btn; + color: $primary; + background-color: #4164a925; + } + + &-info { + @extend %btn; + color: var(--color-info); + background-color: #4285f425; + } + + &-success { + @extend %btn; + color: $success; + background-color: #4164a914; + } + + &-warn { + @extend %btn; + color: $warn; + background-color: #ffbb3325; + } + + &-error { + @extend %btn; + color: $primary; + background-color: #4164a914; + } +} + +// Kc Buttons +.kc-btn { + width: 140px; + height: 35px; + + // Sizes + &-sm { + height: 40px; + } + &-xs { + height: 35px; + } + + // Button Colors + &-default { + background: #e0e0e0; + box-shadow: + 0px 2px 2px rgba(0, 0, 0, 0.24), + 0px 0px 2px rgba(0, 0, 0, 0.12); + border-radius: 2px; + color: $grey; + } + &-outline { + border: 1px solid var(--text-color) !important; + } + &-outline.outline-secondary { + border: 1px solid var(--color-secondary) !important; + } + &-primary { + color: white !important; + background: var(--color-primary) !important; + box-shadow: 0px 4px 8px rgba(65, 100, 169, 0.3); + border-radius: 2px; + } + &-secondary { + color: white !important; + background: var(--color-secondary) !important; + box-shadow: 0px 4px 8px rgba(65, 100, 169, 0.3); + border-radius: 2px; + } + &-secondary > span { + color: white !important; + } + &-warning { + color: #f9f9f9 !important; + background: var(--color-danger) !important; + box-shadow: 0px 4px 8px rgba(255, 61, 0, 0.3) !important; + border-radius: 4px; + } + + // View toggler button + &-view { + background: var(--box-container-bg) !important; + svg { + path { + fill: var(--text-color); + } + } + } +} diff --git a/frontend/projects/sdk-ui/assets/styles/components/_filter.scss b/frontend/projects/sdk-ui/assets/styles/components/_filter.scss new file mode 100644 index 0000000..23776bb --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/components/_filter.scss @@ -0,0 +1,272 @@ +.filter { + &-form { + background: var(--background); + border: 1px solid var(--border); + border-radius: 30px; + padding: 0 8px; + display: flex; + align-items: center; + max-width: 300px; + + input { + background-color: transparent; + border: 0; + color: var(--text-color); + letter-spacing: 0.3px; + width: 100%; + font-size: 13px; + + &::placeholder { + color: var(--text-color); + } + } + + button { + color: var(--text-color); + width: 38px; + height: 38px; + line-height: 38px; + + .mat-icon { + font-size: 16px !important; + height: 16px !important; + width: 16px !important; + line-height: 16px !important; + } + } + } + + &-view { + &__btn { + path { + fill: #c4c4c4; + } + + &.active { + path { + fill: var(--color-primary); + } + } + } + } + + &-chart-label { + margin-top: -10px; + + .item { + margin-right: 20px; + font-size: 13px; + margin-top: 12px; + } + + .box { + width: 18px; + height: 18px; + border-radius: 4px; + margin-right: 10px; + } + } +} + +.kc-filters { + // &.visible-bg { + // background-color: var(--background-card-2); + // } + .filter__form { + display: flex; + align-items: center; + background: #f9f9f9; + border: 1px solid; + border-color: var(--border); + padding: 0 3px 0 5px; + border-radius: 25px; + + input { + border: 0; + width: 100%; + background: transparent; + padding: 8px 0; + font-size: 14px; + + &:focus-visible { + outline: none; + } + } + + button { + &.clear-search { + color: red !important; + } + + &.mat-icon-button { + height: unset; + line-height: unset; + } + + .mat-icon { + font-size: 20px; + } + } + } + + .filter__btn { + background: var(--color-primary) !important; + color: var(--white) !important; + border-radius: 27px; + font-size: 15px; + text-align: center; + letter-spacing: 1px; + padding: 0px 30px; + border: 1px solid var(--color-primary); + transition: all 0.3s linear; + + &:hover { + background: transparent !important; + color: var(--color-primary) !important; + } + } + + // Mat + .mat-form-field { + width: 100%; + font-size: 14px; + } + + .mat-form-field-appearance-outline { + .mat-form-field-wrapper { + margin: 0; + padding: 0; + } + + .mat-form-field-infix { + padding: 11px 0; + border-top-width: 4px; + } + + &.mat-form-field-can-float.mat-form-field-should-float .mat-form-field-label, + &.mat-form-field-can-float .mat-input-server:focus + .mat-form-field-label-wrapper .mat-form-field-label { + transform: translateY(-18px) scale(0.8); + } + .mat-form-field-flex { + margin-top: 0; + } + + .mat-select-arrow-wrapper { + transform: none; + } + + // hover + .mat-form-field-outline-thick .mat-form-field-outline-start, + .mat-form-field-outline-thick .mat-form-field-outline-end, + .mat-form-field-outline-thick .mat-form-field-outline-gap { + border-width: 1px; + } + } +} + +.kc-style-dark { + .kc-filters { + input { + &::placeholder { + color: rgba($color: #ffffff, $alpha: 0.6); + } + } + + .filter__form { + background: #1a2c4a; + border-color: #495c7d; + + input { + background: transparent; + color: white; + } + + button { + color: #fff; + } + } + + // Mat + .mat-form-field-appearance-outline .mat-form-field-outline { + background: #1a2c4a; + } + } +} + +// Selector item filter Search +.select_search { + font-size: 13px; + + &::placeholder { + color: var(--text-color); + } + + &_wrapper { + position: sticky; + top: 0; + z-index: 1020; + width: 100%; + background: var(--background-info-name-box); + padding: 10px 16px; + border-bottom: 1px solid var(--border); + display: flex; + + .mat-icon-button { + $size: 22px; + height: $size; + width: $size; + line-height: $size; + } + + .mat-icon { + $size: 19px !important; + font-size: $size; + } + } +} + +.region_filter_form_field { + width: 100%; + font-size: 14px; + + &.mat-form-field-appearance-outline { + .mat-form-field-wrapper { + margin: 0; + padding: 0; + } + + .mat-form-field-infix { + padding: 14px 0; + border-top-width: 0px; + } + + .mat-select-arrow-wrapper { + transform: none; + } + + // hover + .mat-form-field-outline-thick .mat-form-field-outline-start, + .mat-form-field-outline-thick .mat-form-field-outline-end, + .mat-form-field-outline-thick .mat-form-field-outline-gap { + border-width: 1px; + } + } + + &.mat-form-field-type-mat-select { + &:not(.mat-form-field-disabled) .mat-form-field-flex { + padding-left: 15px; + } + } +} + +// Filter form field Used: ... +.filter-form-field { + height: 40px !important; + border: 1px solid var(--border) !important; + border-radius: 50px !important; + + .mat-form-field-infix { + padding: 2px !important; + margin-top: -3px !important; + } +} diff --git a/frontend/projects/sdk-ui/assets/styles/components/_form.scss b/frontend/projects/sdk-ui/assets/styles/components/_form.scss new file mode 100644 index 0000000..7cfdec7 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/components/_form.scss @@ -0,0 +1,12 @@ +/* --------------- Form Input Group Card ------------------- */ +.input-group-card { + --input-group-card-padding-x: 13px; + --input-group-card-padding-y: 10px; + --input-group-card-border-size: 1.5px; + --input-group-card-border-color: var(--border); + + border: var(--input-group-card-border-size) solid var(--input-group-card-border-color); + background: var(--background-1); + padding: var(--input-group-card-padding-y) var(--input-group-card-padding-x); + border-radius: 4px; +} diff --git a/frontend/projects/sdk-ui/assets/styles/components/_icon.scss b/frontend/projects/sdk-ui/assets/styles/components/_icon.scss new file mode 100644 index 0000000..7fb4518 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/components/_icon.scss @@ -0,0 +1,45 @@ +.kc-style { + &-dark { + .region_svg { + $_color: #c5ceda; + + path { + fill: $_color; + } + + circle { + stroke: $_color; + } + } + + .node_svg { + $_color: #e4eaf1; + + path { + stroke: $_color; + } + } + } + + &-light { + .region_svg { + $_color: #06090e; + + path { + fill: $_color; + } + + circle { + stroke: $_color; + } + } + + .node_svg { + $_color: #06090e; + + path { + stroke: $_color; + } + } + } +} diff --git a/frontend/projects/sdk-ui/assets/styles/components/_status.scss b/frontend/projects/sdk-ui/assets/styles/components/_status.scss new file mode 100644 index 0000000..c0143c7 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/components/_status.scss @@ -0,0 +1,25 @@ +@import '../var'; + +.status { + &__btn { + padding: 7px 18px; + border-radius: 18px; + font-weight: 500; + background: var(--gray); + color: #f9f9f9; + } + + &--bg-succeeded, + &--bg-running { + background: var(--color-success) !important; + } + &--bg-pending { + background: var(--color-warn) !important; + } + &--bg-failed { + background: var(--color-danger) !important; + } + // &.unknown { + // background: $grey!important; + // } +} diff --git a/frontend/projects/sdk-ui/assets/styles/components/index.scss b/frontend/projects/sdk-ui/assets/styles/components/index.scss new file mode 100644 index 0000000..46981cb --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/components/index.scss @@ -0,0 +1,6 @@ +@import './status'; +@import './form'; +@import './table'; +@import './btn'; +@import './filter'; +@import './icon'; diff --git a/frontend/projects/sdk-ui/assets/styles/components/table/_table-accordion.scss b/frontend/projects/sdk-ui/assets/styles/components/table/_table-accordion.scss new file mode 100644 index 0000000..add0397 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/components/table/_table-accordion.scss @@ -0,0 +1,143 @@ +/* +* Accordion Table used in mostly in the application details feature +*/ + +$acc-table-prefix: acc-table; + +.#{$acc-table-prefix} { + // Table + display: table; + width: 100%; + table-layout: auto; + + .border-left { + position: relative; + + &:after { + content: ''; + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); + height: 17px; + width: 1.5px; + background-color: var(--text-color); + border-radius: 2px; + } + } + + &-row { + display: table-row; + vertical-align: middle; + width: 100%; + } + + &-cell { + display: table-cell; + vertical-align: inherit; + + &:not(:first-child) { + padding-left: 15px; + } + } + + // Accordion + &-accordion { + display: block; + + .mat-expansion-indicator { + position: absolute; + top: 11px; + right: 15px; + } + + .mat-expansion-panel { + margin: 8px 0; + border-radius: 6px !important; + background: var(--background); + + &-header { + height: 54px; + + &[aria-disabled='true'] { + color: var(--text-color); + } + } + + &:not(.#{$acc-table-prefix}-header) { + border: 1px solid var(--border); + } + + // Table header + &.#{$acc-table-prefix}-header { + .mat-expansion-panel-header { + background: rgba(89, 132, 219, 0.103) !important; + &.mat-expanded, + &.mat-expanded:focus, + &.mat-expanded:hover { + background: transparent !important; + } + } + } + } + + // Expended + .mat-expanded { + .mat-expansion-indicator { + top: 25px; + } + } + + .mat-expansion-panel-header { + font-size: 13px; + line-height: 23px; + padding-right: 40px; + background: var(--background) !important; + &[aria-disabled='true'] { + cursor: default; + } + + &.mat-expanded, + &.mat-expanded:focus, + &.mat-expanded:hover { + background: var(--background-1) !important; + } + } + + .mat-expansion-panel-content { + border-top: 1px solid var(--border); + } + + .mat-expansion-panel-body { + padding-top: 16px; + } + } + + // None Accordion + &-static { + .#{$acc-table-prefix} { + &-body, + &-header { + margin: 8px 0; + border-radius: 6px; + padding: 12px 24px; + } + &-header { + background: var(--background-kc-stepper); + } + &-body { + background: var(--background); + line-height: 33px; + } + } + + a.#{$acc-table-prefix}-body { + cursor: pointer; + display: block; + transition: border 0.3s linear; + &:hover { + border-color: var(--color-primary); + } + } + } +} diff --git a/frontend/projects/sdk-ui/assets/styles/components/table/_table-kc.scss b/frontend/projects/sdk-ui/assets/styles/components/table/_table-kc.scss new file mode 100644 index 0000000..59ff1dc --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/components/table/_table-kc.scss @@ -0,0 +1,36 @@ +/* +* KC Table used in over the project +*/ + +.kc-table { + width: 100%; + + &__container { + overflow-y: auto; + } +} + +@media (max-width: 1279px) { + .ltXl\:responsive { + width: 1279px; + } +} + +@media (max-width: 1023px) { + .kc-table\:responsive, + .ltLg\:responsive { + width: 1023px; + } +} + +@media (max-width: 767px) { + .ltMd\:responsive { + width: 767px; + } +} + +@media (max-width: 639px) { + .ltSm\:responsive { + width: 639px; + } +} diff --git a/frontend/projects/sdk-ui/assets/styles/components/table/_table-label.scss b/frontend/projects/sdk-ui/assets/styles/components/table/_table-label.scss new file mode 100644 index 0000000..2d2ca5c --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/components/table/_table-label.scss @@ -0,0 +1,52 @@ +/* +* Table Label is for preview inner table data +*/ + +.table-label { + &__container { + border: 1px solid var(--border); + padding: 1rem; + border-radius: 5px; + } + + width: 100%; + background-color: var(--background-table); + text-align: left; + border-radius: 4px; + overflow: hidden; + + th { + background: var(--background-table-th); + + &.border-left { + position: relative; + + &::after { + content: ''; + height: 12px; + width: 1px; + background: var(--text-color); + position: absolute; + left: 0; + top: 50%; + transform: translate(-50%, -50%); + } + } + } + + th, + td { + padding: 10px 16px; + font-weight: 400; + } + + tbody { + tr { + border-bottom: 1px solid var(--border); + + &:last-child { + border-bottom: 0; + } + } + } +} diff --git a/frontend/projects/sdk-ui/assets/styles/components/table/_table-ui.scss b/frontend/projects/sdk-ui/assets/styles/components/table/_table-ui.scss new file mode 100644 index 0000000..86b6eb0 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/components/table/_table-ui.scss @@ -0,0 +1,35 @@ +/* +* Table UI used in dashboard page +*/ + +.table { + &-ui { + width: 100%; + border: 1px solid var(--border); + border-radius: 4px; + background: var(--background); + position: relative; + overflow: hidden; + min-width: 570px; + + .inner-container { + //height: 221px; + // overflow-y: scroll; + // padding-bottom: 40px; + &::-webkit-scrollbar-track { + box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1); + background: var(--background-info-name-box); + } + + &::-webkit-scrollbar { + width: 6px; + height: 6px; + background: var(--background-kc-stepper); + } + + &::-webkit-scrollbar-thumb { + background: var(--background-kc-stepper); + } + } + } +} diff --git a/frontend/projects/sdk-ui/assets/styles/components/table/index.scss b/frontend/projects/sdk-ui/assets/styles/components/table/index.scss new file mode 100644 index 0000000..5e3114e --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/components/table/index.scss @@ -0,0 +1,4 @@ +@import './table-kc'; +@import './table-ui'; +@import './table-accordion'; +@import './table-label'; diff --git a/frontend/projects/sdk-ui/assets/styles/core.scss b/frontend/projects/sdk-ui/assets/styles/core.scss new file mode 100644 index 0000000..c6ad057 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/core.scss @@ -0,0 +1,853 @@ +@use '@angular/material' as mat; +@import './var'; + +// Custom Theming for Angular Material +// For more information: https://material.angular.io/guide/theming + +// Include the common styles for Angular Material. We include this here so that you only +// have to load a single css file for Angular Material in your app. +// Be sure that you only ever include this mixin once! +@include mat.core($config); + +// Include theme styles for core and each component used in your app. +// Alternatively, you can import and @include the theme mixins for each component +// that you are using. +@include mat.all-component-themes($kc-theme); + +// Partials +@import './root'; +@import 'partials/_mixins.scss'; +@import 'partials/_horizontal.scss'; +@import 'partials/_vertical.scss'; +@import 'partials/_print.scss'; +@import 'partials/_overrides.scss'; +@import 'partials/_scrollbar.scss'; +@import 'partials/plugins/_angular-material.scss'; +@import 'partials/plugins/_apexcharts.scss'; + +// Styles +@import 'partials/styles/_style-dark.scss'; +@import 'partials/styles/_style-light.scss'; +@import 'partials/styles/_style-light-pink.scss'; + +// Icon +@import '_fonticon.scss'; + +// Plus imports for other components in your app. +/* Global Custom Components */ +@import 'components'; +/* Library/Plugin overrides */ +@import 'plugins'; + +/* You can add global styles to this file, and also import other style files */ +html { + box-sizing: border-box; + font-size: 16px; + height: 100%; +} + +body { + height: 100%; + font-size: 0.875rem; + font-family: var(--font); + color: var(--text-color); + line-height: 1.5; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +div { + box-sizing: border-box; +} + +$md-font-size-h4: 14px; +$md-font-size-tab: 13px; +$md-font-size-commit-p: 12px; +$md-font-size-commit-small: 10px; + +%kc-card { + background-color: #ffffff; + box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.08); + border-radius: 2px; + margin: 10px 0; +} + +.text-primary { + color: var(--brand-2); +} + +.text-success { + color: $success; +} + +.text-error { + color: $error !important; +} + +.text-grey { + color: $grey; +} + +.text-dark { + color: $grey-dark; +} + +.text-info { + color: var(--color-info); +} + +.text-warn { + color: #ff5722; +} + +// Universal Styles ---> + +.txt-md { + font-size: 15px; +} + +.txt-semi-md { + font-size: 13px; +} + +.txt-semi-lg { + font-size: 17px; +} + +.txt-semi-bold { + font-weight: 600; +} + +.line-h-27 { + line-height: 27px; +} + +/* Extra large devices (large laptops and desktops, 1200px and up) */ +@media only screen and (min-width: 1200px) { + .txt-md { + font-size: 16px; + } + + .txt-semi-md { + font-size: 14px; + } + + .txt-semi-lg { + font-size: 18px; + } +} + +// <--- Universal Styles +.md-drppicker, +.double { + width: 499px !important; +} + +.sidenav { + box-shadow: 6px 0px 18px rgba(0, 0, 0, 0.06); +} + +img.loader { + width: 50px; +} + +.text-capitalize { + text-transform: capitalize; +} + +.mat-expansion-indicator { + &:after { + color: var(--text-color) !important; + border-color: unset !important; + content: 'Details'; + } +} + +.form-control { + @extend %kc-card; + width: auto; + padding: 13px 21px; + + input { + width: 100%; + + &:focus { + outline: none; + } + } +} + +.form-error { + color: rgb(231, 85, 97); + font-size: 12px; +} + +@keyframes moving-gradient { + 0% { + background-position: -250px 0; + } + + 100% { + background-position: 250px 0; + } +} + +@keyframes blinker { + from { + opacity: 1; + } + + to { + opacity: 0.3; + } +} + +.text-dots-on-overflow { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.blink { + text-decoration: blink; + animation-name: blinker; + animation-duration: 0.6s; + animation-iteration-count: infinite; + animation-timing-function: ease-in-out; + animation-direction: alternate; + -webkit-animation-name: blinker; + -webkit-animation-duration: 0.6s; + -webkit-animation-iteration-count: infinite; + -webkit-animation-timing-function: ease-in-out; + -webkit-animation-direction: alternate; +} + +.grayscale { + -webkit-filter: grayscale(100%); + /* Safari 6.0 - 9.0 */ + filter: grayscale(100%); +} + +.bucketExplorer { + mat-tab-header { + background: #fff !important; + } + + .mat-tab-label { + min-width: 33%; + height: 55px; + } +} + +mat-expansion-panel { + border-radius: 0px !important; + + mat-expansion-panel-header { + &:hover { + background: rgba(65, 100, 169, 0.2) !important; + } + } +} + +kc-application-details, +kc-log-form, +kc-vpc-monitoring { + .mat-form-field-underline { + display: none !important; + } +} + +///////////////////////Media queries //////////////////////// +@media screen and (max-width: 1500px) { + .subheading-2, + h4 { + font: unset !important; + } + + kc-toolbar-notifications-dropdown { + .notification { + padding: 5px 20px !important; + } + + .dropdown-header { + padding: 5px 20px !important; + + .dropdown-heading { + font-size: 14px; + } + + .dropdown-subheading { + font-size: 12px; + } + } + + ic-icon { + font-size: 14px; + } + + .notification-label { + font-size: 12px; + } + + .notification-description { + font-size: 12px; + } + + .dropdown-footer { + padding: 0px !important; + } + } + + kc-toolbar-user { + .user-name { + font-weight: 400; + } + + mat-icon { + height: 16px; + width: 16px; + } + } + + kc-toolbar-user-dropdown { + .notification { + padding: 5px 20px !important; + } + + mat-icon { + font-size: 17px !important; + height: 16px !important; + width: 17px !important; + } + + .dropdown-header { + padding: 5px 20px !important; + + .dropdown-heading { + font-size: 14px !important; + } + } + + .notification-label, + span { + font-size: 12px !important; + } + + .notification-description { + font-size: 10px !important; + } + + .dropdown-footer { + mat-icon { + vertical-align: unset !important; + } + + padding: 0px !important; + } + + .dropdown-footer-select { + vertical-align: unset !important; + } + } + + /* kc-breadcrumbs { + a { + font-size: 12px !important; + } + + ic-icon { + font-size: 16px !important; + } + }*/ + .kc-application-list { + mat-icon { + font-size: 30px !important; + } + + .body-2 { + font: unset !important; + + span { + font-size: 14px !important; + } + } + + .text-secondary { + .app-status { + font-size: 12px !important; + } + } + + .footer-container { + div { + font-size: 11px; + padding: 2px 4px; + } + } + } + + .mat-stroked-button { + min-width: unset !important; + } + + button { + ic-icon { + font-size: 16px !important; + } + } + + h1 { + font-weight: 400 !important; + } + + .title { + font-size: 16px !important; + } + + .log-header-table { + tr { + td { + font-size: 12px !important; + } + } + } + + .stream { + h6 { + font-size: 12px !important; + } + } + + .sidenav-items { + a, + .item-label { + font-size: 14px !important; + } + + mat-icon { + font-size: 20px !important; + margin-top: 3px !important; + } + + .item { + min-height: unset !important; + } + } + + mat-expansion-panel-header { + font-size: 13px !important; + } + + .mat-expansion-panel-body { + font-size: 13px !important; + } + + h4 { + font-size: $md-font-size-h4; + } + + .card-btn { + height: unset !important; + } + + .mat-tab-label-content { + font-size: $md-font-size-tab; + } + + .commit-item { + p { + font-size: $md-font-size-commit-p + 2; + font-weight: 500; + } + + .git-commit-id { + font-size: $md-font-size-commit-small + 2 !important; + font-weight: 400 !important; + margin-top: 0 !important; + } + + small { + font-size: $md-font-size-commit-small + 2; + } + } + + .pipeline-container { + p { + font-size: $md-font-size-commit-small + 2 !important; + } + } + + .pipeline-step-details-view-container { + .header-title { + font-weight: 500 !important; + font-size: 16px !important; + margin-bottom: 0px; + padding-bottom: 0px; + } + + .body-container { + p, + a { + font-size: 13px !important; + } + } + } + + .console-log-container { + width: 120px !important; + + .header-container { + font-size: $md-font-size-commit-small + 4 !important; + } + } + + .headline { + font-size: 16px !important; + } + + .mat-form-field, + mat-select, + input { + font-size: 13px !important; + } + + button { + font-size: 13px !important; + } + + .cdk-overlay-pane { + mat-icon { + font-size: 16px !important; + } + } + + .cdk-overlay-container { + mat-dialog-container { + .mat-dialog-title { + font-size: 14px !important; + } + + mat-dialog-content { + .avatar { + height: 60px !important; + width: 60px !important; + } + + h3 { + font-size: 16px !important; + font-weight: 400 !important; + } + } + } + } + + .mat-cell, + .mat-footer-cell { + font-size: 13px; + + mat-icon { + font-size: 19px !important; + } + } + + .mat-menu-item { + line-height: 32px !important; + height: 32px !important; + } + + .dirName { + h3 { + font-size: 14px !important; + } + } + + kc-application-form { + mat-expansion-panel-header { + height: auto !important; + position: relative; + + mat-panel-title { + p { + font-size: 14px !important; + font-weight: 500 !important; + } + } + } + + .kc-application-type { + .card { + img { + width: 40px !important; + height: 40px !important; + } + + .body-2 { + span { + font-size: 13px !important; + } + } + } + } + + .block { + font-size: 14px !important; + } + + .mat-vertical-stepper-header { + padding: 10px 24px !important; + } + + .mat-checkbox-label { + font-size: 13px; + } + } + + .kc-app-env-list { + .card { + .relative { + padding: 8px !important; + } + } + } + + .resource-config { + h3 { + font-size: 13px !important; + font-weight: 500 !important; + } + } + + .kc-vpc-list { + .card { + p { + font-size: 13px !important; + } + + .body-2 { + span { + font-size: 13px !important; + } + } + + .vpc-status { + font-size: 12px !important; + } + } + } + + .kc-vpc-form, + .kc-bucket-form { + .radio-label { + font-size: 16px !important; + } + + .icon { + img { + width: 50px; + height: 50px; + margin-top: 20%; + } + } + + .box { + .card { + .kc-cpu { + font-size: 32px; + } + + .display-1 { + span { + font-size: 18px; + } + } + + .body-2 { + span { + font-size: 13px; + } + } + } + } + + .right { + img { + min-width: 120px !important; + max-width: 120px !important; + width: 120px !important; + margin: 0 auto; + } + + .card { + .total { + font-size: 20px !important; + } + } + } + + .price-table { + tr { + td { + padding: 10px 20px; + } + } + + .display-1 { + font-size: 16px !important; + } + } + } +} + +.mat-dialog-container { + background: var(--background-card) !important; + border: solid 1px var(--dialog-border-color); +} + +.kc-style-dark { + .mat-table { + background: var(--sidenav-background); + } + + mat-button-toggle-group { + .mat-button-toggle-button { + background: var(--background-kc-stepper); + } + + .mat-button-toggle-checked { + .mat-button-toggle-button { + background: var(--background-info-name-box); + } + } + } +} + +.bg-app-bar { + background: var(--toolbar-background) !important; +} + +.spin-item { + animation-name: spin; + animation-duration: 5000ms; + animation-iteration-count: infinite; + animation-timing-function: linear; +} + +@keyframes spin { + from { + transform: rotate(0deg); + } + + to { + transform: rotate(360deg); + } +} + +.h-min-full { + min-height: 85vh; +} + +.txt-sm { + font-size: 12px; +} + +.mt--10 { + margin-top: -10px; +} + +/* KC Switch Button */ +.kc-switch { + position: relative; + display: inline-block; + width: 60px; + height: 34px; + + input { + opacity: 0; + width: 0; + height: 0; + } + + .kc-switch-slider { + position: absolute; + cursor: pointer; + top: 8px; + left: 8px; + right: 0; + bottom: 0; + border-radius: 34px; + background-color: #ccc; + -webkit-transition: 0.4s; + transition: 0.4s; + + &:before { + position: absolute; + content: ''; + height: 20px; + width: 20px; + left: 3px; + bottom: 3px; + border-radius: 50%; + background-color: white; + transition: 0.4s; + -webkit-transition: 0.4s; + } + } + + .failed { + background-color: darkred; + } + + .kc-switch-inp:checked + .kc-switch-slider { + background-color: #52bacc; + } + + .kc-switch-inp:focus + .kc-switch-slider { + box-shadow: 0 0 1px #2196f3; + } + + .kc-switch-inp:checked + .kc-switch-slider:before { + -webkit-transform: translateX(26px); + -ms-transform: translateX(26px); + transform: translateX(26px); + } +} + +//Changing Angular Material Typography +$custom-typography: mat.define-typography-config( + $font-family: 'Open Sans, sans-serif' +); +@include mat.core($custom-typography); +//Changing Angular Material Typography + +/* KC Switch Button */ +.kc-text-xs { + font-size: 10px; +} + +.kc-scroll-overlay { + overflow: scroll; + /* Hide scrollbar for IE, Edge and Firefox */ + -ms-overflow-style: none; + /* IE and Edge */ + scrollbar-width: none; + + /* Firefox */ + /* Hide scrollbar for Chrome, Safari and Opera */ + &::-webkit-scrollbar { + display: none; + } +} + +mat-paginator { + background: none !important; +} + +.log-dialog-content { + max-height: calc(100vh - 105px) !important; +} + +// Disabled Link +.route-disabled { + pointer-events: none; + cursor: default; +} diff --git a/frontend/projects/sdk-ui/assets/styles/partials/_horizontal.scss b/frontend/projects/sdk-ui/assets/styles/partials/_horizontal.scss new file mode 100644 index 0000000..04e408b --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/partials/_horizontal.scss @@ -0,0 +1,50 @@ +.horizontal-layout { + --navigation-height: 0px; + --toolbar-width: 100%; + + @screen xl { + --toolbar-width: calc(100% - var(--sidenav-width)); + + &.sidenav-collapsed { + --toolbar-width: calc(100% - var(--sidenav-collapsed-width)); + } + } + + .sidenav-container { + /* When the sidenav is not fixed, stretch the sidenav container to fill the available space. This + causes `` to act as our scrolling element for desktop layouts. */ + flex: 1; + } + + &.has-fixed-footer { + &.scroll-disabled .content { + height: calc(100% - var(--toolbar-height) - var(--footer-height)); + } + } +} + +@screen xl { + body:not([dir='rtl']) { + .horizontal-layout { + &.sidenav-collapsed .sidenav-content { + margin-left: var(--sidenav-collapsed-width) !important; + } + + &:not(.sidenav-collapsed) .sidenav-content { + margin-left: var(--sidenav-width) !important; + } + } + } + + [dir='rtl'] { + .horizontal-layout { + &.sidenav-collapsed .sidenav-content { + margin-right: var(--sidenav-collapsed-width) !important; + } + + &:not(.sidenav-collapsed) .sidenav-content { + margin-right: var(--sidenav-width) !important; + } + } + } +} diff --git a/frontend/projects/sdk-ui/assets/styles/partials/_mixins.scss b/frontend/projects/sdk-ui/assets/styles/partials/_mixins.scss new file mode 100644 index 0000000..11db38d --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/partials/_mixins.scss @@ -0,0 +1,107 @@ +@function _get-umbra-map($color, $opacity) { + $shadow-color: if(type-of($color) == color, rgba($color, $opacity * 0.2), $color); + + @return ( + 0: '0px 0px 0px 0px #{$shadow-color}', + 1: '0px 2px 1px -1px #{$shadow-color}', + 2: '0px 3px 1px -2px #{$shadow-color}', + 3: '0px 3px 3px -2px #{$shadow-color}', + 4: '0px 2px 4px -1px #{$shadow-color}', + 5: '0px 3px 5px -1px #{$shadow-color}', + 6: '0px 3px 5px -1px #{$shadow-color}', + 7: '0px 4px 5px -2px #{$shadow-color}', + 8: '0px 5px 5px -3px #{$shadow-color}', + 9: '0px 5px 6px -3px #{$shadow-color}', + 10: '0px 6px 6px -3px #{$shadow-color}', + 11: '0px 6px 7px -4px #{$shadow-color}', + 12: '0px 7px 8px -4px #{$shadow-color}', + 13: '0px 7px 8px -4px #{$shadow-color}', + 14: '0px 7px 9px -4px #{$shadow-color}', + 15: '0px 8px 9px -5px #{$shadow-color}', + 16: '0px 8px 10px -5px #{$shadow-color}', + 17: '0px 8px 11px -5px #{$shadow-color}', + 18: '0px 9px 11px -5px #{$shadow-color}', + 19: '0px 9px 12px -6px #{$shadow-color}', + 20: '0px 10px 13px -6px #{$shadow-color}', + 21: '0px 10px 13px -6px #{$shadow-color}', + 22: '0px 10px 14px -6px #{$shadow-color}', + 23: '0px 11px 14px -7px #{$shadow-color}', + 24: '0px 11px 15px -7px #{$shadow-color}' + ); +} + +@function _get-penumbra-map($color, $opacity) { + $shadow-color: if(type-of($color) == color, rgba($color, $opacity * 0.14), $color); + + @return ( + 0: '0px 0px 0px 0px #{$shadow-color}', + 1: '0px 1px 1px 0px #{$shadow-color}', + 2: '0px 2px 2px 0px #{$shadow-color}', + 3: '0px 3px 4px 0px #{$shadow-color}', + 4: '0px 4px 5px 0px #{$shadow-color}', + 5: '0px 5px 8px 0px #{$shadow-color}', + 6: '0px 6px 10px 0px #{$shadow-color}', + 7: '0px 7px 10px 1px #{$shadow-color}', + 8: '0px 8px 10px 1px #{$shadow-color}', + 9: '0px 9px 12px 1px #{$shadow-color}', + 10: '0px 10px 14px 1px #{$shadow-color}', + 11: '0px 11px 15px 1px #{$shadow-color}', + 12: '0px 12px 17px 2px #{$shadow-color}', + 13: '0px 13px 19px 2px #{$shadow-color}', + 14: '0px 14px 21px 2px #{$shadow-color}', + 15: '0px 15px 22px 2px #{$shadow-color}', + 16: '0px 16px 24px 2px #{$shadow-color}', + 17: '0px 17px 26px 2px #{$shadow-color}', + 18: '0px 18px 28px 2px #{$shadow-color}', + 19: '0px 19px 29px 2px #{$shadow-color}', + 20: '0px 20px 31px 3px #{$shadow-color}', + 21: '0px 21px 33px 3px #{$shadow-color}', + 22: '0px 22px 35px 3px #{$shadow-color}', + 23: '0px 23px 36px 3px #{$shadow-color}', + 24: '0px 24px 38px 3px #{$shadow-color}' + ); +} + +@function _get-ambient-map($color, $opacity) { + $shadow-color: if(type-of($color) == color, rgba($color, $opacity * 0.12), $color); + + @return ( + 0: '0px 0px 0px 0px #{$shadow-color}', + 1: '0px 1px 3px 0px #{$shadow-color}', + 2: '0px 1px 5px 0px #{$shadow-color}', + 3: '0px 1px 8px 0px #{$shadow-color}', + 4: '0px 1px 10px 0px #{$shadow-color}', + 5: '0px 1px 14px 0px #{$shadow-color}', + 6: '0px 1px 18px 0px #{$shadow-color}', + 7: '0px 2px 16px 1px #{$shadow-color}', + 8: '0px 3px 14px 2px #{$shadow-color}', + 9: '0px 3px 16px 2px #{$shadow-color}', + 10: '0px 4px 18px 3px #{$shadow-color}', + 11: '0px 4px 20px 3px #{$shadow-color}', + 12: '0px 5px 22px 4px #{$shadow-color}', + 13: '0px 5px 24px 4px #{$shadow-color}', + 14: '0px 5px 26px 4px #{$shadow-color}', + 15: '0px 6px 28px 5px #{$shadow-color}', + 16: '0px 6px 30px 5px #{$shadow-color}', + 17: '0px 6px 32px 5px #{$shadow-color}', + 18: '0px 7px 34px 6px #{$shadow-color}', + 19: '0px 7px 36px 6px #{$shadow-color}', + 20: '0px 8px 38px 7px #{$shadow-color}', + 21: '0px 8px 40px 7px #{$shadow-color}', + 22: '0px 8px 42px 7px #{$shadow-color}', + 23: '0px 9px 44px 8px #{$shadow-color}', + 24: '0px 9px 46px 8px #{$shadow-color}' + ); +} + +@function kc-elevation($zValue, $color: #523f68, $opacity: 0.3) { + @if type-of($zValue) != number or not unitless($zValue) { + @error '$zValue must be a unitless number'; + } + @if $zValue < 0 or $zValue > 24 { + @error '$zValue must be between 0 and 24'; + } + + @return #{map-get(_get-umbra-map($color, $opacity), $zValue)}, #{map-get(_get-penumbra-map($color, $opacity), $zValue)}, + #{map-get(_get-ambient-map($color, $opacity), $zValue)}; +} diff --git a/frontend/projects/sdk-ui/assets/styles/partials/_overrides.scss b/frontend/projects/sdk-ui/assets/styles/partials/_overrides.scss new file mode 100644 index 0000000..72eb087 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/partials/_overrides.scss @@ -0,0 +1,18 @@ +.ic-inline > svg { + display: inline-block; +} + +ic-icon:not(.ic-inline) > svg, +.iconify:not(.ic-inline) > svg { + margin: 0 auto; + vertical-align: middle; +} + +.kc-scrollbar { + min-height: 0; +} + +.kc-scrollblock { + position: fixed; + width: 100%; +} diff --git a/frontend/projects/sdk-ui/assets/styles/partials/_print.scss b/frontend/projects/sdk-ui/assets/styles/partials/_print.scss new file mode 100644 index 0000000..6c4449b --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/partials/_print.scss @@ -0,0 +1,37 @@ +@media print { + html, + body { + height: auto !important; + overflow: initial !important; + } + + .toolbar, + .sidenav { + display: none !important; + } + + .content { + margin-top: 0 !important; + } + + .mat-drawer-container { + overflow: visible !important; + } + + .mat-drawer-side { + border-right: none !important; + } + + .sidenav-content { + margin-left: 0 !important; + background-color: var(--background-card); + } + + .footer { + display: none !important; + } + + .config-panel-toggle { + display: none !important; + } +} diff --git a/frontend/projects/sdk-ui/assets/styles/partials/_scrollbar.scss b/frontend/projects/sdk-ui/assets/styles/partials/_scrollbar.scss new file mode 100644 index 0000000..223848d --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/partials/_scrollbar.scss @@ -0,0 +1,22 @@ +body.is-blink { + ::-webkit-scrollbar { + background-color: rgba(0, 0, 0, 0); + height: var(--blink-scrollbar-width); + width: var(--blink-scrollbar-width); + } + + ::-webkit-scrollbar:hover { + background-color: rgba(0, 0, 0, 0.12); + } + + ::-webkit-scrollbar-thumb { + border: 2px solid transparent; + border-radius: var(--blink-scrollbar-width); + box-shadow: inset 0 0 0 12px rgba(0, 0, 0, 0.37); + } + + ::-webkit-scrollbar-thumb:active { + border-radius: var(--blink-scrollbar-width); + box-shadow: inset 0 0 0 12px rgba(0, 0, 0, 0.54); + } +} diff --git a/frontend/projects/sdk-ui/assets/styles/partials/_vertical.scss b/frontend/projects/sdk-ui/assets/styles/partials/_vertical.scss new file mode 100644 index 0000000..d7a3244 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/partials/_vertical.scss @@ -0,0 +1,30 @@ +.vertical-layout { + --toolbar-width: 100%; + + kc-secondary-toolbar { + .h-14 { + display: none; + } + + .fixed { + background: none; + border-top: none; + box-shadow: none; + margin-bottom: calc(var(--padding-16) * -1); + padding-top: var(--padding-12); + position: relative; + top: 0; + } + } + + &.content-container > .sidenav-container > .sidenav-content > .content { + margin-left: auto; + margin-right: auto; + } + + &.has-fixed-footer { + &.scroll-disabled .content { + height: calc(100% - var(--toolbar-height) - var(--footer-height)); + } + } +} diff --git a/frontend/projects/sdk-ui/assets/styles/partials/plugins/_angular-calendar.scss b/frontend/projects/sdk-ui/assets/styles/partials/plugins/_angular-calendar.scss new file mode 100644 index 0000000..8b92e0f --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/partials/plugins/_angular-calendar.scss @@ -0,0 +1,193 @@ +.cal-month-view { + background: var(--background-card); + + .cal-days { + border-color: var(--foreground-divider); + + .cal-cell-row { + border-color: var(--foreground-divider); + } + } + + .cal-header .cal-cell { + font: var(--font-body-2); + padding-bottom: var(--padding-12); + padding-top: var(--padding-12); + } + + .cal-cell-row { + &:hover { + background: var(--background-hover); + } + + .cal-cell { + &:hover { + background: var(--background-hover); + } + + &.cal-open { + background: var(--background-hover); + box-shadow: var(--elevation-z4); + } + } + } + + .cal-day-cell { + min-height: 150px; + + &.cal-today { + background: var(--background-app-bar); + } + + &:not(:last-child) { + border-color: var(--foreground-divider); + } + } + + .cal-open-day-events { + background: var(--color-primary-500); + border-bottom: 1px solid var(--foreground-divider); + box-shadow: inset 0 0 4px 0 var(--text-secondary); + + > div { + align-content: center; + align-items: center; + background: var(--background-card); + box-shadow: var(--elevation-z2); + color: var(--text-dark); + display: flex; + flex-direction: row; + justify-content: flex-start; + padding-left: var(--padding); + padding-right: var(--padding); + + & + div { + margin-top: var(--padding-12); + } + + mwl-calendar-event-title { + display: flex; + flex: 1; + flex-direction: row; + + .cal-event-title { + color: var(--text-color); + flex: 1; + font: var(--font-body-1); + padding: var(--padding-12); + } + } + + .cal-event-action { + color: var(--text-secondary); + + & + .cal-event-action { + margin-left: var(--padding-12); + } + } + } + } +} + +.cal-week-view, +.cal-day-view { + background: var(--background-card); + + .cal-header { + font: var(--font-body-2); + + b { + font-weight: 500; + } + + &.cal-weekend span { + color: var(--text-secondary); + } + + &.cal-today { + background: var(--background-app-bar); + } + } + + .cal-day-headers .cal-header:hover, + .cal-day-headers .cal-drag-over { + background-color: var(--background-hover); + } + + .cal-hour { + background: var(--background-card); + + &:nth-child(odd) { + background: var(--background-card); + } + } + + .cal-hour-odd { + background: var(--background-app-bar); + } + + .cal-hour-segment { + &:hover { + background: var(--background-hover); + } + } + + .cal-time-events { + .cal-day-columns { + .cal-hour-segment { + &:hover { + background: var(--background-hover); + } + } + } + } + + .cal-event { + align-content: center; + align-items: center; + display: flex; + flex-direction: row; + justify-content: space-between; + + mwl-calendar-event-actions { + order: 2; + } + + mwl-calendar-event-title { + display: block; + flex: 1; + order: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + .cal-event-title { + outline: none; + } + } + + .cal-event-actions { + align-content: center; + align-items: center; + display: flex; + flex-direction: row; + justify-content: flex-end; + + .cal-event-action { + color: var(--text-secondary); + height: auto; + + .icon { + font-size: 18px; + padding: var(--padding-4); + } + } + } + } +} + +.cal-event-title { + color: var(--text-color); + font: var(--font-body-1); + text-decoration: none; +} diff --git a/frontend/projects/sdk-ui/assets/styles/partials/plugins/_angular-material.scss b/frontend/projects/sdk-ui/assets/styles/partials/plugins/_angular-material.scss new file mode 100644 index 0000000..48eea14 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/partials/plugins/_angular-material.scss @@ -0,0 +1,112 @@ +.mat-icon-button .mat-button-wrapper > *, +.mat-menu-item .mat-icon, +.mat-button .mat-icon { + vertical-align: middle !important; +} + +.mat-icon.iconify, +.mat-icon-button .mat-icon.iconify { + font-size: var(--default-icon-size); + height: unset; + width: unset; +} + +.mat-form-field-suffix, +.mat-form-field-prefix { + .mat-icon-button .mat-icon { + font-size: inherit; + } +} + +.mat-table { + mat-row, + mat-header-row, + mat-footer-row, + th.mat-header-cell, + td.mat-cell, + td.mat-footer-cell { + border-bottom-color: var(--foreground-divider); + } +} + +.mat-form-field { + margin-bottom: 4px; +} + +.mat-primary.mat-form-field { + .mat-form-field-prefix, + .mat-form-field-suffix { + transition: var(--trans-ease-out); + } + + &.mat-focused .mat-form-field-prefix, + &.mat-focused .mat-form-field-suffix { + color: var(--color-primary-500); + } +} + +.mat-form-field.mat-form-field-invalid { + &.mat-focused .mat-form-field-prefix, + &.mat-focused .mat-form-field-suffix { + color: var(--color-red-500); + } +} + +.mat-table td.mat-cell { + box-sizing: content-box; + padding-right: var(--padding-12); + white-space: nowrap; +} + +.mat-paginator-page-size-select.mat-form-field .mat-form-field-flex { + padding-top: 0; +} + +.mat-menu-item ic-icon { + margin-inline-end: var(--padding-16); + vertical-align: middle; + + > svg { + vertical-align: middle; + } +} + +.mat-select-panel { + font-size: 1rem; +} + +textarea.mat-input-element { + line-height: 1.5; +} + +.kc-flex-form-field { + .mat-form-field-infix { + width: 50px; + } +} + +.kc-dense-form-field { + margin-bottom: -1.34375em; + + &.mat-form-field-appearance-outline { + .mat-form-field-infix { + padding-top: 4px; + } + } +} + +.kc-tabs { + .mat-tab-label.mat-tab-label-active { + opacity: 1; + } + + .mat-tab-link.mat-tab-label-active { + opacity: 1; + } +} + +.kc-tabs-dense { + .mat-tab-label { + min-width: 0; + } +} diff --git a/frontend/projects/sdk-ui/assets/styles/partials/plugins/_apexcharts.scss b/frontend/projects/sdk-ui/assets/styles/partials/plugins/_apexcharts.scss new file mode 100644 index 0000000..b471539 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/partials/plugins/_apexcharts.scss @@ -0,0 +1,8 @@ +.apexcharts-legend-text { + margin-left: 4px; + top: -1px; +} + +body .apexcharts-tooltip.light { + background: var(--background-card); +} diff --git a/frontend/projects/sdk-ui/assets/styles/partials/styles/_style-dark.scss b/frontend/projects/sdk-ui/assets/styles/partials/styles/_style-dark.scss new file mode 100644 index 0000000..67e31b7 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/partials/styles/_style-dark.scss @@ -0,0 +1,153 @@ +@use '@angular/material' as mat; +.kc-style-dark { + @include mat.all-component-themes($kc-dark-theme); + $sidenav-background: #151f36; + $primary: #5bc4d6; + $secondary: #4164a9; + $info: #226add; + $warn: #ffbb33; + $warn-dark: #ff8800; + $success: #36c678; + $success-light: #c3eed7; + $grey: rgb(82, 81, 81); + $grey2: #495c7d; + $dark-light: #243c64; + $grey-dark: #212121; + $danger: #b1122a; + $slider: #52bacc; + + // Color + --active-box-shadow-1: none; + --status-active: #caedf3; + --color-primary: #{$primary}; + --color-secondary: #{$secondary}; + --color-dark-light: #{$dark-light}; + --color-info: #{$info}; + --color-warn: #{$warn}; + --color-success: #{$success}; + --color-success-light: #{$success-light}; + --color-danger: #{$danger}; + --color-kc-step-number-active: white; + --color-kc-step-number: #c5ceda; + --color-tomato-red: #ff6347; + + //temp + --box-container-bg: #243c64; + --box-container-bg-2: #243c64; + --create-new-app-btn-bg: #3c4a61; + + --background-selected-repo: #1f365b; + --background-block-btn-details-box: #314262; + --background-resource-type: #314262; + --background-kc-step-number-active: #495c7d; + --background-info-name-box: #22375b; + --background-pipeline-step-box: #22375b; + --background-kc-step-number: #495c7d; + --background-kc-stepper: #1a2c4a; + --background: #1a2c4a; + --background-1: #22375b; + --background-2: #67769b; + --background-3: #243c64; + --background-4: #3c4c72; + --background-5: #151f36; + --background-active: #243c64; + --border-active: #{$secondary}; + --border: #{$grey2}; + --border-form-field: #1a2c4a; + --text-color: #c5ceda; + --label-color: #{$grey2}; + --icon: #5c638b; + --background-close-btn: #3c4c72; + --commit-item-shimmer-1: var(--background); + --commit-item-shimmer-2: var(--background-3); + --white: #ffffff; + --brand: #4164a9; + --brand-lighter: #d2e1ff; + --brand-2: #52bacc; + --brand-2-lighter: #caedf3; + --grey: #bdbdbd; + --grey-lighter: #e8eefb; + + // Foreground + --background-app-bar: #{map-get(map-get($kc-dark-theme, background), app-bar)}; + + // Background + --sidenav-background: #131d35; + --footer-background: var(--background-card); + --navigation-background: #0d152f; + // --toolbar-background: #0D152F; + --toolbar-background: #0a1b33; + --toolbar-border: #0d152f; + --background-base: #0d152f; + + --container-bg: var(--background-5); + --input-bg: var(--background); + --icon: var(--text-color); + --icon-primary: var(--text-color); + + // Colors primary + --background-card: #151f36; + --background-card-2: #334155; + --border-color: #495c7d; + --footer-color: var(--text-color); + --navigation-color: var(--text-color); + --text-color: #{$light-primary-text}; + --toolbar-color: #{$light-primary-text}; + --text-color-light: #{$dark-primary-text}; + --step-bg: var(--background); + --step-active-bg: var(--background-active); + --custom-tab-active: #22375b; + --step-active-text: var(--text-color); + --step-active-number: var(--text-color); + --input-border: var(--border); + --btn-transparent-color: #e4eaf1; + --btn-transparent-background: #1a202e; + --text-color-1: #d7dce3; + --text-hint: rgba(255, 255, 255, 0.7); + + // Toolbar + --foreground-divider: #{map-get(map-get($kc-dark-theme, foreground), divider)}; + + //Search + --search-background: #1a2c4a; + + // Sidenav + --sidenav-color: var(--text-color); + + // Sidenav Item + --sidenav-item-background-active: #{darken($sidenav-background, 2)}; + --sidenav-item-color: var(--text-color); + --sidenav-item-color-active: #{$primary}; + --sidenav-item-dropdown-background: #{darken($sidenav-background, 2)}; + --sidenav-item-dropdown-background-hover: #{darken($sidenav-background, 3)}; + --sidenav-item-icon-color: #494b74; + --sidenav-item-icon-color-active: var(--color-primary-500); + --sidenav-toolbar-background: #{$sidenav-background}; + + // Navigation + --text-hint-light: #{$dark-disabled-text}; + --background-hover: #{map-get(map-get($kc-dark-theme, background), hover)}; + + // Secondary Toolbar + --text-secondary: #{$light-secondary-text}; + + // Footer + --text-secondary-light: #{$dark-secondary-text}; + --secondary-toolbar-background: var(--background-card); + + --dialog-border-color: #5c6bc0; + + // Box + --box-background: #182641; + + // Table Label + --background-table: var(--background-card); + --background-table-th: #314262; + + // CDK Icon + --cdk-icon-bg: var(--border-active); + --cdk-icon-2-bg: #dfe7f5; + --cdk-icon-2-color: var(--border-active); + + background: var(--background-base); +} diff --git a/frontend/projects/sdk-ui/assets/styles/partials/styles/_style-light-pink.scss b/frontend/projects/sdk-ui/assets/styles/partials/styles/_style-light-pink.scss new file mode 100644 index 0000000..9493fb5 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/partials/styles/_style-light-pink.scss @@ -0,0 +1,147 @@ +@use '@angular/material' as mat; +.kc-style-pink { + @include mat.all-component-themes($kc-light-pink-theme); + $sidenav-background: white; + $primary: #ec008c; + // $info: #4285F4; + // $warn: #ffbb33; + // $warn-dark: #FF8800; + // $success: #36C678; + // $success-light: #D2E1FF; + // $grey: rgb(82, 81, 81); + // $grey-dark: #212121; + $secondary: #3db7e4; + // $danger: #B1122A; + // $slider: #4164A9; + // //Color + // --active-box-shadow-1: 5px 15px 40px rgba(211, 221, 239, 0.7); + // --status-active: #CAEDF3; + --color-primary: #{$primary}; + --color-secondary: #{$secondary}; + // --color-info: #{$info}; + // --color-warn: #{$warn}; + // --color-success: #{$success}; + // --color-success-light: #{$success-light}; + // --color-danger: #{$danger}; + // --color-white: #ffffff; + --color-kc-step-number-active: var(--color-primary); + // --color-kc-step-number: white; + // --commit-item-shimmer-1: #F9FBFF; + // --commit-item-shimmer-2: #E9F0FF; + // --btn-transparent-color: #1a202e; + // --btn-transparent-background: #E4EAF1; + // --text-color-1: #3d4857; + // --color-tomato-red: #ff6347; + // //temp + --box-container-bg: #fef7fb; + --box-container-bg-2: #f2e6ed; // applicationList, + --create-new-app-btn-bg: #fde0f1; + // --background-selected-repo: #F4F7FC; + // --background-block-btn-details-box: #FFFFFF; + --background-resource-type: var(--color-primary); + // --background-kc-step-number-active: #D2E1FF; + --background-info-name-box: #fef7fb; + // --background-pipeline-step-box: #FFFFFF; + --background-kc-step-number: var(--color-primary); + --background-kc-stepper: #fef7fb; + // --background: #ffffff; + // --background-1: #F9FBFF; + // --background-2: #ffffff; + // --background-3: #ffffff; + --background-4: #fef7fb; + // --background-5: #ffffff; + --background-active: #fef7fb; + --border: #e2e2e2; + --border-active: #{$primary}; + // --border-form-field: #D2E1FF; + --text-color: #2d2d2d; + // --label-color: #D2E1FF; + // --icon: #{$grey}; + --background-close-btn: #fef7fb; + // --icon-primary: $primary; + + // --white: #ffffff; + --brand: #{$primary}; + // --brand-lighter: #D2E1FF; + // --brand-2: #52BACC; + // --brand-2-lighter: #CAEDF3; + // --grey: #BDBDBD; + // --grey-lighter: #E8EEFB; + + // --navigation-background: var(--background-card); + // --sidenav-background: #{$sidenav-background}; + // --step-bg: #F9FBFF; + --step-active-bg: var(--color-primary); + // --custom-tab-active: #E9F0FF; + // --step-active-text: #ffffff; + --step-active-number: var(--color-primary); + // --input-bg: var(--background-4); + // --input-border: var(--border); + + // // Sidenav + --toolbar-background: var(--background-base); + // --toolbar-border: #efefef; + // --sidenav-color: var(--text-color); + + // Sidenav Item + // --sidenav-item-background-active: #{darken($sidenav-background, 2)}; + // --sidenav-item-color: var(--text-color); + --sidenav-item-color-active: #{$primary}; + // --sidenav-item-dropdown-background: #{darken($sidenav-background, 2)}; + // --sidenav-item-dropdown-background-hover: #{darken($sidenav-background, 3)}; + // --sidenav-item-icon-color: #494B74; + // --sidenav-item-icon-color-active: var(--color-primary-500); + // --sidenav-toolbar-background: #{$sidenav-background}; + + // --dialog-border-color: transparent; + + // --background-card: #e2e8f0; + // --background-card-2: #e2e8f0; + // Box + --box-background: #ede9f7; + + // Table + // --background-table: #f9f6f6; + // --background-table-th: #EEEEEE; + + // CDK Icon + // --cdk-icon-bg: var(--border-active); + // --cdk-icon-2-bg: var(--color-primary-50); + // --cdk-icon-2-color: var(--border-active); + + // ? Var Override + --background-base: #fff4fa; + --toolbar-icon-color: var(--color-primary-500); + + // primary + --color-primary-50: #fde0f1; + --color-primary-100: #f9b3dd; + --color-primary-200: #f680c6; + --color-primary-300: #f24daf; + --color-primary-400: #ef269d; + --color-primary-500: #ec008c; + --color-primary-600: #ea0084; + --color-primary-700: #e70079; + --color-primary-800: #e4006f; + --color-primary-900: #df005c; + --color-primary-A100: #ffffff; + --color-primary-A200: #ffd3e2; + --color-primary-A400: #ffa0c1; + --color-primary-A700: #ff86b0; + --color-primary-contrast-50: #000000; + --color-primary-contrast-100: #000000; + --color-primary-contrast-200: #000000; + --color-primary-contrast-300: #ffffff; + --color-primary-contrast-400: #ffffff; + --color-primary-contrast-500: #ffffff; + --color-primary-contrast-600: #ffffff; + --color-primary-contrast-700: #ffffff; + --color-primary-contrast-800: #ffffff; + --color-primary-contrast-900: #ffffff; + --color-primary-contrast-A100: #000000; + --color-primary-contrast-A200: #ffffff; + --color-primary-contrast-A400: #ffffff; + --color-primary-contrast-A700: #ffffff; + + // background: var(--background-base); +} diff --git a/frontend/projects/sdk-ui/assets/styles/partials/styles/_style-light.scss b/frontend/projects/sdk-ui/assets/styles/partials/styles/_style-light.scss new file mode 100644 index 0000000..5334789 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/partials/styles/_style-light.scss @@ -0,0 +1,116 @@ +.kc-style-light { + $sidenav-background: white; + $primary: #5bc4d6; + $secondary: #4164a9; + $info: #6d90c7; + $warn: #ffbb33; + $warn-dark: #ff8800; + $success: #36c678; + $success-light: #d2e1ff; + $grey: rgb(82, 81, 81); + $grey-dark: #212121; + $danger: #b1122a; + $slider: #4164a9; + + // Color + --active-box-shadow-1: 5px 15px 40px rgba(211, 221, 239, 0.7); + --status-active: #caedf3; + --color-primary: #{$primary}; + --color-secondary: #{$secondary}; + --color-info: #{$info}; + --color-warn: #{$warn}; + --color-success: #{$success}; + --color-success-light: #{$success-light}; + --color-danger: #{$danger}; + --color-white: #ffffff; + --color-kc-step-number-active: var(--color-secondary); + --color-kc-step-number: white; + --commit-item-shimmer-1: #f9fbff; + --commit-item-shimmer-2: #e9f0ff; + --btn-transparent-color: #1a202e; + --btn-transparent-background: #e4eaf1; + --text-color-1: #3d4857; + --color-tomato-red: #ff6347; + --text-hint: rgba(0, 0, 0, 0.6); + + //temp + --box-container-bg: #d2e1ff; + --box-container-bg-2: #dae3f1; + --create-new-app-btn-bg: #d2e1ff; + + --background-selected-repo: #f4f7fc; + --background-block-btn-details-box: #ffffff; + --background-resource-type: var(--color-primary); + --background-kc-step-number-active: #d2e1ff; + --background-info-name-box: #e9f0ff; + --background-pipeline-step-box: #ffffff; + --background-kc-step-number: var(--color-secondary); + --background-kc-stepper: #f9fbff; + --background: #ffffff; + --background-1: #f9fbff; + --background-2: #ffffff; + --background-3: #ffffff; + --background-4: #f7f9fe; + --background-5: #ffffff; + --background-active: #e9f0ff; + --border: #d2e1ff; + --border-active: #{$secondary}; + --border-form-field: #d2e1ff; + --text-color: #323b6e; + --label-color: #d2e1ff; + --icon: #{$grey}; + --background-close-btn: #d2e1ff; + --icon-primary: $primary; + + --white: #ffffff; + --brand: #4164a9; + --brand-lighter: #d2e1ff; + --brand-2: #52bacc; + --brand-2-lighter: #caedf3; + --grey: #bdbdbd; + --grey-lighter: #e8eefb; + + --navigation-background: var(--background-card); + --sidenav-background: #{$sidenav-background}; + --step-bg: #1e232e; + --step-active-bg: var(--color-secondary); + --custom-tab-active: #e9f0ff; + --step-active-text: #ffffff; + --step-active-number: var(--color-secondary); + --input-bg: var(--background-4); + --input-border: var(--border); + + // Sidenav + --toolbar-background: #f5f5f8; + --toolbar-border: #efefef; + --sidenav-color: var(--text-color); + + // Sidenav Item + --sidenav-item-background-active: #{darken($sidenav-background, 2)}; + --sidenav-item-color: var(--text-color); + --sidenav-item-color-active: #{$secondary}; + --sidenav-item-dropdown-background: #{darken($sidenav-background, 2)}; + --sidenav-item-dropdown-background-hover: #{darken($sidenav-background, 3)}; + --sidenav-item-icon-color: #494b74; + --sidenav-item-icon-color-active: var(--color-primary-500); + --sidenav-toolbar-background: #{$sidenav-background}; + + --dialog-border-color: transparent; + + // --background-card: #e2e8f0; + --background-card-2: #f5f5f8; + + // Box + --box-background: #e2e8f0; + + // Table Label + --background-table: #523f680b; + --background-table-th: #eeeeee; + + // CDK Icon + --cdk-icon-bg: var(--border-active); + --cdk-icon-2-bg: var(--color-primary-50); + --cdk-icon-2-color: var(--border-active); + + background: var(--background-base); +} diff --git a/frontend/projects/sdk-ui/assets/styles/plugins/_cdk-overlay.scss b/frontend/projects/sdk-ui/assets/styles/plugins/_cdk-overlay.scss new file mode 100644 index 0000000..5844839 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/plugins/_cdk-overlay.scss @@ -0,0 +1,108 @@ +.cdk-global-overlay-wrapper, +.cdk-overlay-container { + pointer-events: none; + top: 0; + left: 0; + height: 100%; + width: 100%; +} + +.cdk-overlay-container { + position: fixed; + z-index: 1000; +} + +.cdk-overlay-container:empty { + display: none; +} + +.cdk-global-overlay-wrapper { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; + position: absolute; + z-index: 1000; +} + +.cdk-overlay-pane { + position: absolute; + pointer-events: auto; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + z-index: 1000; + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; + max-width: 100%; + max-height: 100%; +} + +.cdk-overlay-backdrop { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 1000; + pointer-events: auto; + -webkit-tap-highlight-color: transparent; + -webkit-transition: opacity 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); + -o-transition: opacity 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); + -moz-transition: opacity 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); + transition: opacity 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); + opacity: 0; +} + +.cdk-overlay-backdrop.cdk-overlay-backdrop-showing { + opacity: 1; +} + +@media screen and (-ms-high-contrast: active) { + .cdk-overlay-backdrop.cdk-overlay-backdrop-showing { + opacity: 0.6; + } +} + +.cdk-overlay-dark-backdrop { + background: rgba(0, 0, 0, 0.288); +} + +.cdk-overlay-transparent-backdrop, +.cdk-overlay-transparent-backdrop.cdk-overlay-backdrop-showing { + opacity: 0; +} + +.cdk-overlay-connected-position-bounding-box { + position: absolute; + z-index: 1000; + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -webkit-flex-direction: column; + -moz-box-orient: vertical; + -moz-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + min-width: 1px; + min-height: 1px; +} + +.cdk-global-scrollblock { + position: fixed; + width: 100%; + overflow-y: scroll; +} + +.cdk-overlay-backdrop.cdk-overlay-backdrop-showing { + background: #000 !important; + opacity: 0.5 !important; +} diff --git a/frontend/projects/sdk-ui/assets/styles/plugins/_charts.scss b/frontend/projects/sdk-ui/assets/styles/plugins/_charts.scss new file mode 100644 index 0000000..0d4a4a4 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/plugins/_charts.scss @@ -0,0 +1,12 @@ +.apexcharts-legend-series { + margin-left: 14px !important; +} + +.apexcharts-canvas { + padding-right: 5px !important; +} + +.apexcharts-tooltip { + background: var(--background-3) !important; + color: var(--text-color) !important; +} diff --git a/frontend/projects/sdk-ui/assets/styles/plugins/_owl-dt.scss b/frontend/projects/sdk-ui/assets/styles/plugins/_owl-dt.scss new file mode 100644 index 0000000..739c5fb --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/plugins/_owl-dt.scss @@ -0,0 +1,770 @@ +owl-date-time-container { + background: var(--background) !important; + + .owl-dt-control-content, + span { + color: var(--text-color) !important; + } + + .owl-dt-timer-input { + background: var(--background-info-name-box); + } + + svg { + g { + path { + fill: var(--text-color) !important; + } + } + } +} + +.owl-dialog-container { + position: relative; + pointer-events: auto; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + display: block; + padding: 1.5em; + -webkit-box-shadow: + 0 11px 15px -7px rgba(0, 0, 0, 0.2), + 0 24px 38px 3px rgba(0, 0, 0, 0.14), + 0 9px 46px 8px rgba(0, 0, 0, 0.12); + -moz-box-shadow: + 0 11px 15px -7px rgba(0, 0, 0, 0.2), + 0 24px 38px 3px rgba(0, 0, 0, 0.14), + 0 9px 46px 8px rgba(0, 0, 0, 0.12); + box-shadow: + 0 11px 15px -7px rgba(0, 0, 0, 0.2), + 0 24px 38px 3px rgba(0, 0, 0, 0.14), + 0 9px 46px 8px rgba(0, 0, 0, 0.12); + -moz-border-radius: 2px; + border-radius: 2px; + overflow: auto; + background: #fff; + color: rgba(0, 0, 0, 0.87); + width: 100%; + height: 100%; + outline: 0; +} + +.owl-dt-container, +.owl-dt-container * { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.owl-dt-container { + display: block; + font-size: 1rem; + background: #fff; + pointer-events: auto; + z-index: 1000; + overflow: auto; +} + +.owl-dt-container-row { + border-bottom: 1px solid rgba(0, 0, 0, 0.12); +} + +.owl-dt-container-row:last-child { + border-bottom: none; +} + +.owl-dt-calendar { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -webkit-flex-direction: column; + -moz-box-orient: vertical; + -moz-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + width: 100%; +} + +.owl-dt-calendar-control { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -webkit-align-items: center; + -moz-box-align: center; + -ms-flex-align: center; + align-items: center; + font-size: 1em; + width: 100%; + padding: 0.5em; + color: #000; +} + +.owl-dt-calendar-control .owl-dt-calendar-control-content { + -webkit-box-flex: 1; + -webkit-flex: 1 1 auto; + -moz-box-flex: 1; + -ms-flex: 1 1 auto; + flex: 1 1 auto; + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -webkit-justify-content: center; + -moz-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -webkit-align-items: center; + -moz-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.owl-dt-calendar-control .owl-dt-calendar-control-content .owl-dt-calendar-control-button { + padding: 0 0.8em; +} + +.owl-dt-calendar-control .owl-dt-calendar-control-content .owl-dt-calendar-control-button:hover { + background-color: rgba(0, 0, 0, 0.12); +} + +.owl-dt-calendar-main { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -webkit-flex-direction: column; + -moz-box-orient: vertical; + -moz-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-flex: 1; + -webkit-flex: 1 1 auto; + -moz-box-flex: 1; + -ms-flex: 1 1 auto; + flex: 1 1 auto; + padding: 0 0.5em 0.5em; + outline: 0; +} + +.owl-dt-calendar-view { + display: block; + -webkit-box-flex: 1; + -webkit-flex: 1 1 auto; + -moz-box-flex: 1; + -ms-flex: 1 1 auto; + flex: 1 1 auto; +} + +.owl-dt-calendar-multi-year-view { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -webkit-align-items: center; + -moz-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.owl-dt-calendar-multi-year-view .owl-dt-calendar-table { + width: -webkit-calc(100% - 3em); + width: -moz-calc(100% - 3em); + width: calc(100% - 3em); +} + +.owl-dt-calendar-multi-year-view .owl-dt-calendar-table .owl-dt-calendar-header th { + padding-bottom: 0.25em; +} + +.owl-dt-calendar-table { + width: 100%; + border-collapse: collapse; + border-spacing: 0; +} + +.owl-dt-calendar-table .owl-dt-calendar-header { + color: rgba(0, 0, 0, 0.4); +} + +.owl-dt-calendar-table .owl-dt-calendar-header .owl-dt-weekdays th { + font-size: 0.7em; + font-weight: 400; + text-align: center; + padding-bottom: 1em; +} + +.owl-dt-calendar-table .owl-dt-calendar-header .owl-dt-calendar-table-divider { + position: relative; + height: 1px; + padding-bottom: 0.5em; +} + +.owl-dt-calendar-table .owl-dt-calendar-header .owl-dt-calendar-table-divider:after { + content: ''; + position: absolute; + top: 0; + left: -0.5em; + right: -0.5em; + height: 1px; + background: rgba(0, 0, 0, 0.12); +} + +.owl-dt-calendar-table .owl-dt-calendar-cell { + position: relative; + height: 0; + line-height: 0; + text-align: center; + outline: 0; + color: rgba(0, 0, 0, 0.85); + appearance: none; + -webkit-appearance: none; + -webkit-tap-highlight-color: transparent; + -webkit-tap-highlight-color: transparent; +} + +.owl-dt-calendar-table .owl-dt-calendar-cell-content { + position: absolute; + top: 5%; + left: 5%; + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -webkit-align-items: center; + -moz-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + -moz-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 90%; + height: 90%; + font-size: 0.8em; + line-height: 1; + border: 1px solid transparent; + -moz-border-radius: 999px; + border-radius: 999px; + color: inherit; + cursor: pointer; +} + +.owl-dt-calendar-table .owl-dt-calendar-cell-out { + opacity: 0.2; +} + +.owl-dt-calendar-table .owl-dt-calendar-cell-today:not(.owl-dt-calendar-cell-selected) { + border-color: rgba(0, 0, 0, 0.4); +} + +.owl-dt-calendar-table .owl-dt-calendar-cell-selected { + color: rgba(255, 255, 255, 0.85); + background-color: #3f51b5; +} + +.owl-dt-calendar-table .owl-dt-calendar-cell-selected.owl-dt-calendar-cell-today { + -webkit-box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.85); + -moz-box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.85); + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.85); +} + +.owl-dt-calendar-table .owl-dt-calendar-cell-disabled .owl-dt-calendar-cell-content, +.owl-dt-calendar-table .owl-dt-calendar-cell-disabled { + cursor: default; +} + +.owl-dt-calendar-table .owl-dt-calendar-cell-disabled > .owl-dt-calendar-cell-content:not(.owl-dt-calendar-cell-selected) { + color: rgba(0, 0, 0, 0.4); +} + +.owl-dt-calendar-table .owl-dt-calendar-cell-disabled > .owl-dt-calendar-cell-content.owl-dt-calendar-cell-selected { + opacity: 0.4; +} + +.owl-dt-calendar-table .owl-dt-calendar-cell-disabled > .owl-dt-calendar-cell-today:not(.owl-dt-calendar-cell-selected) { + border-color: rgba(0, 0, 0, 0.2); +} + +.owl-dt-calendar-table .owl-dt-calendar-cell-active:focus > .owl-dt-calendar-cell-content:not(.owl-dt-calendar-cell-selected), +.owl-dt-calendar-table :not(.owl-dt-calendar-cell-disabled):hover > .owl-dt-calendar-cell-content:not(.owl-dt-calendar-cell-selected) { + background-color: rgba(0, 0, 0, 0.04); +} + +.owl-dt-calendar-table .owl-dt-calendar-cell-in-range { + background: rgba(63, 81, 181, 0.2); +} + +.owl-dt-calendar-table .owl-dt-calendar-cell-in-range.owl-dt-calendar-cell-range-from { + -moz-border-radius-topleft: 999px; + border-top-left-radius: 999px; + -moz-border-radius-bottomleft: 999px; + border-bottom-left-radius: 999px; +} + +.owl-dt-calendar-table .owl-dt-calendar-cell-in-range.owl-dt-calendar-cell-range-to { + -moz-border-radius-topright: 999px; + border-top-right-radius: 999px; + -moz-border-radius-bottomright: 999px; + border-bottom-right-radius: 999px; +} + +.owl-dt-timer { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -webkit-justify-content: center; + -moz-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + width: 100%; + height: 7em; + padding: 0.5em; + outline: 0; +} + +.owl-dt-timer-box { + position: relative; + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -moz-inline-box; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -webkit-flex-direction: column; + -moz-box-orient: vertical; + -moz-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-align: center; + -webkit-align-items: center; + -moz-box-align: center; + -ms-flex-align: center; + align-items: center; + width: 25%; + height: 100%; +} + +.owl-dt-timer-content { + -webkit-box-flex: 1; + -webkit-flex: 1 1 auto; + -moz-box-flex: 1; + -ms-flex: 1 1 auto; + flex: 1 1 auto; + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -webkit-justify-content: center; + -moz-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -webkit-align-items: center; + -moz-box-align: center; + -ms-flex-align: center; + align-items: center; + width: 100%; + margin: 0.2em 0; +} + +.owl-dt-timer-content .owl-dt-timer-input { + display: block; + width: 2em; + text-align: center; + border: 1px solid rgba(0, 0, 0, 0.5); + -moz-border-radius: 3px; + border-radius: 3px; + outline: medium none; + font-size: 1.2em; + padding: 0.2em; +} + +.owl-dt-timer-divider { + display: inline-block; + -webkit-align-self: flex-end; + -ms-flex-item-align: end; + align-self: flex-end; + position: absolute; + width: 0.6em; + height: 100%; + left: -0.3em; +} + +.owl-dt-timer-divider:after, +.owl-dt-timer-divider:before { + content: ''; + display: inline-block; + width: 0.35em; + height: 0.35em; + position: absolute; + left: 50%; + -moz-border-radius: 50%; + border-radius: 50%; + -webkit-transform: translateX(-50%); + -moz-transform: translateX(-50%); + -ms-transform: translateX(-50%); + transform: translateX(-50%); + background-color: currentColor; +} + +.owl-dt-timer-divider:before { + top: 35%; +} + +.owl-dt-timer-divider:after { + bottom: 35%; +} + +.owl-dt-control-button { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: pointer; + outline: 0; + border: none; + -webkit-tap-highlight-color: transparent; + display: inline-block; + white-space: nowrap; + text-decoration: none; + vertical-align: baseline; + margin: 0; + padding: 0; + background-color: transparent; + font-size: 1em; + color: inherit; +} + +.owl-dt-control-button .owl-dt-control-button-content { + position: relative; + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -moz-inline-box; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-box-pack: center; + -webkit-justify-content: center; + -moz-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -webkit-align-items: center; + -moz-box-align: center; + -ms-flex-align: center; + align-items: center; + outline: 0; +} + +.owl-dt-control-period-button .owl-dt-control-button-content { + height: 1.5em; + padding: 0 0.5em; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-transition: background-color 0.1s linear; + -o-transition: background-color 0.1s linear; + -moz-transition: background-color 0.1s linear; + transition: background-color 0.1s linear; +} + +.owl-dt-control-period-button:hover > .owl-dt-control-button-content { + background-color: rgba(0, 0, 0, 0.12); +} + +.owl-dt-control-period-button .owl-dt-control-button-arrow { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -webkit-justify-content: center; + -moz-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -webkit-align-items: center; + -moz-box-align: center; + -ms-flex-align: center; + align-items: center; + width: 1em; + height: 1em; + margin: 0.1em; + -webkit-transition: -webkit-transform 0.2s ease; + transition: -webkit-transform 0.2s ease; + -o-transition: transform 0.2s ease; + -moz-transition: + transform 0.2s ease, + -moz-transform 0.2s ease; + transition: transform 0.2s ease; + transition: + transform 0.2s ease, + -webkit-transform 0.2s ease, + -moz-transform 0.2s ease; +} + +.owl-dt-control-arrow-button .owl-dt-control-button-content { + padding: 0; + -moz-border-radius: 50%; + border-radius: 50%; + width: 1.5em; + height: 1.5em; +} + +.owl-dt-control-arrow-button[disabled] { + color: rgba(0, 0, 0, 0.4); + cursor: default; +} + +.owl-dt-control-arrow-button svg { + width: 50%; + height: 50%; + fill: currentColor; +} + +.owl-dt-inline-container, +.owl-dt-popup-container { + position: relative; + width: 18.5em; + -webkit-box-shadow: + 0 5px 5px -3px rgba(0, 0, 0, 0.2), + 0 8px 10px 1px rgba(0, 0, 0, 0.14), + 0 3px 14px 2px rgba(0, 0, 0, 0.12); + -moz-box-shadow: + 0 5px 5px -3px rgba(0, 0, 0, 0.2), + 0 8px 10px 1px rgba(0, 0, 0, 0.14), + 0 3px 14px 2px rgba(0, 0, 0, 0.12); + box-shadow: + 0 5px 5px -3px rgba(0, 0, 0, 0.2), + 0 8px 10px 1px rgba(0, 0, 0, 0.14), + 0 3px 14px 2px rgba(0, 0, 0, 0.12); +} + +.owl-dt-inline-container .owl-dt-calendar, +.owl-dt-inline-container .owl-dt-timer, +.owl-dt-popup-container .owl-dt-calendar, +.owl-dt-popup-container .owl-dt-timer { + width: 100%; +} + +.owl-dt-inline-container .owl-dt-calendar, +.owl-dt-popup-container .owl-dt-calendar { + height: 20.25em; +} + +.owl-dt-dialog-container { + max-height: 95vh; + margin: -1.5em; +} + +.owl-dt-dialog-container .owl-dt-calendar { + min-width: 250px; + min-height: 330px; + max-width: 750px; + max-height: 750px; +} + +.owl-dt-dialog-container .owl-dt-timer { + min-width: 250px; + max-width: 750px; +} + +@media all and (orientation: landscape) { + .owl-dt-dialog-container .owl-dt-calendar { + width: 58vh; + height: 62vh; + } + + .owl-dt-dialog-container .owl-dt-timer { + width: 58vh; + } +} + +@media all and (orientation: portrait) { + .owl-dt-dialog-container .owl-dt-calendar { + width: 80vw; + height: 80vw; + } + + .owl-dt-dialog-container .owl-dt-timer { + width: 80vw; + } +} + +.owl-dt-container-buttons { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; + width: 100%; + height: 2em; + color: #3f51b5; +} + +.owl-dt-container-control-button { + font-size: 1em; + width: 50%; + height: 100%; + -moz-border-radius: 0; + border-radius: 0; +} + +.owl-dt-container-control-button .owl-dt-control-button-content { + height: 100%; + width: 100%; + -webkit-transition: background-color 0.1s linear; + -o-transition: background-color 0.1s linear; + -moz-transition: background-color 0.1s linear; + transition: background-color 0.1s linear; +} + +.owl-dt-container-control-button:hover .owl-dt-control-button-content { + background-color: rgba(0, 0, 0, 0.1); +} + +.owl-dt-container-info { + padding: 0 0.5em; + cursor: pointer; + -webkit-tap-highlight-color: transparent; +} + +.owl-dt-container-info .owl-dt-container-range { + outline: 0; +} + +.owl-dt-container-info .owl-dt-container-range .owl-dt-container-range-content { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + -moz-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + padding: 0.5em 0; + font-size: 0.8em; +} + +.owl-dt-container-info .owl-dt-container-range:last-child { + border-top: 1px solid rgba(0, 0, 0, 0.12); +} + +.owl-dt-container-info .owl-dt-container-info-active { + color: #3f51b5; +} + +.owl-dt-container-disabled, +.owl-dt-trigger-disabled { + opacity: 0.35; + filter: Alpha(Opacity=35); + background-image: none; + cursor: default !important; +} + +.owl-dt-timer-hour12 { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -webkit-justify-content: center; + -moz-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -webkit-align-items: center; + -moz-box-align: center; + -ms-flex-align: center; + align-items: center; + color: #3f51b5; +} + +.owl-dt-timer-hour12 .owl-dt-timer-hour12-box { + border: 1px solid currentColor; + -moz-border-radius: 2px; + border-radius: 2px; + -webkit-transition: background 0.2s ease; + -o-transition: background 0.2s ease; + -moz-transition: background 0.2s ease; + transition: background 0.2s ease; +} + +.owl-dt-timer-hour12 .owl-dt-timer-hour12-box .owl-dt-control-button-content { + width: 100%; + height: 100%; + padding: 0.5em; +} + +.owl-dt-timer-hour12 .owl-dt-timer-hour12-box:focus .owl-dt-control-button-content, +.owl-dt-timer-hour12 .owl-dt-timer-hour12-box:hover .owl-dt-control-button-content { + background: #3f51b5; + color: #fff; +} + +.owl-dt-calendar-only-current-month .owl-dt-calendar-cell-out { + visibility: hidden; + cursor: default; +} + +.owl-dt-inline { + display: inline-block; +} + +.owl-dt-control { + outline: 0; + cursor: pointer; +} + +.owl-dt-control .owl-dt-control-content { + outline: 0; +} + +.owl-dt-control:focus > .owl-dt-control-content { + background-color: rgba(0, 0, 0, 0.12); +} + +.owl-dt-control:not(:-moz-focusring):focus > .owl-dt-control-content { + -moz-box-shadow: none; + box-shadow: none; +} + +.owl-hidden-accessible { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} diff --git a/frontend/projects/sdk-ui/assets/styles/plugins/_snackbar.scss b/frontend/projects/sdk-ui/assets/styles/plugins/_snackbar.scss new file mode 100644 index 0000000..5f95e6b --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/plugins/_snackbar.scss @@ -0,0 +1,4 @@ +.snackbar-dark { + background: #22375b !important; + color: white !important; +} diff --git a/frontend/projects/sdk-ui/assets/styles/plugins/_tooltip.scss b/frontend/projects/sdk-ui/assets/styles/plugins/_tooltip.scss new file mode 100644 index 0000000..6b60c8f --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/plugins/_tooltip.scss @@ -0,0 +1,15 @@ +//Tooltip +.mat-tooltip { + color: var(--text-color) !important; + background: var(--background-info-name-box) !important; + font-style: normal; + font-weight: normal; + font-size: 12px; + line-height: 18px; + letter-spacing: 0.3px; + padding: 11px !important; +} + +.custom-tooltip { + border: 1px solid var(--border) !important; +} diff --git a/frontend/projects/sdk-ui/assets/styles/plugins/form/_checkbox.scss b/frontend/projects/sdk-ui/assets/styles/plugins/form/_checkbox.scss new file mode 100644 index 0000000..ae8ca38 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/plugins/form/_checkbox.scss @@ -0,0 +1,79 @@ +.rounded-checkbox { + .mat-checkbox-background, + .mat-checkbox-frame { + border-radius: 50% !important; + } +} + +.mat-checkbox-checked .mat-checkbox-background, +.mat-checkbox-indeterminate .mat-checkbox-background { + background-color: var(--background-kc-step-number) !important; + + svg { + path { + stroke: #0d152f !important; + } + } +} + +mat-checkbox, +.directoryListCheckBox { + mat-icon { + float: left; + } + + .mat-checkbox-inner-container { + width: 18px; + height: 18px; + } + + .mat-checkbox-frame { + border-radius: unset; + border: 0.5px solid rgba(0, 0, 0, 0.25); + } + + mat-checkbox, + .directoryListCheckBox { + mat-icon { + float: left; + } + + .mat-checkbox-inner-container { + width: 18px; + height: 18px; + } + + .mat-checkbox-frame { + border-radius: unset; + border: 0.5px solid rgba(0, 0, 0, 0.25); + } + } +} + +@media screen and (max-width: 768px) { + table { + mat-checkbox, + .directoryListCheckBox { + .mat-checkbox-inner-container { + height: 16px !important; + width: 16px !important; + } + } + } +} + +mat-checkbox.mat-checkbox-circular .mat-checkbox-frame, +.directoryListCheckBox .mat-checkbox-frame { + border-radius: 50px; +} + +.mat-checkbox-checked .mat-checkbox-background, +.mat-checkbox-indeterminate .mat-checkbox-background { + background-color: #d7dce3 !important; + + svg { + path { + stroke: #0d152f !important; + } + } +} diff --git a/frontend/projects/sdk-ui/assets/styles/plugins/form/_input.scss b/frontend/projects/sdk-ui/assets/styles/plugins/form/_input.scss new file mode 100644 index 0000000..aa7fc15 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/plugins/form/_input.scss @@ -0,0 +1,196 @@ +.custom-mat-form-field { + width: 100% !important; + + .mat-form-field-flex { + padding: 22px 18px 0 18px !important; + background: var(--background-kc-stepper) !important; + margin-top: 0 !important; + } + + .mat-form-field-infix { + position: unset !important; + border-top: 0 !important; + padding: 0 !important; + height: 42px !important; + width: 100%; + + input { + margin-top: 0.4rem !important; + color: var(--text-color); + } + + input[type='number'] { + margin-top: 2% !important; + } + } + + .mat-form-field-label { + left: 18px !important; + padding-top: 18px !important; + } + + .mat-form-field-empty { + padding-top: 9px !important; + top: 30% !important; + + span, + mat-label { + background: var(--background) !important; + color: var(--text-color); + } + } + + .mat-form-field-label-wrapper { + position: absolute !important; + top: 0 !important; + padding-top: 0 !important; + margin-top: 0 !important; + } + + .mat-form-field-outline-gap { + border-top-color: unset !important; + } + + mat-select { + margin-top: 2% !important; + .mat-select-value { + color: var(--text-color); + } + } + + &.mat-form-field-appearance-outline .mat-form-field-prefix, + &.mat-form-field-appearance-outline .mat-form-field-suffix { + top: 1px; + } + + // Prefix icon Heigh Fix + &.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-prefix .mat-icon-button, + &.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-suffix .mat-icon-button { + .mat-icon { + font-size: 16px; + height: 15px; + } + + &.btn-eye { + width: 28px; + height: 21px; + } + } +} + +.custom-mat-form-field-full-width { + width: 100% !important; + + .mat-form-field-flex { + padding: 22px 18px 0 18px !important; + background: var(--background-kc-stepper) !important; + margin-top: 0 !important; + } + + .mat-form-field-infix { + position: unset !important; + border-top: 0 !important; + padding: 0 !important; + height: 42px !important; + + input { + margin-top: 0.4rem !important; + color: var(--text-color); + } + + input[type='number'] { + margin-top: 2% !important; + } + } + + .mat-form-field-label { + left: 18px !important; + padding-top: 18px !important; + } + + .mat-form-field-empty { + padding-top: 9px !important; + top: 30% !important; + + span, + mat-label { + background: var(--background) !important; + color: var(--text-color); + } + } + + .mat-form-field-label-wrapper { + position: absolute !important; + top: 0 !important; + padding-top: 0 !important; + margin-top: 0 !important; + } + + .mat-form-field-outline-gap { + border-top-color: unset !important; + } + + mat-select { + margin-top: 2% !important; + .mat-select-value { + color: var(--text-color); + } + } +} + +.custom-mat-form-field, +.custom-mat-form-field-full-width { + // direct mat class css + &.mat-form-field-appearance-outline .mat-form-field-flex { + border-radius: 5px; + } + + &.mat-form-field-appearance-outline .mat-form-field-outline { + color: var(--border); + font-weight: 600; + border-radius: 6px; + top: 0em !important; + } +} + +// BT/Bootstrap style/ style 2 +.bt-form-field { + &.mat-form-field-appearance-outline { + .mat-form-field-infix { + padding: 17px 0; + border-top-width: 4px; + } + .mat-select-arrow-wrapper { + transform: translate(0); + } + .mat-form-field-outline-thick .mat-form-field-outline-start, + .mat-form-field-outline-thick .mat-form-field-outline-end, + .mat-form-field-outline-thick .mat-form-field-outline-gap { + border-width: 1px; + } + } + + .mat-chip.mat-standard-chip { + background: var(--box-container-bg-2); + } + + &.mat-form-field-appearance-outline { + .mat-form-field-label { + margin-top: 2px; + } + } +} + +// ---------------------- Form View Mode --------------------- +.form-view-mode { + .mat-form-field-infix { + input { + color: var(--text-color) !important; + } + } + mat-select { + .mat-select-value { + color: var(--text-color) !important; + } + } +} diff --git a/frontend/projects/sdk-ui/assets/styles/plugins/form/_select-panel.scss b/frontend/projects/sdk-ui/assets/styles/plugins/form/_select-panel.scss new file mode 100644 index 0000000..cbaff44 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/plugins/form/_select-panel.scss @@ -0,0 +1,7 @@ +.mat-select-panel { + background: var(--background-kc-stepper) !important; + + .mat-option-text { + color: var(--text-color) !important; + } +} diff --git a/frontend/projects/sdk-ui/assets/styles/plugins/form/index.scss b/frontend/projects/sdk-ui/assets/styles/plugins/form/index.scss new file mode 100644 index 0000000..3e66369 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/plugins/form/index.scss @@ -0,0 +1,3 @@ +@import './input'; +@import './select-panel'; +@import './checkbox'; diff --git a/frontend/projects/sdk-ui/assets/styles/plugins/index.scss b/frontend/projects/sdk-ui/assets/styles/plugins/index.scss new file mode 100644 index 0000000..c9198fc --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/plugins/index.scss @@ -0,0 +1,6 @@ +@import './form'; +@import './charts'; +@import './snackbar'; +@import './tooltip'; +@import './owl-dt'; +@import './cdk-overlay'; diff --git a/frontend/projects/sdk-ui/assets/styles/tailwind.scss b/frontend/projects/sdk-ui/assets/styles/tailwind.scss new file mode 100644 index 0000000..b0462d0 --- /dev/null +++ b/frontend/projects/sdk-ui/assets/styles/tailwind.scss @@ -0,0 +1,5 @@ +@tailwind base; +@import './_base.scss'; +@tailwind components; +@tailwind utilities; +@import './_utilities.scss'; diff --git a/frontend/projects/sdk-ui/assets/webfonts/klovercloud-icon.eot b/frontend/projects/sdk-ui/assets/webfonts/klovercloud-icon.eot new file mode 100644 index 0000000000000000000000000000000000000000..7a4ebb9cd64e8640af5b94005a0e8c573792658b GIT binary patch literal 22312 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 literal 0 HcmV?d00001 diff --git a/frontend/projects/sdk-ui/assets/webfonts/klovercloud-icon.svg b/frontend/projects/sdk-ui/assets/webfonts/klovercloud-icon.svg new file mode 100644 index 0000000..ded96da --- /dev/null +++ b/frontend/projects/sdk-ui/assets/webfonts/klovercloud-icon.svg @@ -0,0 +1,67 @@ + + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/projects/sdk-ui/assets/webfonts/klovercloud-icon.ttf b/frontend/projects/sdk-ui/assets/webfonts/klovercloud-icon.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1cdcf48a6819a55053d24eba4bac63e39b6fbea3 GIT binary patch literal 22112 zcmch937j0ob$3_a-7`HiJw5mC&d%;!d*8F8V=rk}5|WV6Nw_2=fe^a);AO>Fo@);XqFpxMv?0DlN{&L{hd=^%I@j>FmG4P8C5Ic^&)B66edS-VP9X@`x zd#9^kRlT~aUcGwn)e1}y1fMV?NJ8IvTYCqBVeLZ*`8?iTmtDL2;48_8ZxsaA2>;=I zyAK`2Hw6C&@zwWD-+0AW{`k8S@PAkkHvQi#_wK&D>FDFP3&NINh#$TZ0mg^bJp70k za#vn^_=f+w%=ZiUDgXbTK5*IYKfn4PP6)!*&%*!qYj@vpP}nJ6F9_SZ;Lq&eeeK@M zd|R{dpNleHKX~BKVbl}P`4bc`NV0>PD1so~C;kIMKHz=XE5aZ%;IDres=fG`5QLY{ zmu64S3KJ4uL{eYWo(u=5GJT#h{zdpy<`{UOrTm&X&pVFE+yU|pOj2<4?5bpikEVHmBGv$B9z zbqXWG24RPAjc}uIi*T24On6-QOW|w6ap4ETtHLkX8g>yo$ZlaDXMe{2R!oRJ;*@x? zco@|v4HdF2t!fjC#Nq)~_Ze&%7#?Lqh2j{iexztb1#SV}VZ_FwrBedlgrH?x)o3KP zoDB@4oK9Bn%X7~lkI`BSCFF@LBdW3}O?Gjj?5~z;aiTM&$q!Mfs93RwWdkglX7NTA zS0mAg7GRpHm4^$(f*NE2mTfH*TU8BRlxC=LIlhd4h6}xHxID(n!=)k;rx{@6gA zBWT`_HfbuQrqFn7n6d_9K?Nc@s2W&H?S&IIyY&juq4VKVd3^(eD8oabD#Qk;)##}C)>T{M zwFFb7*gxOy`D(>$L0+!Z>@k{eMQQs$))le?;ZP_{??6_p^R=d_<(>1HX>fPD39VnW?;4h314xHmSD`Z^~{hFqUvaX00I$vs(0;(!Ynx#v+ zBJ0Q64I%ljoDr+*MR(H)OE>xU1+tARS>roBW647MT0ePt=X3pOmwjmj^ z0)&Mss5grY?ObRuGZaM=e}JZ;?y@S&^KFyGYo@XT1KFu)&hO7frXuu-o*LwSaf-%m zDwa;ip7TKR-%5V&wfUgaz*k?)ByXgrY9Wu-fZF#rLirxUI7kfRtm&8!R)YEh0h8n7 z`@6f-?V2S@s=D5`nP{LYh_u6DL#4^l(%1L4$*DDu_|TCUZ@*?GEmaXkOB+F-NS5l4 zo4k7r*^K)BTCp@t155@jprS)19o<}zG#P`98G|mTE|w(8logd-t%nU!QWV9MOvjL! zg2_<%vs1Hu=$F*lL``{>F$DnC>O9|Q)o|ZQbx>6_6cu1-nkinb+onYGQ^5cmwetTI zGo!w(3aay;XcZbGqA|Ku*D${2M`=%!zJ@)`FJy!+p)9NyF2%m~huGKd5&lGYO!zC| zdEsA$H&C4*YhXn-h+S+6>j#OB4wgWxmC_)9+P3DAzC7P%yq(4A2Q4gRqln2zvj8G7 zZ?E&{ypp9%D7RX8HX5%>4#L>UqC^ipVy0!uL*;38p@fttD$D6RXy|el^@?B4N_BxH z!eN6{8LCyS)`KO-_TZ@PRihYDv8(aD7u#v9i4~EOwrkp4X@gek>R7IW&lJx7O%G|K zT1a!>^4e(Fa-X+sEu`xKoqZsd$;9HBOdOFw(Ak}Yz8 zX4$7DlbR0%OOa#Aq!kWZ^L~n}yi|+jm^{9hkZTFq2`_7%S13H%9}BsUhhni1+Z>9m z4g3GmALh<^*XpLJlf(8?P3zvdzpC?4gcKFUjT=RA@AhREQu6CSD%pdzG?nCOVz+O{ z^c1fn>n=(6>8PHsK=SU04Yo zUjgogvoPK#&N+_-Hmrx0Xug39;cP-Rnll>21k7_!Ro-TZvnoXm{LJuBaS7{Xg;otK z4n-hMd8lu&Op_FI&W=mVtz7Pk@v#-X9UUuUaih0TELoPKM4XXAvEu>DajXYc?qEAt zT4AQ9k{kN_hq?>J5yw%)h=1kIohy$K%CX+I_EFmo21~hI$KM(ahH0?(87cF91~bf* z$u>Kd*nRLw7sBDtLIfYHS{@C;0CH*NgA|Q$7He>T4@SxBZO7v} zdqHgw+|0nj0ZS8wt9R_Uy}hli{q`L@uC9Zha=)sCbj`1R)i0Z7i}f(enk|06=#yqo z!L6oqA9X*bYO?Y%pd-fE#!2#Z!Diht!97O`X zqLTt=^3T|UtGBOPe<0J+k~y$`-S#@zy^9@r%6->UEER8QiQ_$Ui{`F4C3Q8YnWuOr zYzxl;xuA{H*k|s>KC@ETg0*v05c0(GdQIsY>i3``NHVR5rg=8mTUc0KeD*H~1*VzL zS5u*glaWWAJr=v@|BQ^O@!zKbS9{X@u-1(KIB{_I>B#@$rklsL7F$?XTl-W)gT1PE zaS@}K3q#`=pP};bKr?!A zARdbZaWaXVc}?u+OttjPGsHH5)6kxNTGLcVedZZBn)b{yns(;7RA~d>O=*b_UzDci zBZ2~+w$VkNfWJ9(je!P@* zFC;pH*K+|qC-$_qR-W&kn8@%51aZnZONd1GnGhG6lozB=3rWZg42HuMi?0M5@xVzTAtuGQ$H!y%R{oAji3DO- zAUaOvD15v=k9Cq3Mj;FNpzx10YTm}e_Z4gbnAY=WSIm4Hqs7mDUPO7giU%S-@0Khn_eIMJx%^fyS4H4HdTB;q&&Nln)rb8fR@DvFMI2POn8xa0c>rA->uv|m>J zs$$4fCh|>(KI(IjO8jhVb7p&g|7BfWlh{myfsyu(T>}FbWg{8W=W`=r+wN^_7;Q=q zN25)stKU~lCYPn#*Ecn0#Gh%38Z;K_ZUj|DdjJOuUAf4L;KYh2VqJtaBuc!>m8TY} zFK*y)rOR}5oQy?Lm2kdA3&agPq?VSBDUw*r5vYz?d5Y+P3_AQTm|q)(i!rl2rW!*< zb0CP9zBKfF78FSyLqZFWt;VdNp&Z9cUt)#%Ky#r7NoSP0HJFtS(D{8@ljMDJ*mzf@ zGvSB<<2f_HBJs}1jA1KRD3U&nCWzCz1W#C>iFC#zEMPuo1Vks%8F`lxMq){uc5hyH z)m7{0Wq10MmX-8xR~-FGU6lrdNiYz8Kb&N6P*M@-DBFJ(oFiU_>#m}8$LXYW1pTs< zB#-N3&fgL_uK5Ey|^63{>z0-=qdcF;+^@k3)U*ze9qX|MX6*qchlxAJ1*I> z<)&=bFtW*H^OoW9hQ^%}6X&cQpSTp8LU_EZbBNjQtA|X-G;B@tgEWQ$ft(Y`1p)v9 z*@!fIN4UNH(CRfCcWl{wQ!eY}+S}E&C6{Yn-gk7Pmsdl>r4!?8mkpK9&t$^)eDy1C zjv+5dR&2wFm`={JfOqBJzA;@xZkR-}Ky0bG^tyHC<+wuq3xxIL1N zi7&amvMN!Kq{<)u@abXpP3%ZOXU{LBM_!a}Ziao3eZYMSz3#!=ekNV2#`p4MC9UURPfLE3ZxxxJ{}Sm9mf)J^A-{37l8N?HY7H{u7xP#7UYIT zeD{UpFMRj-@pbQ^?B26Zo`;SL0yZDWoWFv3*(7veZk{9T5#BC50BQ4a;Z^X=SvE?e zL&H(XRvBD-F^5~v4h~}K(inLB;V1*cG>Vm63z7)%NW%PfP?aXqNY`dGE&O>j=4}u- zXM3AT$sR0aYnuT-ZzCBm;j|f-=^%dE?a4V~Wq!M9#Ffe9mZ8Dn;h~|;Nj#f}hK7d+ zhqfe>?)MMfbkiYv|FeB&YHFsPJpXy=kbSQ^J{bN4 z`YZmi@E~hKmCGdzOQX}?~6jq4j3apZ+Zz8HuERfpCQ%&G#22PbTm;Au0ks^g_$D)mp z-a$III2Wf*%C<;Ch)VJ5c=666&6o6jcjDfzu~5L*Su89i8OLC2OVNzQ#tMb@skbz* zKBSNT!R}Q{0->?ad)*bp?n_@J;ZS8o!e-NUGHJVa+lh-hMn*c4;jm_RwD}^2l~#tu*q%&NAGhPdF z|HTUlFPuq8@A*ZXM!pXn=TEWcc+&)Z-^8*QHkvmWK4KjaKm&OSKyiGaqWI3E&_tS- z)h+^Pa`D+Xi0^z1l{<)RyqJ1`CK#_m3Ez1Xs?&Vs767R_H?dQ3nn~@S4IaFTF?|V>!FlmnI0>WjTCAY7YF4HBnl>%j?OR8S>Y=zgg0WLdu;;6$&Xf zn=0&bd9IAyZg-YV%yK_+Mu3Qt>H9mVM6Hz5Hr<`6Rj-h8tc4o7Gi<_r5q&^);=LjS zK!1L$lrW!0gbC1~bA)q+&7efr3hxwd7Ct2WG3e2w3o{G@O(0oewr}FPwVOzXAF-2L6JfT&PSyf{@s_Pyf4=qS+kTGEHgY?1y}h~E z6HmIkp7?Au-`ks)KQOoQla&6GM10zT^e_PrBZuWkL|=H4NqEFtQ{nH2Q=a1x;Qqu( zJ>jHM&J&)Sa+r_8os>IyOWh*|0#jX`tE^|AwN`a@O$F|7r&3`L)%{60#mpz3aDV!y zkPF}BCySMNdx+&2!%Kv#g&QE*`;hPnjNdb`hj>BwH{o?Mub@R#9mij0_E5^diS8@J ztk&B>*l+Snb*nTI%P#WeF*S%7(dx#a0@Wi;GzYvO9#S6;Dl)(5e@S*qZEDu1s1gmW zTBKJ2Sy<9GH`}(v^7}1%m$XR}3%IN1E}z^W7o){>1RMGD6vg27xyV{m4X`2nVSXN88_Bl-uC7mT_hP&KxdBz-M zpa2sTy~xSTZ#Tzk6`!pEqELg}**7KQ-ubj=&zbfwpU`yjgnX@Z3|t)XI)5h23eO4u zB>a#m>kONB3d-fmPkR*;{8>)qT z5eK4%=&CpG#dBPTM_1#jGIh-+o(qf@o#DWQ+59kHC{mzTCTa&5Kd)7u7cMFf7e5Hs z0efD!NacCGW_VsNE4cW`JvImRX`|`Ie@VF_~MNYl(IQV{$S%8FN^qCATI=VL?;#jWlPPe8y0k z!d7URSPQIj@|i?;K$69kK+43BP)R0N#v({}P8LB24N+HvTG;Q`ldj{BLFMT8#mRL~ zN>RT*05Kfg|20KJPnkN?^`yc6$Imgy_5VbSTK<3}M*UVma*b>@yBe|>NMlx$Tl?_9 zls{qW0Zj{N5ZP%k^ZoX!gVv@hZw+&m}K&hFts2@_9>bv!Qj9M>yoJ{@B%rg znXrYB7?6=9)!N_R+S=DA-VzFWotpDHIG69B&JKolEe&->o6|le5)3v6o6_pCNPDzn zYezIKYxxX%N=Y}iZ|R71M3*X-jV?k*#YW;wffenDEJ0%QtvS++luM)Sk&bQc(Iy4G z+fr5)CxWA1`xfLEU7`f+#AFo16JK6U9IdpW(^N=UTLUnfK-YTR43|Al9UMUiqMO;L z^(1tGx{)wUrmMg+Qz9P@cYAFd2$_vWB9V5y?&l+sXdB*WB+`bLO;sblBBGmMS`pCD z-SgeVU?H=pPepVn*>NoDQ@_ajv^oF*9hs;YEsQ@Ot?oYRX1t&+be8&s+yq|65*mbd z*iWny&KLFx*9n5-u_E9~iE)t@`5f$L)$tjAWcYI*YngOYk+_~eV*OxlUojWewJeQ|@rGJJi zu6F|D2{`Ux#3IOo2%`pF3oi(Lz$TMb;E=wl(nXqe@mulCeS}B} zh)yfQ;K|qIQR!jugqOhjT1x}sBQN$L241q%UD9b^k%S9~?j-K#f4ny1^3A3?lb6GZ&I^{GGE%Jd^AbB{jxi}o= zeV~Czqs8H1Kq(R#dkGPV+<1m@t}`J!zGYrkd=JpdybgqoLogMJvG+1Yp*86kFAUjA ze`-SLOOI{t-c8C0$nzmDtRy7GlXybYyUqPmBdn5`MhzQxwI`(aCEMkhQo;bv=bOpsM$?2PrcHt0vpFbEAw zXd|UXNY7(&;DJ3H%%WthWwn8cme48Rj0F zp%YU%fZWYSife*!a5dDS0oEG`N>Vc5KJO2DvMO$K-2jd6Qel^{AC_q!gPLegChCv=B%vbul4XQe6%RyIWP|d4 z^C1zBcNGiEpvJV96^dP5#i9p8-ZOf^1*2mZT<{!5;sygEOXEhvKxc2Cd%17bsy?=y z$f^6)SaWksip83VXI|CkrrbZIaCQsa`(OoSih6IaE<*NcOz8TAVyW)Ss-+MNOP*RR zOr)+6B@t}OgcP&rBZhrq)RQ}%T0eFTui4n>1@43*-w4Yf!?*#%Co8V7s!yElUqxc0 zOsq0NwPT&UrpNnMiN`6N#7dP{pzdfehlf!w)NUO%_VtRYD(eBPL#e$f&>{6o(4^I9Lr0_hb5z@^t=gf~R@)?grF!tsd*qT&n|VQ7K>8 z4CYG~vpJCj!xDAkNX=Q8yhZf^Sj?BfTvGjQs;LJq=8kGiO0|X@CCEJHtQvMRyAm5X zc5rqDZR6r4e0#)h3j1|w*F`X#h8`4ZPg8ZjCMhtW#^y;Z1O<~Bs3NjuwE412ZUszS z0XAi+7AuPf+;6)7Z$E9*q)){jjKq?t0#m$YCr?1b@H`vzdfE|S!XgVXQ5!*Il42t%7C|kQgv`KKdd|VuvwH$Yig;|mCv#%RI z$1+2(R|f2dp_6I3Fjc7#m7egMs)AGeEWVO$5JAH`AxobzS|egA(rSE0(+IBokYGuE zLu8+kq|eZxCg4=z%8%Y~EV1JW6o*2emP2L*H4rC!hCiu1t(bl*p*+LbE+)>RG?Yaj z!x=JBqi=V`z>b{i}|?hqaUpH-y!z-ePYFTt%Vfq5mkbtSO665Q|5IoliOFJPRzU}JbLr1tL- z{s{7lnqa}(pD=pFP2OPA)^4qU=g?Lc=ZkqC(b=|8#x zHu?ZtL}BUD!W@i?byd~p1Wi>nv1CQ%YgC*Po26;B!TB3dZQPJKVVI_I!fG{i-Fn~w zpHGn^ewMRhxXa^v-~kI(4_WJk?(^vWqQeAqT&$ENMQTyM2-y#pww4=9pUc|6e_B~uAQiFVU?dA4Z}VZ7p4nOKi7 z7ihstBSf02>Y#9q7hjSt+kuDRTKL?v;ttR5T-uL(B|*dK zY6^L`M4|Pxvw0HeYQzL!i0HN==Nslt0t#n4du7G7?sr)3%X{{)_pJ)GI;)nxf5XL_ zHeH`>ZOvZ4Y1737w`K?3x33u++tH9pHS8E0TSIWFp&>=EG`pwrBbHCEaDh+cdOpX7dthyHfpER_DajBVKI+Xv z79-Tj?N7?Wa$#JU6xP57a6RfrpotS;Nf*_M zS`>f9Qn6HymrG@mg2Al2sKiUfc(h!?S%-g>vxI9^T!%8!qVXtY#Iq}E5Qr7?c(r)6 zSdMB4^}fm(!U?~ID?WDU=+Q&F55vLd=r%leZ{4=deR|`@!yAelHXPniF}7{p`XPk7 zPm>p6hc>z=fU}FdN007C!lOqI<8$=TVW6?)+qP}}$;OR;jo1x;y`l2R)~!5j+kcan z!ZxCqtrq#je=T-@uDg)Azj%Ll_x(iT^S``@C`*^QQ@~g>gOWH>FqkzTAs3-wr9rHIOjBLwHhn zR`@DxGG4%` zv8{OPB^O_L)y0?GT5RL+RabJDjYfN--P>}$VnaIL?;jjjAC?;;1D{gI2mSr|NQ1Pg zq3FwP>ju`!Sa&4R-&>cb0#Vgx1p}(%vy0JCOW4VU zmcalz(j8+rpCwC1J`@+qky^6Dwgt2Py9sj!Co2iFWMOhZe@G^QOYdTlzTt?a)1 zNZf2|Fyg+^P{u6Xx^d*HZugaqx0cLIsQaoB_cdSKXlOIzBl%cvN#q?&Q#MMv+O~5T z&B9&c;hk;Jf@s95%TSr5R~DlEsisn*X*i+iqJmAG{RfT}?}#kP{qKCHELfN6(#ShS zwek&Ir3F&pG_?W!hQUCUerMomsS5UNPqGJ*e-X2Rq&Ix355jKvhvokMbx}NP2l~ry zs^(kQ-(Qwyqfz=Ugc43I1@;OyDLf~BL3|2Ue;HWz3Dql}#N}{P5aMRZkd1g;exam{ z;wdIbeDMN@lw~_Ju@fYefV25QUnu0`&f|_`ss~k5a;7MZd9Fl=EI@9^cY-3|9CdJ; zSaNVr2!3Da_u3DtFaa3|{&2sg1t+gHpfZ=CH_+Amhi+fQY!r)Ff!R`;u7V)W6Q=b+ z-7z@Ok4{<6Bnq4to)*vIlkT;0$Aoaw$UA+_1DyAILwHKE#OH)fu(}pV@Ix0J=&r>4O$iYcmBjPS2=q)M zn?=sv5^FnuQ9`W#YlvRX?~c;#Aq{=UFIC}^MQblod(*6hJ6Pl=Nnmen+Ht`%amvj+ zJr_`lT&7Km04k-4iEp$9!>X*Op+s%YnNq~x?vF@DzS)=1(}tvmgIQlN;Lid{GMbEp znE{gH@9<-e<}zjiVO1m+^y5U{*N|jl6By{O323)Fm~2gSK^~F@$xEjCaflcDQ%QKz zpaxwN&_s*vAPs@>ZdOC;!$JRl-jw&RRDshYoh$MxNT?J`HX!p;>L^NqiOx6GaiJBw zih{`QXBUe5!~!JDxO9cJOv{){jy+3NPsl3@Wc1lFI@*zL?`TSQbchAd+cEN3M>^f! zo=$gw*X%rbTskhzfYaP0kS&R~^%l7h57ua$f3DsSuCme93&2%wx_Uzq7tVo78=|*+ zavdSK?x-@TsS&6WY3%7jFbN+a-=GU;RRSa(H_U7*naLFL+j@HX`+It}G{_K~5|?VC2;UK$!%fGWpd-2?lioc~dXtsvP@q(|YgtUa%i4H|p24|x{~ndVe7 zM+d50GS!?Z6i{j(m0HMCsa_1#Cr>f`o8CV}MGU=v(|LeKM**GJxrb-_sHn-htwYT8 z2ujUbdy;lIxtQ)bzl{F>v$(Fit!;!9D{m>AT-Z1&VJ9*^vi{|#(C{(n*mHsrX+Txi8o=T`;C z+3*kzB-E`hj_Yw<)b(xnd{PG#*FVT^8}p!TI>LDL2YG(=d*ko5Z_aXt5`{DLfH+&< zQT1@OEp*vPntybOIZ(Uk!p{f%xKK4t z7vHTXbwj@gwr_VE2HZWi-?I07&9?mEQoiz7eh82q_KRCAn~iY{;N5K`bo@VzJ>qK1 zwynyudj{$IWPWHU|0IX#AEi9$$pueHKLXF*MzXs+SOXl7PkZ(UMJbcOHBId6*@Sn} zi?2JyP-lNSebwq!n>MXleN`F{!E0s)Sjhf*!}^AlTzU5y2>yj%w?k}TW=(xU5AN>_ z6`j}9a;jlH^saT=XFXh%b#i+TmF_+=yQme*MM=Z%5HHKZvDsa-$BxY&b9WuXS%qBq zD|i_~L1Kt^U=y++PS7nbr+Pf&=G-{IfYq1yv0)C!1~J1ya*&S8SgUp>W#n;|-R^7> zLy{HlyuA(2?K|lohAhCR_6YA*2nkO?^^(oaoH_BIP?N#_Tp^1l23xhH^W*Priv6|09{{MtBAHutT zKJJ2rve{%6#z+fq$O5|`-%c-#Auo2r0!-=IgVlJ#p?AiMpU)eu!ea^%AuYX6$td4a zeyXlhKd;@OeNS)HHyJag-~1!r1yaA)JY zn=Wd4Z`14PZOs>Do^R1x&Tn~tYa%OV+p^E+^xTr%uH3!3zsa4*NAiDFxUv{7UQzr; z@xR*qZI|;A7!|J*GQ1YGk>Z}J6M(%FjW~@tZe3JisDgwis<4Fc%~et-o$2s}JlyoY}W` z|K7LmKD_tx%$^%FYcD&n;lP3YJ+J_z#vDd-_MwFRyotNv--}+z;5PS-aM$v_*Z@qz N?ZF5`hjF&&{{x-vAaMWy literal 0 HcmV?d00001 diff --git a/frontend/projects/sdk-ui/assets/webfonts/klovercloud-icon.woff b/frontend/projects/sdk-ui/assets/webfonts/klovercloud-icon.woff new file mode 100644 index 0000000000000000000000000000000000000000..2ee32e4e5dffc8515977b1a194712a11bdd4bf04 GIT binary patch literal 22188 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 literal 0 HcmV?d00001 diff --git a/frontend/projects/sdk-ui/index.ts b/frontend/projects/sdk-ui/index.ts new file mode 100644 index 0000000..2864883 --- /dev/null +++ b/frontend/projects/sdk-ui/index.ts @@ -0,0 +1 @@ +export * from './src/sdk-ui.module'; diff --git a/frontend/projects/sdk-ui/karma.conf.js b/frontend/projects/sdk-ui/karma.conf.js new file mode 100644 index 0000000..d12502b --- /dev/null +++ b/frontend/projects/sdk-ui/karma.conf.js @@ -0,0 +1,41 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + jasmine: { + // you can add configuration options for Jasmine here + // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html + // for example, you can disable the random execution with `random: false` + // or set a specific seed with `seed: 4321` + }, + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + jasmineHtmlReporter: { + suppressAll: true // removes the duplicated traces + }, + coverageReporter: { + dir: require('path').join(__dirname, '../../coverage/sdk-ui'), + subdir: '.', + reporters: [{ type: 'html' }, { type: 'text-summary' }] + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/frontend/projects/sdk-ui/ng-package.json b/frontend/projects/sdk-ui/ng-package.json new file mode 100644 index 0000000..a0bd57b --- /dev/null +++ b/frontend/projects/sdk-ui/ng-package.json @@ -0,0 +1,17 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/sdk-ui", + "lib": { + "entryFile": "index.ts", + "cssUrl": "inline", + "styleIncludePaths": ["./assets/styles"] + }, + "deleteDestPath": false, + "assets": [ + { + "glob": "**/*", + "input": "assets", + "output": "assets" + } + ] +} diff --git a/frontend/projects/sdk-ui/package.json b/frontend/projects/sdk-ui/package.json new file mode 100644 index 0000000..86e520f --- /dev/null +++ b/frontend/projects/sdk-ui/package.json @@ -0,0 +1,12 @@ +{ + "name": "@sdk-ui", + "version": "0.0.1", + "peerDependencies": { + "@angular/common": "^14.2.0", + "@angular/core": "^14.2.0" + }, + "dependencies": { + "tslib": "^2.3.0" + }, + "sideEffects": false +} diff --git a/frontend/projects/sdk-ui/src/animations/dropdown.animation.ts b/frontend/projects/sdk-ui/src/animations/dropdown.animation.ts new file mode 100644 index 0000000..7558b2b --- /dev/null +++ b/frontend/projects/sdk-ui/src/animations/dropdown.animation.ts @@ -0,0 +1,19 @@ +import { animate, state, style, transition, trigger } from '@angular/animations'; + +export const dropdownAnimation = trigger('dropdown', [ + state( + 'false', + style({ + height: 0, + opacity: 0 + }) + ), + state( + 'true', + style({ + height: '*', + opacity: 1 + }) + ), + transition('false <=> true', animate('300ms cubic-bezier(.35, 0, .25, 1)')) +]); diff --git a/frontend/projects/sdk-ui/src/animations/fade-in-right.animation.ts b/frontend/projects/sdk-ui/src/animations/fade-in-right.animation.ts new file mode 100644 index 0000000..8c21417 --- /dev/null +++ b/frontend/projects/sdk-ui/src/animations/fade-in-right.animation.ts @@ -0,0 +1,21 @@ +import { animate, style, transition, trigger } from '@angular/animations'; + +export function fadeInRightAnimation(duration: number) { + return trigger('fadeInRight', [ + transition(':enter', [ + style({ + transform: 'translateX(-20px)', + opacity: 0 + }), + animate( + `${duration}ms cubic-bezier(0.35, 0, 0.25, 1)`, + style({ + transform: 'translateX(0)', + opacity: 1 + }) + ) + ]) + ]); +} + +export const fadeInRight400ms = fadeInRightAnimation(400); diff --git a/frontend/projects/sdk-ui/src/animations/fade-in-up.animation.ts b/frontend/projects/sdk-ui/src/animations/fade-in-up.animation.ts new file mode 100644 index 0000000..5bd8581 --- /dev/null +++ b/frontend/projects/sdk-ui/src/animations/fade-in-up.animation.ts @@ -0,0 +1,21 @@ +import { animate, style, transition, trigger } from '@angular/animations'; + +export function fadeInUpAnimation(duration: number) { + return trigger('fadeInUp', [ + transition(':enter', [ + style({ + transform: 'translateY(20px)', + opacity: 0 + }), + animate( + `${duration}ms cubic-bezier(0.35, 0, 0.25, 1)`, + style({ + transform: 'translateY(0)', + opacity: 1 + }) + ) + ]) + ]); +} + +export const fadeInUp400ms = fadeInUpAnimation(400); diff --git a/frontend/projects/sdk-ui/src/animations/index.ts b/frontend/projects/sdk-ui/src/animations/index.ts new file mode 100644 index 0000000..7e1a213 --- /dev/null +++ b/frontend/projects/sdk-ui/src/animations/index.ts @@ -0,0 +1 @@ +export * from './public-api'; diff --git a/frontend/projects/sdk-ui/src/animations/ng-package.json b/frontend/projects/sdk-ui/src/animations/ng-package.json new file mode 100644 index 0000000..1dc0b0b --- /dev/null +++ b/frontend/projects/sdk-ui/src/animations/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "index.ts" + } +} diff --git a/frontend/projects/sdk-ui/src/animations/popover.animation.ts b/frontend/projects/sdk-ui/src/animations/popover.animation.ts new file mode 100644 index 0000000..45b6046 --- /dev/null +++ b/frontend/projects/sdk-ui/src/animations/popover.animation.ts @@ -0,0 +1,35 @@ +import { animate, group, style, transition, trigger } from '@angular/animations'; + +export const popoverAnimation = trigger('transformPopover', [ + transition(':enter', [ + style({ + opacity: 0, + transform: 'scale(0.6)' + }), + group([ + animate( + '100ms linear', + style({ + opacity: 1 + }) + ), + animate( + '150ms cubic-bezier(0, 0, 0.2, 1)', + style({ + transform: 'scale(1)' + }) + ) + ]) + ]), + transition(':leave', [ + style({ + opacity: 1 + }), + animate( + '100ms linear', + style({ + opacity: 0 + }) + ) + ]) +]); diff --git a/frontend/projects/sdk-ui/src/animations/public-api.ts b/frontend/projects/sdk-ui/src/animations/public-api.ts new file mode 100644 index 0000000..a83c051 --- /dev/null +++ b/frontend/projects/sdk-ui/src/animations/public-api.ts @@ -0,0 +1,8 @@ +export * from './dropdown.animation'; +export * from './fade-in-right.animation'; +export * from './fade-in-up.animation'; +export * from './popover.animation'; +export * from './scale-fade-in.animation'; +export * from './scale-in-out.animation'; +export * from './scale-in.animation'; +export * from './stagger.animation'; diff --git a/frontend/projects/sdk-ui/src/animations/scale-fade-in.animation.ts b/frontend/projects/sdk-ui/src/animations/scale-fade-in.animation.ts new file mode 100644 index 0000000..5a36309 --- /dev/null +++ b/frontend/projects/sdk-ui/src/animations/scale-fade-in.animation.ts @@ -0,0 +1,21 @@ +import { animate, style, transition, trigger } from '@angular/animations'; + +export function scaleFadeInAnimation(duration: number) { + return trigger('scaleFadeIn', [ + transition(':enter', [ + style({ + transform: 'scale(0.8)', + opacity: 0 + }), + animate( + `${duration}ms cubic-bezier(0.35, 0, 0.25, 1)`, + style({ + transform: 'scale(1)', + opacity: 1 + }) + ) + ]) + ]); +} + +export const scaleFadeIn400ms = scaleFadeInAnimation(400); diff --git a/frontend/projects/sdk-ui/src/animations/scale-in-out.animation.ts b/frontend/projects/sdk-ui/src/animations/scale-in-out.animation.ts new file mode 100644 index 0000000..513fdcb --- /dev/null +++ b/frontend/projects/sdk-ui/src/animations/scale-in-out.animation.ts @@ -0,0 +1,30 @@ +import { animate, style, transition, trigger } from '@angular/animations'; + +export const scaleInOutAnimation = trigger('scaleInOut', [ + transition(':enter', [ + style({ + transform: 'scale(0)', + opacity: 0 + }), + animate( + '0.2s cubic-bezier(0.35, 0, 0.25, 1)', + style({ + transform: 'scale(1)', + opacity: 1 + }) + ) + ]), + transition(':leave', [ + style({ + transform: 'scale(1)', + opacity: 1 + }), + animate( + '0.2s cubic-bezier(0.35, 0, 0.25, 1)', + style({ + transform: 'scale(0)', + opacity: 0 + }) + ) + ]) +]); diff --git a/frontend/projects/sdk-ui/src/animations/scale-in.animation.ts b/frontend/projects/sdk-ui/src/animations/scale-in.animation.ts new file mode 100644 index 0000000..0b34a89 --- /dev/null +++ b/frontend/projects/sdk-ui/src/animations/scale-in.animation.ts @@ -0,0 +1,19 @@ +import { animate, style, transition, trigger } from '@angular/animations'; + +export function scaleInAnimation(duration: number) { + return trigger('scaleIn', [ + transition(':enter', [ + style({ + transform: 'scale(0)' + }), + animate( + `${duration}ms cubic-bezier(0.35, 0, 0.25, 1)`, + style({ + transform: 'scale(1)' + }) + ) + ]) + ]); +} + +export const scaleIn400ms = scaleInAnimation(400); diff --git a/frontend/projects/sdk-ui/src/animations/stagger.animation.ts b/frontend/projects/sdk-ui/src/animations/stagger.animation.ts new file mode 100644 index 0000000..7c87ac7 --- /dev/null +++ b/frontend/projects/sdk-ui/src/animations/stagger.animation.ts @@ -0,0 +1,15 @@ +import { animateChild, query, stagger, transition, trigger } from '@angular/animations'; + +export function staggerAnimation(timing: number) { + return trigger('stagger', [ + transition('* => *', [ + // each time the binding value changes + query('@fadeInUp, @fadeInRight, @scaleIn', stagger(timing, animateChild()), { optional: true }) + ]) + ]); +} + +export const stagger80ms = staggerAnimation(80); +export const stagger60ms = staggerAnimation(60); +export const stagger40ms = staggerAnimation(40); +export const stagger20ms = staggerAnimation(20); diff --git a/frontend/projects/sdk-ui/src/components/base-route-pagination.component.ts b/frontend/projects/sdk-ui/src/components/base-route-pagination.component.ts new file mode 100644 index 0000000..b6139d3 --- /dev/null +++ b/frontend/projects/sdk-ui/src/components/base-route-pagination.component.ts @@ -0,0 +1,78 @@ +import { inject } from '@angular/core'; +import { PageEvent } from '@angular/material/paginator'; +import { ActivatedRoute, QueryParamsHandling, Router } from '@angular/router'; +import { Subject } from 'rxjs'; +import { mapTo, startWith, switchMap, tap } from 'rxjs/operators'; + +type queryParams = { + page: number; + pagelen: number; + [key: string]: any; +}; + +type TPaginationConfig = { + page: number; + pagelen: number; + pageSizeOption: number[]; +}; + +export class BasePaginationRoute { + protected route = inject(ActivatedRoute); + protected router = inject(Router); + + protected _destroyed$ = new Subject(); + + protected startingPage!: number; + + protected queryParams!: queryParams; + protected pageSizeOptions!: number[]; + protected totalElements: number = 0; + protected elements: T[] = []; + + protected isLoaded = false; + protected isLoading = true; + + private refreshEvent$ = new Subject(); + + protected routeQueryParam$ = this.route.queryParams.pipe( + switchMap(_qp => { + const { page, pagelen } = _qp; + this.queryParams.page = page || this.startingPage; + if (pagelen) this.queryParams.pagelen = pagelen; + return this.refreshEvent$.pipe(startWith(undefined), mapTo(_qp)); + }) + ); + + constructor(config?: Partial) { + this.startingPage = config?.page || 0; + this.queryParams = { + page: this.startingPage, + pagelen: config?.pagelen || 12 + }; + this.pageSizeOptions = config?.pageSizeOption || [12, 24, 36]; + } + + protected updateRouteQueryParams(qp: Partial, queryParamsHandling: QueryParamsHandling = 'merge'): void { + this.router.navigate([], { + relativeTo: this.route, + queryParams: qp, + queryParamsHandling + }); + } + + // Pagination + protected handlePageEvent(event: PageEvent) { + const qp = { + page: event.pageIndex, + pagelen: event.pageSize + }; + this.updateRouteQueryParams(qp); + } + + /** + * @description Refresh with current query param state + */ + public refresh() { + this.refreshEvent$.next(); + } +} diff --git a/frontend/projects/sdk-ui/src/components/base-table.componenet.ts b/frontend/projects/sdk-ui/src/components/base-table.componenet.ts new file mode 100644 index 0000000..b71cf1c --- /dev/null +++ b/frontend/projects/sdk-ui/src/components/base-table.componenet.ts @@ -0,0 +1,22 @@ +import { ChangeDetectorRef } from '@angular/core'; + +export class BaseTableComponenet { + initialSelection = []; + allowMultiSelect = true; + selection: any; + tableValue = []; + + constructor(protected cdr: ChangeDetectorRef) {} + + /** Whether the number of selected elements matches the total number of rows. */ + protected isAllSelected() { + const numSelected = this.selection.selected.length; + const numRows = this.tableValue.length; + return numSelected === numRows; + } + + /** Selects all rows if they are not all selected; otherwise clear selection. */ + protected masterToggle() { + this.isAllSelected() ? this.selection.clear() : this.tableValue.forEach(row => this.selection.select(row)); + } +} diff --git a/frontend/projects/sdk-ui/src/components/index.ts b/frontend/projects/sdk-ui/src/components/index.ts new file mode 100644 index 0000000..d1640ba --- /dev/null +++ b/frontend/projects/sdk-ui/src/components/index.ts @@ -0,0 +1,2 @@ +export * from './base-table.componenet'; +export * from './base-route-pagination.component'; diff --git a/frontend/projects/sdk-ui/src/components/ng-package.json b/frontend/projects/sdk-ui/src/components/ng-package.json new file mode 100644 index 0000000..1dc0b0b --- /dev/null +++ b/frontend/projects/sdk-ui/src/components/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "index.ts" + } +} diff --git a/frontend/projects/sdk-ui/src/directives/container/container.directive.spec.ts b/frontend/projects/sdk-ui/src/directives/container/container.directive.spec.ts new file mode 100644 index 0000000..80c42c6 --- /dev/null +++ b/frontend/projects/sdk-ui/src/directives/container/container.directive.spec.ts @@ -0,0 +1,8 @@ +import { ContainerDirective } from './container.directive'; + +describe('ContainerDirective', () => { + it('should create an instance', () => { + const directive = new ContainerDirective(); + expect(directive).toBeTruthy(); + }); +}); diff --git a/frontend/projects/sdk-ui/src/directives/container/container.directive.ts b/frontend/projects/sdk-ui/src/directives/container/container.directive.ts new file mode 100644 index 0000000..e96d8ed --- /dev/null +++ b/frontend/projects/sdk-ui/src/directives/container/container.directive.ts @@ -0,0 +1,12 @@ +import { Directive, HostBinding } from '@angular/core'; + +/** + * @description container can be fix width as box + * @deprecated box container styles removed + */ +@Directive({ + selector: '[kcContainer]' +}) +export class ContainerDirective { + @HostBinding('class.container') enabled!: boolean; +} diff --git a/frontend/projects/sdk-ui/src/directives/container/container.module.ts b/frontend/projects/sdk-ui/src/directives/container/container.module.ts new file mode 100644 index 0000000..eec192f --- /dev/null +++ b/frontend/projects/sdk-ui/src/directives/container/container.module.ts @@ -0,0 +1,10 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ContainerDirective } from './container.directive'; + +@NgModule({ + declarations: [ContainerDirective], + imports: [CommonModule], + exports: [ContainerDirective] +}) +export class ContainerModule {} diff --git a/frontend/projects/sdk-ui/src/directives/container/index.ts b/frontend/projects/sdk-ui/src/directives/container/index.ts new file mode 100644 index 0000000..25902a8 --- /dev/null +++ b/frontend/projects/sdk-ui/src/directives/container/index.ts @@ -0,0 +1,2 @@ +export * from './container.directive'; +export * from './container.module'; diff --git a/frontend/projects/sdk-ui/src/directives/index.ts b/frontend/projects/sdk-ui/src/directives/index.ts new file mode 100644 index 0000000..85ee15b --- /dev/null +++ b/frontend/projects/sdk-ui/src/directives/index.ts @@ -0,0 +1 @@ +export * from './container'; diff --git a/frontend/projects/sdk-ui/src/directives/ng-package.json b/frontend/projects/sdk-ui/src/directives/ng-package.json new file mode 100644 index 0000000..1dc0b0b --- /dev/null +++ b/frontend/projects/sdk-ui/src/directives/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "index.ts" + } +} diff --git a/frontend/projects/sdk-ui/src/interfaces/config.interface.ts b/frontend/projects/sdk-ui/src/interfaces/config.interface.ts new file mode 100644 index 0000000..3972bec --- /dev/null +++ b/frontend/projects/sdk-ui/src/interfaces/config.interface.ts @@ -0,0 +1,32 @@ +import { Icon } from '@visurel/iconify-angular'; +import { CSSVariable } from './css-variable.enum'; +import { ToolbarUserMenuItem } from './toolbar-menu-item.interface'; + +// Navigation +export type SidenavLink = { + id?: string; + type: 'link' | 'dropdown' | 'subheading'; + label: string; + badge?: { + value: string; + background: CSSVariable; + color: CSSVariable; + }; + route?: string; + routerLinkActive?: { exact: boolean }; + icon?: Icon; + children?: SidenavLink[]; + // Permission + envName?: string | string[]; + permissionName?: string | string[]; +}; + +export type CreateDropDownLink = Pick & { + queryParams?: Record; +}; + +export interface IConfig { + navigation: SidenavLink[]; + creationNavigation: CreateDropDownLink[]; + toolbarUserDropdown: ToolbarUserMenuItem[]; +} diff --git a/frontend/projects/sdk-ui/src/interfaces/css-variable.enum.ts b/frontend/projects/sdk-ui/src/interfaces/css-variable.enum.ts new file mode 100644 index 0000000..94fac9b --- /dev/null +++ b/frontend/projects/sdk-ui/src/interfaces/css-variable.enum.ts @@ -0,0 +1,537 @@ +/** + * Regex to convert from :root {} to enum + * Replace: + * --(.*): (.*); + * With: + * '$1' = '--$1', + */ + +export enum CSSVariable { + // Generic + 'container-width' = '--container-width', + 'padding-page' = '--padding-page', + 'padding' = '--padding', + 'padding-16' = '--padding-16', + 'padding-12' = '--padding-12', + 'padding-8' = '--padding-8', + 'padding-4' = '--padding-4', + + // Typography + 'font' = '--font', + 'font-weight-medium' = '--font-weight-medium', + 'font-caption' = '--font-caption', + 'font-body-1' = '--font-body-1', + 'font-body-2' = '--font-body-2', + 'font-subheading-1' = '--font-subheading-1', + 'font-subheading-2' = '--font-subheading-2', + 'font-headline' = '--font-headline', + 'font-title' = '--font-title', + 'font-display-1' = '--font-display-1', + 'font-display-2' = '--font-display-2', + 'font-display-3' = '--font-display-3', + 'font-display-4' = '--font-display-4', + + // Transitions + 'swift-ease-in-out' = '--swift-ease-in-out', + 'swift-ease-in-out-duration' = '--swift-ease-in-out-duration', + 'swift-ease-in-out-timing-function' = '--swift-ease-in-out-timing-function', + 'swift-ease-out' = '--swift-ease-out', + 'swift-ease-out-duration' = '--swift-ease-out-duration', + 'swift-ease-out-timing-function' = '--swift-ease-out-timing-function', + 'swift-ease-in' = '--swift-ease-in', + 'swift-ease-in-duration' = '--swift-ease-in-duration', + 'swift-ease-in-timing-function' = '--swift-ease-in-timing-function', + 'elevation-transition-duration' = '--elevation-transition-duration', + 'elevation-transition-timing-function' = '--elevation-transition-timing-function', + 'elevation-transition' = '--elevation-transition', + + 'text-color' = '--text-color', + 'text-color-light' = '--text-color-light', + 'text-secondary-color' = '--text-secondary-color', + 'text-secondary-color-light' = '--text-secondary-color-light', + 'text-hint' = '--text-hint', + 'text-hint-light' = '--text-hint-light', + + // Foreground + 'foreground-divider' = '--foreground-divider', + + // Background + 'background-base' = '--background-base', + 'background-card' = '--background-card', + 'background-app-bar' = '--background-app-bar', + 'background-hover' = '--background-hover', + + // Elevation + 'elevation-z0' = '--elevation-z0', + 'elevation-z1' = '--elevation-z1', + 'elevation-z2' = '--elevation-z2', + 'elevation-z3' = '--elevation-z3', + 'elevation-z4' = '--elevation-z4', + 'elevation-z5' = '--elevation-z5', + 'elevation-z6' = '--elevation-z6', + 'elevation-z7' = '--elevation-z7', + 'elevation-z8' = '--elevation-z8', + 'elevation-z9' = '--elevation-z9', + 'elevation-z10' = '--elevation-z10', + 'elevation-z11' = '--elevation-z11', + 'elevation-z12' = '--elevation-z12', + 'elevation-z13' = '--elevation-z13', + 'elevation-z14' = '--elevation-z14', + 'elevation-z15' = '--elevation-z15', + 'elevation-z16' = '--elevation-z16', + 'elevation-z17' = '--elevation-z17', + 'elevation-z18' = '--elevation-z18', + 'elevation-z19' = '--elevation-z19', + 'elevation-z20' = '--elevation-z20', + + // Sidenav + 'sidenav-width' = '--sidenav-width', + 'sidenav-background' = '--sidenav-background', + 'sidenav-color' = '--sidenav-color', + + // Sidenav Item + 'sidenav-item-padding' = '--sidenav-item-padding', + 'sidenav-toolbar-background' = '--sidenav-toolbar-background', + 'sidenav-item-background-active' = '--sidenav-item-background-active', + 'sidenav-item-color' = '--sidenav-item-color', + 'sidenav-item-color-active' = '--sidenav-item-color-active', + 'sidenav-item-icon-color' = '--sidenav-item-icon-color', + 'sidenav-item-icon-color-active' = '--sidenav-item-icon-color-active', + 'sidenav-item-icon-gap' = '--sidenav-item-icon-gap', + 'sidenav-item-icon-size' = '--sidenav-item-icon-size', + 'sidenav-item-dropdown-background' = '--sidenav-item-dropdown-background', + 'sidenav-item-dropdown-background-hover' = '--sidenav-item-dropdown-background-hover', + 'sidenav-item-dropdown-gap' = '--sidenav-item-dropdown-gap', + + // Toolbar + 'toolbar-height' = '--toolbar-height', + 'toolbar-background' = '--toolbar-background', + 'toolbar-color' = '--toolbar-color', + 'toolbar-icon-color' = '--toolbar-icon-color', + + // Secondary Toolbar + 'secondary-toolbar-height' = '--secondary-toolbar-height', + + // Navigation + 'navigation-height' = '--navigation-height', + 'navigation-background' = '--navigation-background', + 'navigation-color' = '--navigation-color', + + // Footer + 'footer-height' = '--footer-height', + 'footer-z-index' = '--footer-z-index', + 'footer-background' = '--footer-background', + 'footer-color' = '--footer-color', + 'footer-elevation' = '--footer-elevation', + + // Page Layouts + 'page-layout-height' = '--page-layout-height', + 'page-layout-toolbar-height' = '--page-layout-toolbar-height', + + // Misc + 'blink-scrollbar-width' = '--blink-scrollbar-width', + 'default-icon-size' = '--default-icon-size', + 'border-radius' = '--border-radius', + + // Colors + 'primary-color-50' = '--primary-color-50', + 'primary-color-100' = '--primary-color-100', + 'primary-color-200' = '--primary-color-200', + 'primary-color-300' = '--primary-color-300', + 'primary-color-400' = '--primary-color-400', + 'primary-color-500' = '--primary-color-500', + 'primary-color-600' = '--primary-color-600', + 'primary-color-700' = '--primary-color-700', + 'primary-color-800' = '--primary-color-800', + 'primary-color-900' = '--primary-color-900', + 'primary-color-A100' = '--primary-color-A100', + 'primary-color-A200' = '--primary-color-A200', + 'primary-color-A400' = '--primary-color-A400', + 'primary-color-A700' = '--primary-color-A700', + 'primary-color-contrast-50' = '--primary-color-contrast-50', + 'primary-color-contrast-100' = '--primary-color-contrast-100', + 'primary-color-contrast-200' = '--primary-color-contrast-200', + 'primary-color-contrast-300' = '--primary-color-contrast-300', + 'primary-color-contrast-400' = '--primary-color-contrast-400', + 'primary-color-contrast-500' = '--primary-color-contrast-500', + 'primary-color-contrast-600' = '--primary-color-contrast-600', + 'primary-color-contrast-700' = '--primary-color-contrast-700', + 'primary-color-contrast-800' = '--primary-color-contrast-800', + 'primary-color-contrast-900' = '--primary-color-contrast-900', + 'primary-color-contrast-A100' = '--primary-color-contrast-A100', + 'primary-color-contrast-A200' = '--primary-color-contrast-A200', + 'primary-color-contrast-A400' = '--primary-color-contrast-A400', + 'primary-color-contrast-A700' = '--primary-color-contrast-A700', + + // Primary + 'color-primary-50' = '--color-primary-50', + 'color-primary-100' = '--color-primary-100', + 'color-primary-200' = '--color-primary-200', + 'color-primary-300' = '--color-primary-300', + 'color-primary-400' = '--color-primary-400', + 'color-primary-500' = '--color-primary-500', + 'color-primary-600' = '--color-primary-600', + 'color-primary-700' = '--color-primary-700', + 'color-primary-800' = '--color-primary-800', + 'color-primary-900' = '--color-primary-900', + 'color-primary-A100' = '--color-primary-A100', + 'color-primary-A200' = '--color-primary-A200', + 'color-primary-A400' = '--color-primary-A400', + 'color-primary-A700' = '--color-primary-A700', + 'color-primary-contrast-50' = '--color-primary-contrast-50', + 'color-primary-contrast-100' = '--color-primary-contrast-100', + 'color-primary-contrast-200' = '--color-primary-contrast-200', + 'color-primary-contrast-300' = '--color-primary-contrast-300', + 'color-primary-contrast-400' = '--color-primary-contrast-400', + 'color-primary-contrast-500' = '--color-primary-contrast-500', + 'color-primary-contrast-600' = '--color-primary-contrast-600', + 'color-primary-contrast-700' = '--color-primary-contrast-700', + 'color-primary-contrast-800' = '--color-primary-contrast-800', + 'color-primary-contrast-900' = '--color-primary-contrast-900', + 'color-primary-contrast-A100' = '--color-primary-contrast-A100', + 'color-primary-contrast-A200' = '--color-primary-contrast-A200', + 'color-primary-contrast-A400' = '--color-primary-contrast-A400', + 'color-primary-contrast-A700' = '--color-primary-contrast-A700', + + // Red + 'color-red-50' = '--color-red-50', + 'color-red-100' = '--color-red-100', + 'color-red-200' = '--color-red-200', + 'color-red-300' = '--color-red-300', + 'color-red-400' = '--color-red-400', + 'color-red-500' = '--color-red-500', + 'color-red-600' = '--color-red-600', + 'color-red-700' = '--color-red-700', + 'color-red-800' = '--color-red-800', + 'color-red-900' = '--color-red-900', + 'color-red-A100' = '--color-red-A100', + 'color-red-A200' = '--color-red-A200', + 'color-red-A400' = '--color-red-A400', + 'color-red-A700' = '--color-red-A700', + 'color-red-contrast-50' = '--color-red-contrast-50', + 'color-red-contrast-100' = '--color-red-contrast-100', + 'color-red-contrast-200' = '--color-red-contrast-200', + 'color-red-contrast-300' = '--color-red-contrast-300', + 'color-red-contrast-400' = '--color-red-contrast-400', + 'color-red-contrast-500' = '--color-red-contrast-500', + 'color-red-contrast-600' = '--color-red-contrast-600', + 'color-red-contrast-700' = '--color-red-contrast-700', + 'color-red-contrast-800' = '--color-red-contrast-800', + 'color-red-contrast-900' = '--color-red-contrast-900', + 'color-red-contrast-A100' = '--color-red-contrast-A100', + 'color-red-contrast-A200' = '--color-red-contrast-A200', + 'color-red-contrast-A400' = '--color-red-contrast-A400', + 'color-red-contrast-A700' = '--color-red-contrast-A700', + + // Green + 'color-green-50' = '--color-green-50', + 'color-green-100' = '--color-green-100', + 'color-green-200' = '--color-green-200', + 'color-green-300' = '--color-green-300', + 'color-green-400' = '--color-green-400', + 'color-green-500' = '--color-green-500', + 'color-green-600' = '--color-green-600', + 'color-green-700' = '--color-green-700', + 'color-green-800' = '--color-green-800', + 'color-green-900' = '--color-green-900', + 'color-green-A100' = '--color-green-A100', + 'color-green-A200' = '--color-green-A200', + 'color-green-A400' = '--color-green-A400', + 'color-green-A700' = '--color-green-A700', + 'color-green-contrast-50' = '--color-green-contrast-50', + 'color-green-contrast-100' = '--color-green-contrast-100', + 'color-green-contrast-200' = '--color-green-contrast-200', + 'color-green-contrast-300' = '--color-green-contrast-300', + 'color-green-contrast-400' = '--color-green-contrast-400', + 'color-green-contrast-500' = '--color-green-contrast-500', + 'color-green-contrast-600' = '--color-green-contrast-600', + 'color-green-contrast-700' = '--color-green-contrast-700', + 'color-green-contrast-800' = '--color-green-contrast-800', + 'color-green-contrast-900' = '--color-green-contrast-900', + 'color-green-contrast-A100' = '--color-green-contrast-A100', + 'color-green-contrast-A200' = '--color-green-contrast-A200', + 'color-green-contrast-A400' = '--color-green-contrast-A400', + 'color-green-contrast-A700' = '--color-green-contrast-A700', + + // Amber + 'color-amber-50' = '--color-amber-50', + 'color-amber-100' = '--color-amber-100', + 'color-amber-200' = '--color-amber-200', + 'color-amber-300' = '--color-amber-300', + 'color-amber-400' = '--color-amber-400', + 'color-amber-500' = '--color-amber-500', + 'color-amber-600' = '--color-amber-600', + 'color-amber-700' = '--color-amber-700', + 'color-amber-800' = '--color-amber-800', + 'color-amber-900' = '--color-amber-900', + 'color-amber-A100' = '--color-amber-A100', + 'color-amber-A200' = '--color-amber-A200', + 'color-amber-A400' = '--color-amber-A400', + 'color-amber-A700' = '--color-amber-A700', + 'color-amber-contrast-50' = '--color-amber-contrast-50', + 'color-amber-contrast-100' = '--color-amber-contrast-100', + 'color-amber-contrast-200' = '--color-amber-contrast-200', + 'color-amber-contrast-300' = '--color-amber-contrast-300', + 'color-amber-contrast-400' = '--color-amber-contrast-400', + 'color-amber-contrast-500' = '--color-amber-contrast-500', + 'color-amber-contrast-600' = '--color-amber-contrast-600', + 'color-amber-contrast-700' = '--color-amber-contrast-700', + 'color-amber-contrast-800' = '--color-amber-contrast-800', + 'color-amber-contrast-900' = '--color-amber-contrast-900', + 'color-amber-contrast-A100' = '--color-amber-contrast-A100', + 'color-amber-contrast-A200' = '--color-amber-contrast-A200', + 'color-amber-contrast-A400' = '--color-amber-contrast-A400', + 'color-amber-contrast-A700' = '--color-amber-contrast-A700', + + // Orange + 'color-orange-50' = '--color-orange-50', + 'color-orange-100' = '--color-orange-100', + 'color-orange-200' = '--color-orange-200', + 'color-orange-300' = '--color-orange-300', + 'color-orange-400' = '--color-orange-400', + 'color-orange-500' = '--color-orange-500', + 'color-orange-600' = '--color-orange-600', + 'color-orange-700' = '--color-orange-700', + 'color-orange-800' = '--color-orange-800', + 'color-orange-900' = '--color-orange-900', + 'color-orange-A100' = '--color-orange-A100', + 'color-orange-A200' = '--color-orange-A200', + 'color-orange-A400' = '--color-orange-A400', + 'color-orange-A700' = '--color-orange-A700', + 'color-orange-contrast-50' = '--color-orange-contrast-50', + 'color-orange-contrast-100' = '--color-orange-contrast-100', + 'color-orange-contrast-200' = '--color-orange-contrast-200', + 'color-orange-contrast-300' = '--color-orange-contrast-300', + 'color-orange-contrast-400' = '--color-orange-contrast-400', + 'color-orange-contrast-500' = '--color-orange-contrast-500', + 'color-orange-contrast-600' = '--color-orange-contrast-600', + 'color-orange-contrast-700' = '--color-orange-contrast-700', + 'color-orange-contrast-800' = '--color-orange-contrast-800', + 'color-orange-contrast-900' = '--color-orange-contrast-900', + 'color-orange-contrast-A100' = '--color-orange-contrast-A100', + 'color-orange-contrast-A200' = '--color-orange-contrast-A200', + 'color-orange-contrast-A400' = '--color-orange-contrast-A400', + 'color-orange-contrast-A700' = '--color-orange-contrast-A700', + + // Deep Orange + 'color-deep-orange-50' = '--color-deep-orange-50', + 'color-deep-orange-100' = '--color-deep-orange-100', + 'color-deep-orange-200' = '--color-deep-orange-200', + 'color-deep-orange-300' = '--color-deep-orange-300', + 'color-deep-orange-400' = '--color-deep-orange-400', + 'color-deep-orange-500' = '--color-deep-orange-500', + 'color-deep-orange-600' = '--color-deep-orange-600', + 'color-deep-orange-700' = '--color-deep-orange-700', + 'color-deep-orange-800' = '--color-deep-orange-800', + 'color-deep-orange-900' = '--color-deep-orange-900', + 'color-deep-orange-A100' = '--color-deep-orange-A100', + 'color-deep-orange-A200' = '--color-deep-orange-A200', + 'color-deep-orange-A400' = '--color-deep-orange-A400', + 'color-deep-orange-A700' = '--color-deep-orange-A700', + 'color-deep-orange-contrast-50' = '--color-deep-orange-contrast-50', + 'color-deep-orange-contrast-100' = '--color-deep-orange-contrast-100', + 'color-deep-orange-contrast-200' = '--color-deep-orange-contrast-200', + 'color-deep-orange-contrast-300' = '--color-deep-orange-contrast-300', + 'color-deep-orange-contrast-400' = '--color-deep-orange-contrast-400', + 'color-deep-orange-contrast-500' = '--color-deep-orange-contrast-500', + 'color-deep-orange-contrast-600' = '--color-deep-orange-contrast-600', + 'color-deep-orange-contrast-700' = '--color-deep-orange-contrast-700', + 'color-deep-orange-contrast-800' = '--color-deep-orange-contrast-800', + 'color-deep-orange-contrast-900' = '--color-deep-orange-contrast-900', + 'color-deep-orange-contrast-A100' = '--color-deep-orange-contrast-A100', + 'color-deep-orange-contrast-A200' = '--color-deep-orange-contrast-A200', + 'color-deep-orange-contrast-A400' = '--color-deep-orange-contrast-A400', + 'color-deep-orange-contrast-A700' = '--color-deep-orange-contrast-A700', + + 'color-purple-50' = '--color-purple-50', + 'color-purple-100' = '--color-purple-100', + 'color-purple-200' = '--color-purple-200', + 'color-purple-300' = '--color-purple-300', + 'color-purple-400' = '--color-purple-400', + 'color-purple-500' = '--color-purple-500', + 'color-purple-600' = '--color-purple-600', + 'color-purple-700' = '--color-purple-700', + 'color-purple-800' = '--color-purple-800', + 'color-purple-900' = '--color-purple-900', + 'color-purple-A100' = '--color-purple-A100', + 'color-purple-A200' = '--color-purple-A200', + 'color-purple-A400' = '--color-purple-A400', + 'color-purple-A700' = '--color-purple-A700', + 'color-purple-contrast-50' = '--color-purple-contrast-50', + 'color-purple-contrast-100' = '--color-purple-contrast-100', + 'color-purple-contrast-200' = '--color-purple-contrast-200', + 'color-purple-contrast-300' = '--color-purple-contrast-300', + 'color-purple-contrast-400' = '--color-purple-contrast-400', + 'color-purple-contrast-500' = '--color-purple-contrast-500', + 'color-purple-contrast-600' = '--color-purple-contrast-600', + 'color-purple-contrast-700' = '--color-purple-contrast-700', + 'color-purple-contrast-800' = '--color-purple-contrast-800', + 'color-purple-contrast-900' = '--color-purple-contrast-900', + 'color-purple-contrast-A100' = '--color-purple-contrast-A100', + 'color-purple-contrast-A200' = '--color-purple-contrast-A200', + 'color-purple-contrast-A400' = '--color-purple-contrast-A400', + 'color-purple-contrast-A700' = '--color-purple-contrast-A700', + + 'color-deep-purple-50' = '--color-deep-purple-50', + 'color-deep-purple-100' = '--color-deep-purple-100', + 'color-deep-purple-200' = '--color-deep-purple-200', + 'color-deep-purple-300' = '--color-deep-purple-300', + 'color-deep-purple-400' = '--color-deep-purple-400', + 'color-deep-purple-500' = '--color-deep-purple-500', + 'color-deep-purple-600' = '--color-deep-purple-600', + 'color-deep-purple-700' = '--color-deep-purple-700', + 'color-deep-purple-800' = '--color-deep-purple-800', + 'color-deep-purple-900' = '--color-deep-purple-900', + 'color-deep-purple-A100' = '--color-deep-purple-A100', + 'color-deep-purple-A200' = '--color-deep-purple-A200', + 'color-deep-purple-A400' = '--color-deep-purple-A400', + 'color-deep-purple-A700' = '--color-deep-purple-A700', + 'color-deep-purple-contrast-50' = '--color-deep-purple-contrast-50', + 'color-deep-purple-contrast-100' = '--color-deep-purple-contrast-100', + 'color-deep-purple-contrast-200' = '--color-deep-purple-contrast-200', + 'color-deep-purple-contrast-300' = '--color-deep-purple-contrast-300', + 'color-deep-purple-contrast-400' = '--color-deep-purple-contrast-400', + 'color-deep-purple-contrast-500' = '--color-deep-purple-contrast-500', + 'color-deep-purple-contrast-600' = '--color-deep-purple-contrast-600', + 'color-deep-purple-contrast-700' = '--color-deep-purple-contrast-700', + 'color-deep-purple-contrast-800' = '--color-deep-purple-contrast-800', + 'color-deep-purple-contrast-900' = '--color-deep-purple-contrast-900', + 'color-deep-purple-contrast-A100' = '--color-deep-purple-contrast-A100', + 'color-deep-purple-contrast-A200' = '--color-deep-purple-contrast-A200', + 'color-deep-purple-contrast-A400' = '--color-deep-purple-contrast-A400', + 'color-deep-purple-contrast-A700' = '--color-deep-purple-contrast-A700', + + 'color-cyan-50' = '--color-cyan-50', + 'color-cyan-100' = '--color-cyan-100', + 'color-cyan-200' = '--color-cyan-200', + 'color-cyan-300' = '--color-cyan-300', + 'color-cyan-400' = '--color-cyan-400', + 'color-cyan-500' = '--color-cyan-500', + 'color-cyan-600' = '--color-cyan-600', + 'color-cyan-700' = '--color-cyan-700', + 'color-cyan-800' = '--color-cyan-800', + 'color-cyan-900' = '--color-cyan-900', + 'color-cyan-A100' = '--color-cyan-A100', + 'color-cyan-A200' = '--color-cyan-A200', + 'color-cyan-A400' = '--color-cyan-A400', + 'color-cyan-A700' = '--color-cyan-A700', + + 'color-cyan-contrast-50' = '--color-cyan-contrast-50', + 'color-cyan-contrast-100' = '--color-cyan-contrast-100', + 'color-cyan-contrast-200' = '--color-cyan-contrast-200', + 'color-cyan-contrast-300' = '--color-cyan-contrast-300', + 'color-cyan-contrast-400' = '--color-cyan-contrast-400', + 'color-cyan-contrast-500' = '--color-cyan-contrast-500', + 'color-cyan-contrast-600' = '--color-cyan-contrast-600', + 'color-cyan-contrast-700' = '--color-cyan-contrast-700', + 'color-cyan-contrast-800' = '--color-cyan-contrast-800', + 'color-cyan-contrast-900' = '--color-cyan-contrast-900', + 'color-cyan-contrast-A100' = '--color-cyan-contrast-A100', + 'color-cyan-contrast-A200' = '--color-cyan-contrast-A200', + 'color-cyan-contrast-A400' = '--color-cyan-contrast-A400', + 'color-cyan-contrast-A700' = '--color-cyan-contrast-A700', + + 'color-teal-50' = '--color-teal-50', + 'color-teal-100' = '--color-teal-100', + 'color-teal-200' = '--color-teal-200', + 'color-teal-300' = '--color-teal-300', + 'color-teal-400' = '--color-teal-400', + 'color-teal-500' = '--color-teal-500', + 'color-teal-600' = '--color-teal-600', + 'color-teal-700' = '--color-teal-700', + 'color-teal-800' = '--color-teal-800', + 'color-teal-900' = '--color-teal-900', + 'color-teal-A100' = '--color-teal-A100', + 'color-teal-A200' = '--color-teal-A200', + 'color-teal-A400' = '--color-teal-A400', + 'color-teal-A700' = '--color-teal-A700', + 'color-teal-contrast-50' = '--color-teal-contrast-50', + 'color-teal-contrast-100' = '--color-teal-contrast-100', + 'color-teal-contrast-200' = '--color-teal-contrast-200', + 'color-teal-contrast-300' = '--color-teal-contrast-300', + 'color-teal-contrast-400' = '--color-teal-contrast-400', + 'color-teal-contrast-500' = '--color-teal-contrast-500', + 'color-teal-contrast-600' = '--color-teal-contrast-600', + 'color-teal-contrast-700' = '--color-teal-contrast-700', + 'color-teal-contrast-800' = '--color-teal-contrast-800', + 'color-teal-contrast-900' = '--color-teal-contrast-900', + 'color-teal-contrast-A100' = '--color-teal-contrast-A100', + 'color-teal-contrast-A200' = '--color-teal-contrast-A200', + 'color-teal-contrast-A400' = '--color-teal-contrast-A400', + 'color-teal-contrast-A700' = '--color-teal-contrast-A700', + + 'color-gray-50' = '--color-gray-50', + 'color-gray-100' = '--color-gray-100', + 'color-gray-200' = '--color-gray-200', + 'color-gray-300' = '--color-gray-300', + 'color-gray-400' = '--color-gray-400', + 'color-gray-500' = '--color-gray-500', + 'color-gray-600' = '--color-gray-600', + 'color-gray-700' = '--color-gray-700', + 'color-gray-800' = '--color-gray-800', + 'color-gray-900' = '--color-gray-900', + 'color-gray-A100' = '--color-gray-A100', + 'color-gray-A200' = '--color-gray-A200', + 'color-gray-A400' = '--color-gray-A400', + 'color-gray-A700' = '--color-gray-A700', + 'color-gray-contrast-50' = '--color-gray-contrast-50', + 'color-gray-contrast-100' = '--color-gray-contrast-100', + 'color-gray-contrast-200' = '--color-gray-contrast-200', + 'color-gray-contrast-300' = '--color-gray-contrast-300', + 'color-gray-contrast-400' = '--color-gray-contrast-400', + 'color-gray-contrast-500' = '--color-gray-contrast-500', + 'color-gray-contrast-600' = '--color-gray-contrast-600', + 'color-gray-contrast-700' = '--color-gray-contrast-700', + 'color-gray-contrast-800' = '--color-gray-contrast-800', + 'color-gray-contrast-900' = '--color-gray-contrast-900', + 'color-gray-contrast-A100' = '--color-gray-contrast-A100', + 'color-gray-contrast-A200' = '--color-gray-contrast-A200', + 'color-gray-contrast-A400' = '--color-gray-contrast-A400', + 'color-gray-contrast-A700' = '--color-gray-contrast-A700', + + 'color-light-green-50' = '--color-light-green-50', + 'color-light-green-100' = '--color-light-green-100', + 'color-light-green-200' = '--color-light-green-200', + 'color-light-green-300' = '--color-light-green-300', + 'color-light-green-400' = '--color-light-green-400', + 'color-light-green-500' = '--color-light-green-500', + 'color-light-green-600' = '--color-light-green-600', + 'color-light-green-700' = '--color-light-green-700', + 'color-light-green-800' = '--color-light-green-800', + 'color-light-green-900' = '--color-light-green-900', + 'color-light-green-A100' = '--color-light-green-A100', + 'color-light-green-A200' = '--color-light-green-A200', + 'color-light-green-A400' = '--color-light-green-A400', + 'color-light-green-A700' = '--color-light-green-A700', + 'color-light-green-contrast-50' = '--color-light-green-contrast-50', + 'color-light-green-contrast-100' = '--color-light-green-contrast-100', + 'color-light-green-contrast-200' = '--color-light-green-contrast-200', + 'color-light-green-contrast-300' = '--color-light-green-contrast-300', + 'color-light-green-contrast-400' = '--color-light-green-contrast-400', + 'color-light-green-contrast-500' = '--color-light-green-contrast-500', + 'color-light-green-contrast-600' = '--color-light-green-contrast-600', + 'color-light-green-contrast-700' = '--color-light-green-contrast-700', + 'color-light-green-contrast-800' = '--color-light-green-contrast-800', + 'color-light-green-contrast-900' = '--color-light-green-contrast-900', + 'color-light-green-contrast-A100' = '--color-light-green-contrast-A100', + 'color-light-green-contrast-A200' = '--color-light-green-contrast-A200', + 'color-light-green-contrast-A400' = '--color-light-green-contrast-A400', + 'color-light-green-contrast-A700' = '--color-light-green-contrast-A700', + + 'color-cyan' = '--color-cyan', + 'color-deep-orange' = '--color-deep-orange', + 'color-deep-purple' = '--color-deep-purple', + 'color-light-green' = '--color-light-green', + 'color-lime' = '--color-lime', + 'color-orange' = '--color-orange', + 'color-pink' = '--color-pink', + 'color-purple' = '--color-purple', + 'color-red' = '--color-red', + 'color-amber' = '--color-amber', + 'color-light-blue' = '--color-light-blue', + 'color-indigo' = '--color-indigo', + 'color-green' = '--color-green', + 'color-yellow' = '--color-yellow', + 'color-teal' = '--color-teal', + 'color-blue' = '--color-blue' +} diff --git a/frontend/projects/sdk-ui/src/interfaces/index.ts b/frontend/projects/sdk-ui/src/interfaces/index.ts new file mode 100644 index 0000000..95b325a --- /dev/null +++ b/frontend/projects/sdk-ui/src/interfaces/index.ts @@ -0,0 +1,6 @@ +export * from './css-variable.enum'; +export * from './kc-route.interface'; +export * from './navigation-item.interface'; +export * from './table-column.interface'; +export * from './toolbar-menu-item.interface'; +export * from './config.interface'; diff --git a/frontend/projects/sdk-ui/src/interfaces/kc-route.interface.ts b/frontend/projects/sdk-ui/src/interfaces/kc-route.interface.ts new file mode 100644 index 0000000..a02b9d8 --- /dev/null +++ b/frontend/projects/sdk-ui/src/interfaces/kc-route.interface.ts @@ -0,0 +1,16 @@ +import { Route } from '@angular/router'; + +export interface KcRouteData { + scrollDisabled?: boolean; + toolbarShadowEnabled?: boolean; + containerEnabled?: boolean; + + [key: string]: any; +} + +export interface KcRoute extends Route { + data?: KcRouteData; + children?: KcRoute[]; +} + +export type KcRoutes = KcRoute[]; diff --git a/frontend/projects/sdk-ui/src/interfaces/navigation-item.interface.ts b/frontend/projects/sdk-ui/src/interfaces/navigation-item.interface.ts new file mode 100644 index 0000000..642efb3 --- /dev/null +++ b/frontend/projects/sdk-ui/src/interfaces/navigation-item.interface.ts @@ -0,0 +1,40 @@ +import { Icon } from '@visurel/iconify-angular'; +import { CSSVariable } from './css-variable.enum'; + +export type NavigationItem = any | any | any; + +export interface NavigationLink { + type: 'link'; + route: string | any; + fragment?: string; + label: string; + icon?: Icon; + id: string; + isVisible?: boolean; + routerLinkActive?: { exact: boolean }; + badge?: { + value: string; + background: CSSVariable; + color: CSSVariable; + }; +} + +export interface NavigationDropdown { + type: 'dropdown'; + label: string; + icon?: Icon; + id: string; + isVisible?: boolean; + children?: Array; + badge?: { + value: string; + background: CSSVariable; + color: CSSVariable; + }; +} + +export interface NavigationSubheading { + type: 'subheading'; + label: string; + children: Array; +} diff --git a/frontend/projects/sdk-ui/src/interfaces/ng-package.json b/frontend/projects/sdk-ui/src/interfaces/ng-package.json new file mode 100644 index 0000000..1dc0b0b --- /dev/null +++ b/frontend/projects/sdk-ui/src/interfaces/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "index.ts" + } +} diff --git a/frontend/projects/sdk-ui/src/interfaces/table-column.interface.ts b/frontend/projects/sdk-ui/src/interfaces/table-column.interface.ts new file mode 100644 index 0000000..2b9b473 --- /dev/null +++ b/frontend/projects/sdk-ui/src/interfaces/table-column.interface.ts @@ -0,0 +1,7 @@ +export interface TableColumn { + label: string; + property: keyof T | string; + type: 'text' | 'image' | 'badge' | 'progress' | 'checkbox' | 'button'; + visible?: boolean; + cssClasses?: string[]; +} diff --git a/frontend/projects/sdk-ui/src/interfaces/toolbar-menu-item.interface.ts b/frontend/projects/sdk-ui/src/interfaces/toolbar-menu-item.interface.ts new file mode 100644 index 0000000..55868dd --- /dev/null +++ b/frontend/projects/sdk-ui/src/interfaces/toolbar-menu-item.interface.ts @@ -0,0 +1,12 @@ +import { Icon } from '@visurel/iconify-angular'; + +export interface ToolbarUserMenuItem { + id: string; + icon: Icon; + label: string; + description: string; + colorClass: string; + route: string; + envDisables?: string; + permissions?: string; +} diff --git a/frontend/projects/sdk-ui/src/layout/index.ts b/frontend/projects/sdk-ui/src/layout/index.ts new file mode 100644 index 0000000..a7b1d22 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/index.ts @@ -0,0 +1,2 @@ +export * from './layout.component'; +export * from './layout.module'; diff --git a/frontend/projects/sdk-ui/src/layout/layout.component.html b/frontend/projects/sdk-ui/src/layout/layout.component.html new file mode 100644 index 0000000..b237c7a --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/layout.component.html @@ -0,0 +1,35 @@ +
+ + + + + + + + + + +
+ + +
+
+
+
diff --git a/frontend/projects/sdk-ui/src/layout/layout.component.scss b/frontend/projects/sdk-ui/src/layout/layout.component.scss new file mode 100644 index 0000000..9d18e55 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/layout.component.scss @@ -0,0 +1,98 @@ +.page-container { + bottom: 0; + display: flex; + flex-direction: column; + left: 0; + position: absolute; + right: 0; + top: 0; +} + +.sidenav { + background: var(--sidenav-background); + + ::ng-deep .mat-drawer-inner-container { + overflow: hidden; + } +} + +.content { + min-height: calc(100% - var(--toolbar-height) - var(--navigation-height)); + position: relative; + width: 100%; +} + +.has-footer .content { + min-height: calc(100% - var(--toolbar-height) - var(--navigation-height) - var(--footer-height)); +} + +.scroll-disabled { + .content { + height: calc(100% - var(--toolbar-height) - var(--navigation-height)); + min-height: unset; + } + + &.has-fixed-footer .content, + &.has-footer .content { + height: calc(100% - var(--toolbar-height) - var(--navigation-height) - var(--footer-height)); + min-height: unset; + } +} + +.scroll-disabled { + overflow: hidden; + + .content { + overflow: hidden; + } +} + +.is-mobile { + .toolbar { + position: fixed; + width: 100%; + } + + .content { + // background-color: var(--background-card); + margin-top: var(--toolbar-height); + } +} + +.sidenav-container { + background: var(--background-base); + height: 100%; +} + +.sidenav-content { + overflow-y: auto; + overflow-y: overlay; +} + +.toolbar-fixed { + .toolbar { + position: fixed; + width: var(--toolbar-width); + z-index: 50; + } + + .content { + margin-top: calc(var(--toolbar-height) + var(--navigation-height)); + } +} + +.has-fixed-footer { + .footer { + box-shadow: var(--footer-elevation); + position: fixed; + } + + .content { + margin-bottom: var(--footer-height); + min-height: calc(100% - var(--toolbar-height) - var(--navigation-height) - var(--footer-height)); + } + + &.scroll-disabled .content { + height: calc(100% - var(--toolbar-height) - var(--navigation-height) - var(--footer-height)); + } +} diff --git a/frontend/projects/sdk-ui/src/layout/layout.component.spec.ts b/frontend/projects/sdk-ui/src/layout/layout.component.spec.ts new file mode 100644 index 0000000..81cc234 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/layout.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { LayoutComponent } from './layout.component'; + +describe('LayoutAlphaComponent', () => { + let component: LayoutComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [LayoutComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LayoutComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/projects/sdk-ui/src/layout/layout.component.ts b/frontend/projects/sdk-ui/src/layout/layout.component.ts new file mode 100644 index 0000000..7ceefa9 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/layout.component.ts @@ -0,0 +1,209 @@ +import { AfterViewInit, ChangeDetectorRef, Component, Inject, OnDestroy, OnInit, Optional, ViewChild } from '@angular/core'; +import { DOCUMENT } from '@angular/common'; +import { MatSidenav, MatSidenavContainer } from '@angular/material/sidenav'; +import { NavigationEnd, Router, Scroll } from '@angular/router'; +import { filter, map, startWith, take, takeUntil } from 'rxjs/operators'; +import { Subject, combineLatest } from 'rxjs'; +import { MediaObserver } from '@angular/flex-layout'; +import { checkRouterChildsData } from '@sdk-ui/utils'; +import { PermissionService, RequesterService } from '@core-ui/services'; +import { LayoutService, NavigationService } from '@sdk-ui/services'; +import { SidenavLink } from '@sdk-ui/interfaces'; +import { SdkConfigService } from '@sdk-ui/services'; + +const layoutBreakpoint = 'lt-lg'; +const USER_ADMIN_ROLES = ['ADMIN', 'SUPER_ADMIN']; + +@Component({ + selector: 'kc-layout', + templateUrl: './layout.component.html', + styleUrls: ['./layout.component.scss'] +}) +export class LayoutComponent implements OnInit, AfterViewInit, OnDestroy { + private _destroy$ = new Subject(); + sidenavCollapsed$ = this.layoutService.sidenavCollapsed$; + + mobileQuery$ = this.mediaObserver.asObservable().pipe(map(() => this.mediaObserver.isActive(layoutBreakpoint))); + + toolbarShadowEnabled$ = this.router.events.pipe( + filter(event => event instanceof NavigationEnd), + startWith(null), + map(() => checkRouterChildsData(this.router.routerState.root.snapshot, (data: any) => data.toolbarShadowEnabled)) + ); + + scrollDisabled$ = this.router.events.pipe( + filter(event => event instanceof NavigationEnd), + startWith(null), + map(() => checkRouterChildsData(this.router.routerState.root.snapshot, (data: any) => data.scrollDisabled)) + ); + + containerEnabled$ = this.router.events.pipe( + filter(event => event instanceof NavigationEnd), + startWith(null), + map(() => checkRouterChildsData(this.router.routerState.root.snapshot, (data: any) => data.containerEnabled)) + ); + + userPermissions: string[] = []; + + @ViewChild('sidenav', { static: true }) sidenav!: MatSidenav; + @ViewChild(MatSidenavContainer, { static: true }) + sidenavContainer!: MatSidenavContainer; + + constructor( + private cd: ChangeDetectorRef, + private mediaObserver: MediaObserver, + private layoutService: LayoutService, + private requesterService: RequesterService, + private permissionSvc: PermissionService, + private navigationService: NavigationService, + private router: Router, + private sdkConfigService: SdkConfigService, + @Inject(DOCUMENT) private document: Document + ) { + // Check user is authentication + if (this.requesterService.isAuthenticated()) { + const userData = this.requesterService.get(); + if (!USER_ADMIN_ROLES.includes(userData?.userInfo?.user_type)) { + this.permissionSvc.getPermissions().pipe(take(1)).subscribe(); + } + } + + // Note: disabledFeature and sidenavList will keep on closure + const sidenavList = this.sdkConfigService.initializeNavigation; + + // Sidenav Items + combineLatest([ + this.requesterService.userData$.pipe(takeUntil(this._destroy$)), + this.permissionSvc.userPermissions$.pipe(takeUntil(this._destroy$)) + ]) + .pipe(takeUntil(this._destroy$)) + .subscribe(([userData, permissions]) => { + if (userData === null) { + if (this.userPermissions?.length) { + this.userPermissions = []; + } + this.navigationService.loadItems([]); + return; + } + // When user is authenticated + const isAdmin = USER_ADMIN_ROLES.includes(userData?.userInfo?.user_type); + if (isAdmin) { + this.navigationService.loadItems(sidenavList); + } else { + this.userPermissions = permissions; + const newSidenavList = sidenavList.map(item => this._checkSidenavLinkPermission(item)).filter(Boolean); + this.navigationService.loadItems(newSidenavList); + } + }); + } + + ngOnInit() { + this.mediaObserver + .asObservable() + .pipe( + filter(() => this.mediaObserver.isActive(layoutBreakpoint)), + takeUntil(this._destroy$) + ) + .subscribe(() => this.layoutService.expandSidenav()); + + this.layoutService.sidenavOpen$.pipe(takeUntil(this._destroy$)).subscribe(open => (open ? this.sidenav.open() : this.sidenav.close())); + + this.router.events + .pipe( + filter(event => event instanceof NavigationEnd), + filter(() => this.mediaObserver.isActive(layoutBreakpoint)), + takeUntil(this._destroy$) + ) + .subscribe(() => this.sidenav.close()); + } + + ngAfterViewInit(): void { + this.router.events + .pipe( + filter(e => e instanceof Scroll), + takeUntil(this._destroy$) + ) + .subscribe((e: any) => { + if (e.position) { + // backward navigation + this.sidenavContainer.scrollable.scrollTo({ + start: e.position[0], + top: e.position[1] + }); + } else if (e.anchor) { + // anchor navigation + + const scroll = (anchor: HTMLElement) => + this.sidenavContainer.scrollable.scrollTo({ + behavior: 'smooth', + top: anchor.offsetTop, + left: anchor.offsetLeft + }); + + let anchorElem = this.document.getElementById(e.anchor); + + if (anchorElem) { + scroll(anchorElem); + } else { + setTimeout(() => { + anchorElem = this.document.getElementById(e.anchor); + scroll(anchorElem as HTMLElement); + }, 100); + } + } else { + // forward navigation + this.sidenavContainer.scrollable.scrollTo({ + top: 0, + start: 0 + }); + } + }); + } + + ngOnDestroy(): void { + this._destroy$.next(); + this._destroy$.complete(); + } + + /** + * @description SidenavLink filter helper base on environment disables value + * @return { SidenavLink | null } SidenavLink | null + */ + private _sidenavLinkEnvFilter(item: SidenavLink, disabledFeatures: string[]): SidenavLink | null { + if (!item.envName) { + if (item.children?.length) { + const children = item.children.map(child => this._sidenavLinkEnvFilter(child, disabledFeatures)).filter(Boolean); + + if (!children.length) return null; + + item['children'] = children as SidenavLink[]; + } + return item; + } + + if (typeof item.envName === 'string') return !disabledFeatures.includes(item.envName) ? item : null; + return !item.envName.some(env => disabledFeatures.includes(env)) ? item : null; + } + + /** + * @description SidenavLink filter helper base on role base permission + * @return { SidenavLink | null } SidenavLink | null + */ + private _checkSidenavLinkPermission(item: SidenavLink): SidenavLink | null { + // No Permission + if (!item.permissionName) { + if (item.children?.length) { + const children = item.children.map(child => this._checkSidenavLinkPermission(child)).filter(Boolean); + if (!children.length) return null; + item['children'] = children as SidenavLink[]; + } + return item; + } + + if (typeof item.permissionName === 'string') { + if (item.permissionName === 'ROLE_ADMIN') return null; + return this.userPermissions.includes(item.permissionName) ? item : null; + } + return item.permissionName.some((_perm: string) => this.userPermissions.includes(_perm)) ? item : null; + } +} diff --git a/frontend/projects/sdk-ui/src/layout/layout.module.ts b/frontend/projects/sdk-ui/src/layout/layout.module.ts new file mode 100644 index 0000000..1776b42 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/layout.module.ts @@ -0,0 +1,27 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { LayoutComponent } from './layout.component'; +import { RouterModule } from '@angular/router'; +import { MatSidenavModule } from '@angular/material/sidenav'; +import { MatButtonModule } from '@angular/material/button'; +import { MatToolbarModule } from '@angular/material/toolbar'; +import { MatIconModule } from '@angular/material/icon'; +import { SidenavModule } from './sidenav/sidenav.module'; +import { ToolbarModule } from './toolbar/toolbar.module'; +import { ProgressBarModule } from '@sdk-ui/ui'; + +@NgModule({ + declarations: [LayoutComponent], + imports: [ + CommonModule, + RouterModule, + MatSidenavModule, + MatButtonModule, + MatToolbarModule, + MatIconModule, + SidenavModule, + ToolbarModule, + ProgressBarModule + ] +}) +export class LayoutModule {} diff --git a/frontend/projects/sdk-ui/src/layout/navigation-item/navigation-item.component.html b/frontend/projects/sdk-ui/src/layout/navigation-item/navigation-item.component.html new file mode 100644 index 0000000..256c042 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/navigation-item/navigation-item.component.html @@ -0,0 +1,124 @@ +
+ {{ item.label }} + + + + + + + + + + + + {{ child.label }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ + item.label + }} + + + + diff --git a/frontend/projects/sdk-ui/src/layout/navigation-item/navigation-item.component.scss b/frontend/projects/sdk-ui/src/layout/navigation-item/navigation-item.component.scss new file mode 100644 index 0000000..3ad07d9 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/navigation-item/navigation-item.component.scss @@ -0,0 +1,25 @@ +.navigation-item { + @apply rounded cursor-pointer text-sm font-medium px-4 py-2 relative select-none no-underline block; + margin-inline-end: var(--padding-8); + transition: var(--trans-ease-out); +} + +.navigation-color { + color: var(--navigation-color); +} + +.navigation-menu-item { + transition: var(--trans-ease-out); + + &:hover { + color: var(--color-primary-500); + + .mat-icon { + color: var(--color-primary-500); + } + } + + .mat-icon { + transition: var(--trans-ease-out); + } +} diff --git a/frontend/projects/sdk-ui/src/layout/navigation-item/navigation-item.component.spec.ts b/frontend/projects/sdk-ui/src/layout/navigation-item/navigation-item.component.spec.ts new file mode 100644 index 0000000..0f331eb --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/navigation-item/navigation-item.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { NavigationItemComponent } from './navigation-item.component'; + +describe('NavigationItemComponent', () => { + let component: NavigationItemComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [NavigationItemComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(NavigationItemComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/projects/sdk-ui/src/layout/navigation-item/navigation-item.component.ts b/frontend/projects/sdk-ui/src/layout/navigation-item/navigation-item.component.ts new file mode 100644 index 0000000..1e0aacd --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/navigation-item/navigation-item.component.ts @@ -0,0 +1,59 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { filter, map, startWith } from 'rxjs/operators'; +import { NavigationEnd, Router } from '@angular/router'; +import { NavigationService } from '@sdk-ui/services'; +import { NavigationItem, NavigationLink } from '@sdk-ui/interfaces'; +import { trackByRoute } from '@core-ui/utils'; + +@Component({ + selector: 'kc-navigation-item', + templateUrl: './navigation-item.component.html', + styleUrls: ['./navigation-item.component.scss'] +}) +export class NavigationItemComponent implements OnInit { + @Input() item: NavigationItem; + + isActive$ = this.router.events.pipe( + filter(event => event instanceof NavigationEnd), + startWith(false), + map(() => this.hasActiveChilds(this.item)) + ); + + isLink = this.navigationService.isLink; + isDropdown = this.navigationService.isDropdown; + isSubheading = this.navigationService.isSubheading; + trackByRoute = trackByRoute; + + constructor( + private navigationService: NavigationService, + private router: Router + ) {} + + ngOnInit() {} + + hasActiveChilds(parent: NavigationItem): boolean { + if (this.isLink(parent)) { + return this.router.isActive(parent.route as string, false); + } + + if (this.isDropdown(parent) || this.isSubheading(parent)) { + if (!parent?.children?.length) return false; + return parent?.children?.some(child => { + if (this.isDropdown(child)) { + return this.hasActiveChilds(child); + } + if (this.isLink(child) && !this.isFunction(child.route)) { + return this.router.isActive(child.route as string, false); + } + + return false; + }); + } + + return false; + } + + isFunction(prop: NavigationLink['route']) { + return prop instanceof Function; + } +} diff --git a/frontend/projects/sdk-ui/src/layout/navigation-item/navigation-item.module.ts b/frontend/projects/sdk-ui/src/layout/navigation-item/navigation-item.module.ts new file mode 100644 index 0000000..cd1961f --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/navigation-item/navigation-item.module.ts @@ -0,0 +1,15 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { NavigationItemComponent } from './navigation-item.component'; +import { MatMenuModule } from '@angular/material/menu'; +import { IconModule } from '@visurel/iconify-angular'; +import { MatIconModule } from '@angular/material/icon'; +import { RouterModule } from '@angular/router'; +import { MatRippleModule } from '@angular/material/core'; + +@NgModule({ + declarations: [NavigationItemComponent], + imports: [CommonModule, MatMenuModule, IconModule, MatIconModule, RouterModule, MatRippleModule], + exports: [NavigationItemComponent] +}) +export class NavigationItemModule {} diff --git a/frontend/projects/sdk-ui/src/layout/navigation/navigation.component.html b/frontend/projects/sdk-ui/src/layout/navigation/navigation.component.html new file mode 100644 index 0000000..e814ca0 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/navigation/navigation.component.html @@ -0,0 +1,3 @@ + diff --git a/frontend/projects/sdk-ui/src/layout/navigation/navigation.component.scss b/frontend/projects/sdk-ui/src/layout/navigation/navigation.component.scss new file mode 100644 index 0000000..8d9a302 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/navigation/navigation.component.scss @@ -0,0 +1,11 @@ +:host { + background: var(--navigation-background); + display: block; + height: var(--navigation-height); + position: relative; + z-index: 200; +} + +.navigation { + height: var(--navigation-height); +} diff --git a/frontend/projects/sdk-ui/src/layout/navigation/navigation.component.spec.ts b/frontend/projects/sdk-ui/src/layout/navigation/navigation.component.spec.ts new file mode 100644 index 0000000..0c7ef1e --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/navigation/navigation.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { NavigationComponent } from './navigation.component'; + +describe('NavigationComponent', () => { + let component: NavigationComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [NavigationComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(NavigationComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/projects/sdk-ui/src/layout/navigation/navigation.component.ts b/frontend/projects/sdk-ui/src/layout/navigation/navigation.component.ts new file mode 100644 index 0000000..35b4567 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/navigation/navigation.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; +import { NavigationService } from '@sdk-ui/services'; + +@Component({ + selector: 'kc-navigation', + templateUrl: './navigation.component.html', + styleUrls: ['./navigation.component.scss'] +}) +export class NavigationComponent implements OnInit { + items = this.navigationService.items; + + constructor(private navigationService: NavigationService) {} + + ngOnInit() {} +} diff --git a/frontend/projects/sdk-ui/src/layout/navigation/navigation.module.ts b/frontend/projects/sdk-ui/src/layout/navigation/navigation.module.ts new file mode 100644 index 0000000..2423fb6 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/navigation/navigation.module.ts @@ -0,0 +1,28 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { NavigationComponent } from './navigation.component'; +import { FlexLayoutModule } from '@angular/flex-layout'; +import { MatRippleModule } from '@angular/material/core'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatIconModule } from '@angular/material/icon'; +import { IconModule } from '@visurel/iconify-angular'; +import { RouterModule } from '@angular/router'; +import { ContainerModule } from '@sdk-ui/directives'; +import { NavigationItemModule } from '../navigation-item/navigation-item.module'; + +@NgModule({ + declarations: [NavigationComponent], + imports: [ + CommonModule, + FlexLayoutModule, + MatRippleModule, + MatMenuModule, + MatIconModule, + IconModule, + RouterModule, + NavigationItemModule, + ContainerModule + ], + exports: [NavigationComponent] +}) +export class NavigationModule {} diff --git a/frontend/projects/sdk-ui/src/layout/ng-package.json b/frontend/projects/sdk-ui/src/layout/ng-package.json new file mode 100644 index 0000000..1dc0b0b --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "index.ts" + } +} diff --git a/frontend/projects/sdk-ui/src/layout/sidenav-item/sidenav-item.component.html b/frontend/projects/sdk-ui/src/layout/sidenav-item/sidenav-item.component.html new file mode 100644 index 0000000..0d44c57 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/sidenav-item/sidenav-item.component.html @@ -0,0 +1,73 @@ + + + {{ item.label }} + {{ item.badge.value }} + + +
+ + {{ item.label }} + {{ item.badge.value }} +
+ + +
+ + {{ item.label }} + {{ item.badge.value }} + + + + + +
+
+ + + +
+
+ + +
{{ item.label }}
+ +
diff --git a/frontend/projects/sdk-ui/src/layout/sidenav-item/sidenav-item.component.scss b/frontend/projects/sdk-ui/src/layout/sidenav-item/sidenav-item.component.scss new file mode 100644 index 0000000..9cebe8b --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/sidenav-item/sidenav-item.component.scss @@ -0,0 +1,108 @@ +.item { + align-items: center; + box-sizing: border-box; + color: var(--sidenav-item-color); + cursor: pointer; + display: flex; + flex-direction: row; + min-height: 48px; + padding: var(--padding-8) var(--sidenav-item-padding); + position: relative; + text-decoration: none; + transition: var(--trans-ease-out); + user-select: none; + width: 100%; + + &:hover, + &.active { + background: var(--sidenav-item-background-active); + + .item-icon { + color: var(--sidenav-item-color-active); + } + + .item-label { + color: var(--sidenav-item-color-active); + } + + .item-dropdown-icon { + color: var(--sidenav-item-color-active); + } + } + + &.open { + .item-dropdown-icon { + transform: rotate(90deg) !important; + } + } +} + +@for $i from 1 through 6 { + :host(.item-level-#{$i}) .item { + background: var(--sidenav-item-dropdown-background); + padding-inline-start: calc( + var(--sidenav-item-icon-size) + + var(--sidenav-item-icon-gap) + + var(--sidenav-item-padding) + + (var(--sidenav-item-dropdown-gap) * #{$i - 1}) + ); + + &:hover { + background: var(--sidenav-item-dropdown-background-hover); + } + } +} + +.item-icon, +.item-label, +.item-dropdown-icon { + transition: inherit; +} + +.item-icon { + color: var(--text-color); + font-size: var(--sidenav-item-icon-size); + height: var(--sidenav-item-icon-size); + margin-inline-end: var(--sidenav-item-icon-gap); + width: var(--sidenav-item-icon-size); +} + +.item-label { + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.item-badge { + border-radius: 9999px; + font-size: 11px; + line-height: 20px; + margin-inline-start: var(--padding-8); + padding: 0 7px; + text-align: center; +} + +.item-dropdown-icon { + color: var(--sidenav-item-icon-color); + font-size: 18px; + height: 18px; + line-height: 18px; + margin-inline-start: var(--padding-8); + transform: rotate(0deg) !important; + width: 18px; +} + +.item-dropdown { + overflow: hidden; +} + +.subheading { + box-sizing: border-box; + color: var(--sidenav-item-color); + font: var(--font-caption); + margin-top: var(--padding); + padding: var(--padding-12) var(--padding); + text-transform: uppercase; + white-space: nowrap; +} diff --git a/frontend/projects/sdk-ui/src/layout/sidenav-item/sidenav-item.component.spec.ts b/frontend/projects/sdk-ui/src/layout/sidenav-item/sidenav-item.component.spec.ts new file mode 100644 index 0000000..df00e67 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/sidenav-item/sidenav-item.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { SidenavItemComponent } from './sidenav-item.component'; + +describe('SidenavItemComponent', () => { + let component: SidenavItemComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [SidenavItemComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SidenavItemComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/projects/sdk-ui/src/layout/sidenav-item/sidenav-item.component.ts b/frontend/projects/sdk-ui/src/layout/sidenav-item/sidenav-item.component.ts new file mode 100644 index 0000000..b1efb7c --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/sidenav-item/sidenav-item.component.ts @@ -0,0 +1,140 @@ +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + HostBinding, + Input, + OnChanges, + OnDestroy, + OnInit, + SimpleChanges +} from '@angular/core'; +import { NavigationEnd, Router } from '@angular/router'; +import { filter, takeUntil } from 'rxjs/operators'; +import { Subject } from 'rxjs'; + +import { NavigationService } from '@sdk-ui/services'; +import { NavigationDropdown, NavigationItem, NavigationLink } from '@sdk-ui/interfaces'; +import { dropdownAnimation } from '@sdk-ui/animations'; + +@Component({ + selector: 'kc-sidenav-item', + templateUrl: './sidenav-item.component.html', + styleUrls: ['./sidenav-item.component.scss'], + animations: [dropdownAnimation], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class SidenavItemComponent implements OnInit, OnChanges, OnDestroy { + private _destroy$ = new Subject(); + @Input() item: NavigationItem; + @Input() level!: number; + isOpen!: boolean; + isActive!: boolean; + + isLink = this.navigationService.isLink; + isDropdown = this.navigationService.isDropdown; + isSubheading = this.navigationService.isSubheading; + + constructor( + private router: Router, + private cd: ChangeDetectorRef, + private navigationService: NavigationService + ) {} + + @HostBinding('class') + get levelClass() { + return `item-level-${this.level}`; + } + + ngOnInit() { + this.router.events + .pipe( + filter(event => event instanceof NavigationEnd), + filter(() => this.isDropdown(this.item)), + takeUntil(this._destroy$) + ) + .subscribe(() => this.onRouteChange()); + + this.navigationService.openChange$ + .pipe( + filter(() => this.isDropdown(this.item)), + takeUntil(this._destroy$) + ) + .subscribe(item => this.onOpenChange(item as NavigationDropdown)); + } + + ngOnChanges(changes: SimpleChanges): void { + this._destroy$.next(); + this._destroy$.complete(); + // eslint-disable-next-line no-prototype-builtins + if (changes && changes.hasOwnProperty('item') && this.isDropdown(this.item)) { + this.onRouteChange(); + } + } + + toggleOpen() { + this.isOpen = !this.isOpen; + this.navigationService.triggerOpenChange(this.item as NavigationDropdown); + this.cd.markForCheck(); + } + + onOpenChange(item: NavigationDropdown) { + if (this.isChildrenOf(this.item as NavigationDropdown, item)) { + return; + } + + if (this.hasActiveChilds(this.item as NavigationDropdown)) { + return; + } + + if (this.item !== item) { + this.isOpen = false; + this.cd.markForCheck(); + } + } + + onRouteChange() { + if (this.hasActiveChilds(this.item as NavigationDropdown)) { + this.isActive = true; + this.isOpen = true; + this.navigationService.triggerOpenChange(this.item as NavigationDropdown); + this.cd.markForCheck(); + } else { + this.isActive = false; + this.isOpen = false; + this.navigationService.triggerOpenChange(this.item as NavigationDropdown); + this.cd.markForCheck(); + } + } + + isChildrenOf(parent: NavigationDropdown, item: NavigationDropdown): boolean { + if (!parent.children?.length) return false; + + if (parent.children.indexOf(item) !== -1) { + return true; + } + + return parent.children.filter(child => this.isDropdown(child)).some(child => this.isChildrenOf(child as NavigationDropdown, item)); + } + + hasActiveChilds(parent: NavigationDropdown): boolean { + if (!parent.children?.length) return false; + + return parent.children.some(child => { + if (this.isDropdown(child)) { + return this.hasActiveChilds(child); + } + + if (this.isLink(child) && !this.isFunction(child.route)) { + return this.router.isActive(child.route as string, false); + } + return false; + }); + } + + isFunction(prop: NavigationLink['route']) { + return prop instanceof Function; + } + + ngOnDestroy(): void {} +} diff --git a/frontend/projects/sdk-ui/src/layout/sidenav-item/sidenav-item.module.ts b/frontend/projects/sdk-ui/src/layout/sidenav-item/sidenav-item.module.ts new file mode 100644 index 0000000..a9bbfcf --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/sidenav-item/sidenav-item.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SidenavItemComponent } from './sidenav-item.component'; +import { RouterModule } from '@angular/router'; +import { MatIconModule } from '@angular/material/icon'; +import { MatRippleModule } from '@angular/material/core'; +import { IconModule } from '@visurel/iconify-angular'; +import { FlexLayoutModule } from '@angular/flex-layout'; +import { SafeStyleModule } from '@sdk-ui/pipes'; + +@NgModule({ + declarations: [SidenavItemComponent], + imports: [CommonModule, RouterModule, MatIconModule, MatRippleModule, IconModule, FlexLayoutModule, SafeStyleModule], + exports: [SidenavItemComponent] +}) +export class SidenavItemModule {} diff --git a/frontend/projects/sdk-ui/src/layout/sidenav/sidenav.component.html b/frontend/projects/sdk-ui/src/layout/sidenav/sidenav.component.html new file mode 100644 index 0000000..e081f1c --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/sidenav/sidenav.component.html @@ -0,0 +1,60 @@ +
+
+ +

{{ config.name || 'KloverCloud' }}

+ +
+ +
+ +
+ +
+ Powered By: +
+ + KloverCloud +
+
+
diff --git a/frontend/projects/sdk-ui/src/layout/sidenav/sidenav.component.scss b/frontend/projects/sdk-ui/src/layout/sidenav/sidenav.component.scss new file mode 100644 index 0000000..c7b5783 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/sidenav/sidenav.component.scss @@ -0,0 +1,105 @@ +.sidenav { + color: var(--sidenav-color); + height: 100%; + transition: var(--trans-ease-out); + width: var(--sidenav-width); + + &.collapsed { + width: var(--sidenav-collapsed-width); + + &:not(.open) { + .sidenav-toolbar { + .title { + opacity: 0; + padding-inline-start: var(--sidenav-item-padding); + } + } + + ::ng-deep .sidenav-items { + .item-icon { + margin-inline-end: var(--sidenav-item-padding); + } + + .subheading, + .item-badge, + .item-label { + opacity: 0; + } + } + + .power_by { + flex-direction: column; + &_logo { + width: 20px; + + &_text { + display: none; + } + } + + &_content { + flex-direction: column; + } + } + } + + ::ng-deep { + .subheading, + .item-badge, + .item-label { + transition: all 200ms var(--trans-ease-out-timing-function); + } + } + + &.open { + width: var(--sidenav-width); + } + } +} + +.sidenav-toolbar { + align-items: center; + background: var(--sidenav-toolbar-background); + box-sizing: border-box; + display: flex; + flex-direction: row; + height: var(--toolbar-height); + padding: 0 var(--padding); + white-space: nowrap; + width: 100%; + + .title { + transition: + padding var(--trans-ease-out-duration) var(--trans-ease-out-timing-function), + opacity var(--trans-ease-out-duration) var(--trans-ease-out-timing-function); + } +} + +.sidenav-items { + padding-top: var(--padding-16); + padding-bottom: var(--padding-16); + overflow-y: scroll; +} + +.power_by { + font-size: 13px; + padding: 10px 5px; + font-weight: 600; + border-top: 1px solid var(--background-base); + text-align: center; + gap: 0.5rem; + @apply mt-auto flex items-center justify-center; + + &_logo { + margin-right: 0.25rem; + width: 14px; + + &_text { + font-weight: 700; + } + } + + &_content { + @apply flex items-center flex-wrap; + } +} diff --git a/frontend/projects/sdk-ui/src/layout/sidenav/sidenav.component.spec.ts b/frontend/projects/sdk-ui/src/layout/sidenav/sidenav.component.spec.ts new file mode 100644 index 0000000..1b4aa36 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/sidenav/sidenav.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { SidenavComponent } from './sidenav.component'; + +describe('SidenavAlphaComponent', () => { + let component: SidenavComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [SidenavComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SidenavComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/projects/sdk-ui/src/layout/sidenav/sidenav.component.ts b/frontend/projects/sdk-ui/src/layout/sidenav/sidenav.component.ts new file mode 100644 index 0000000..65712cd --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/sidenav/sidenav.component.ts @@ -0,0 +1,52 @@ +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { Observable } from 'rxjs'; +import { takeWhile } from 'rxjs/operators'; +import { trackByRoute } from '@core-ui/utils'; +import { CoreConfigService, ICoreConfig } from '@core-ui/services'; +import { NavigationService, LayoutService } from '@sdk-ui/services'; +import { NavigationItem } from '@sdk-ui/interfaces'; + +@Component({ + selector: 'kc-sidenav', + templateUrl: './sidenav.component.html', + styleUrls: ['./sidenav.component.scss'] +}) +export class SidenavComponent implements OnInit, OnDestroy { + isAlive: boolean = true; + + @Input() collapsed!: boolean; + collapsedOpen$ = this.layoutService.sidenavCollapsedOpen$; + + items$: Observable = this.navigationService.Items$; + trackByRoute = trackByRoute; + + config!: ICoreConfig; + + constructor( + private navigationService: NavigationService, + private layoutService: LayoutService, + private coreConfigService: CoreConfigService + ) {} + + ngOnInit() { + this.coreConfigService.generalInfo$.pipe(takeWhile(() => this.isAlive)).subscribe(config => { + this.config = config as ICoreConfig; + }); + } + + ngOnDestroy(): void { + this.isAlive = false; + } + + onMouseEnter() { + this.layoutService.collapseOpenSidenav(); + } + + onMouseLeave() { + this.layoutService.collapseCloseSidenav(); + } + + toggleCollapse() { + this.collapsed ? this.layoutService.expandSidenav() : this.layoutService.collapseSidenav(); + } +} diff --git a/frontend/projects/sdk-ui/src/layout/sidenav/sidenav.module.ts b/frontend/projects/sdk-ui/src/layout/sidenav/sidenav.module.ts new file mode 100644 index 0000000..d1e025b --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/sidenav/sidenav.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SidenavComponent } from './sidenav.component'; +import { MatToolbarModule } from '@angular/material/toolbar'; +import { FlexLayoutModule } from '@angular/flex-layout'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { IconModule } from '@visurel/iconify-angular'; +import { SidenavItemModule } from '../sidenav-item/sidenav-item.module'; + +@NgModule({ + declarations: [SidenavComponent], + imports: [CommonModule, MatToolbarModule, SidenavItemModule, FlexLayoutModule, MatButtonModule, MatIconModule, IconModule], + exports: [SidenavComponent] +}) +export class SidenavModule {} diff --git a/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user-dropdown/toolbar-user-dropdown.component.html b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user-dropdown/toolbar-user-dropdown.component.html new file mode 100644 index 0000000..4d21e70 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user-dropdown/toolbar-user-dropdown.component.html @@ -0,0 +1,76 @@ + diff --git a/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user-dropdown/toolbar-user-dropdown.component.scss b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user-dropdown/toolbar-user-dropdown.component.scss new file mode 100644 index 0000000..5f564c6 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user-dropdown/toolbar-user-dropdown.component.scss @@ -0,0 +1,131 @@ +.dropdown { + background: var(--background-card); + border-bottom-left-radius: var(--border-radius); + border-bottom-right-radius: var(--border-radius); + box-shadow: var(--elevation-z4); + max-width: 100vw; + overflow: hidden; + width: 350px; +} + +.dropdown-header { + background: var(--color-primary-500); + box-shadow: var(--elevation-z2); + color: var(--color-primary-contrast-500); + padding: var(--padding-16) var(--padding-16) var(--padding-16) var(--padding-12); +} + +.dropdown-heading-icon { + background: rgba(255, 255, 255, 0.2); + border-radius: 999999px; + margin-right: var(--padding-12); + padding: var(--padding-8); + + .mat-icon { + font-size: 32px; + height: 32px; + width: 32px; + } +} + +.dropdown-heading { + font: var(--font-title); + margin-left: 10px; +} + +.dropdown-content { + max-height: 300px; + overflow-x: hidden; + overflow-y: auto; +} + +.dropdown-footer { + background: var(--background-app-bar); + border-top: 1px solid var(--foreground-divider); + padding: var(--padding-8) var(--padding-12); + + a { + width: 100%; + text-align: center; + color: var(--text-color); + } +} + +.dropdown-footer-select { + padding-left: var(--padding-12); + + .mat-icon:not(.dropdown-footer-select-caret) { + margin-right: var(--padding-8); + vertical-align: -7px; + } +} + +.dropdown-footer-select-caret { + color: var(--text-hint); + font-size: 18px; + height: 18px; + vertical-align: -4px; + width: 18px; +} + +.notification { + color: var(--text-color); + padding: var(--padding-16) var(--padding); + position: relative; + text-decoration: none; + transition: var(--trans-ease-out); + user-select: none; + + &:hover { + background: var(--background-hover); + + .notification-label { + color: var(--color-primary-500); + } + } + + &.read { + opacity: 0.5; + } +} + +.notification-icon { + margin-right: var(--padding); +} + +.notification-label { + transition: inherit; +} + +.notification-description { + color: var(--text-secondary); + font: var(--font-caption); +} + +.notification-chevron { + color: var(--text-hint); + font-size: 18px; + height: 18px; + width: 18px; +} + +.notification + .notification { + border-top: 1px solid var(--foreground-divider); +} + +.text-style { + font-size: 14px; +} + +.user-image { + background: rgba(231, 231, 231, 0.082); + border-radius: 99999999px; + height: 36px; + width: 36px; +} + +.user-image { + img { + border-radius: 50%; + } +} diff --git a/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user-dropdown/toolbar-user-dropdown.component.spec.ts b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user-dropdown/toolbar-user-dropdown.component.spec.ts new file mode 100644 index 0000000..8dc1190 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user-dropdown/toolbar-user-dropdown.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { ToolbarUserDropdownComponent } from './toolbar-user-dropdown.component'; + +describe('ToolbarUserDropdownComponent', () => { + let component: ToolbarUserDropdownComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [ToolbarUserDropdownComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ToolbarUserDropdownComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user-dropdown/toolbar-user-dropdown.component.ts b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user-dropdown/toolbar-user-dropdown.component.ts new file mode 100644 index 0000000..c4219fd --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user-dropdown/toolbar-user-dropdown.component.ts @@ -0,0 +1,55 @@ +import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +import { PopoverRef } from '@sdk-ui/ui'; +import { RequesterService, PermissionService } from '@core-ui/services'; +import { ToolbarUserMenuItem } from '@sdk-ui/interfaces'; +import { trackById } from '@core-ui/utils'; +import { SdkConfigService } from '@sdk-ui/services'; + +@Component({ + selector: 'kc-toolbar-user-dropdown', + templateUrl: './toolbar-user-dropdown.component.html', + styleUrls: ['./toolbar-user-dropdown.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ToolbarUserDropdownComponent implements OnInit { + items: ToolbarUserMenuItem[] = []; + + trackById = trackById; + fullName!: string; + userData: any; + + constructor( + private popoverRef: PopoverRef, + private router: Router, + public requester: RequesterService, + private permissionService: PermissionService, + private SdkonfigService: SdkConfigService + ) {} + + ngOnInit() { + this.userData = this.requester.get(); + if (this.userData.userInfo.first_name || this.userData.userInfo.last_name) { + this.fullName = `${this.userData.userInfo.first_name} ${this.userData.userInfo.last_name}`; + } else { + this.fullName = this.userData?.userInfo?.username?.split('@')?.[0]; + } + + this.items = this.SdkonfigService.initializeToolbarUserDropdown.filter(item => { + if (item.permissions === undefined || this.userData?.userInfo?.user_type === 'ADMIN') return true; + return this.permissionService.userPermissionsSnapshot.includes(item.permissions); + }); + } + + close() { + this.popoverRef.close(); + } + + logout() { + this.requester.clear(); + this.router.navigate(['/auth/login']); + this.permissionService.loadUserPermissions([]); + this.popoverRef.close(); + } +} diff --git a/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user.component.html b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user.component.html new file mode 100644 index 0000000..3ba5c19 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user.component.html @@ -0,0 +1,45 @@ +
+ + + + +
+
+ + + + + + + +
+ + profile photo + +
+
diff --git a/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user.component.scss b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user.component.scss new file mode 100644 index 0000000..909ec3b --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user.component.scss @@ -0,0 +1,41 @@ +.user { + border-radius: var(--border-radius); + cursor: pointer; + position: relative; + transition: var(--trans-ease-out); + user-select: none; + + &:hover, + &.active { + background: var(--background-hover); + } +} + +.mat-icon { + color: var(--color-primary-500); +} + +.user-name { + padding-left: 0.75rem; + font: var(--font-body-1); + font-weight: var(--font-weight-medium); + line-height: 1.3; + margin-inline-end: var(--padding-12); +} + +.user-status { + font-size: 11px; + line-height: 1.3; + text-align: end; +} + +.user-image { + background: rgba(231, 231, 231, 0.082); + border-radius: 99999999px; + height: 36px; + width: 36px; +} + +.user-image img { + border-radius: 50%; +} diff --git a/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user.component.spec.ts b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user.component.spec.ts new file mode 100644 index 0000000..da64f7d --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { ToolbarUserComponent } from './toolbar-user.component'; + +describe('ToolbarUserComponent', () => { + let component: ToolbarUserComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [ToolbarUserComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ToolbarUserComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user.component.ts b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user.component.ts new file mode 100644 index 0000000..f158be0 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user.component.ts @@ -0,0 +1,56 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; +import { Observable } from 'rxjs'; +import { ToolbarUserDropdownComponent } from './toolbar-user-dropdown/toolbar-user-dropdown.component'; +import { RequesterService } from '@core-ui/services'; +import { PopoverService } from '@sdk-ui/ui'; + +@Component({ + selector: 'kc-toolbar-user', + templateUrl: './toolbar-user.component.html', + styleUrls: ['./toolbar-user.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ToolbarUserComponent implements OnInit { + dropdownOpen!: boolean; + userData$!: Observable; + + constructor( + private popover: PopoverService, + private cd: ChangeDetectorRef, + private requesterService: RequesterService + ) {} + + ngOnInit() { + this.userData$ = this.requesterService.userData$; + } + + showPopover(originRef: HTMLElement) { + this.dropdownOpen = true; + this.cd.markForCheck(); + + const popoverRef = this.popover.open({ + content: ToolbarUserDropdownComponent, + origin: originRef, + offsetY: 12, + position: [ + { + originX: 'center', + originY: 'top', + overlayX: 'center', + overlayY: 'bottom' + }, + { + originX: 'end', + originY: 'bottom', + overlayX: 'end', + overlayY: 'top' + } + ] + }); + + popoverRef.afterClosed$.subscribe(() => { + this.dropdownOpen = false; + this.cd.markForCheck(); + }); + } +} diff --git a/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user.module.ts b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user.module.ts new file mode 100644 index 0000000..061a250 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user.module.ts @@ -0,0 +1,31 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { RouterModule } from '@angular/router'; +import { MatIconModule } from '@angular/material/icon'; +import { MatRippleModule } from '@angular/material/core'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatButtonModule } from '@angular/material/button'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { FlexLayoutModule } from '@angular/flex-layout'; +import { IconModule } from '@visurel/iconify-angular'; +import { ToolbarUserComponent } from './toolbar-user.component'; +import { ToolbarUserDropdownComponent } from './toolbar-user-dropdown/toolbar-user-dropdown.component'; +import { SafeStyleModule } from '@sdk-ui/pipes'; + +@NgModule({ + declarations: [ToolbarUserComponent, ToolbarUserDropdownComponent], + imports: [ + CommonModule, + FlexLayoutModule, + MatIconModule, + MatRippleModule, + MatMenuModule, + MatButtonModule, + SafeStyleModule, + RouterModule, + MatTooltipModule, + IconModule + ], + exports: [ToolbarUserComponent] +}) +export class ToolbarUserModule {} diff --git a/frontend/projects/sdk-ui/src/layout/toolbar/toolbar.component.html b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar.component.html new file mode 100644 index 0000000..7a625fc --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar.component.html @@ -0,0 +1,83 @@ +
+ + + + + + +

{{ (toolbarData$ | async)?.title }}

+ + + + +
+ +
+ Please use chrome for better experience! + + + + + + + + + + + + + + + + + +
diff --git a/frontend/projects/sdk-ui/src/layout/toolbar/toolbar.component.scss b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar.component.scss new file mode 100644 index 0000000..4c4e4ae --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar.component.scss @@ -0,0 +1,147 @@ +:host { + background: var(--toolbar-background); + box-sizing: border-box; + color: var(--text-color); + display: block; + white-space: nowrap; + width: 100%; +} + +.options { + display: flex; + justify-content: space-between; + + .search { + vertical-align: middle; + } +} + +.toolbar { + height: var(--toolbar-height); + + &__btn { + @apply ml-2; + } +} + +._user__btn { + @apply ml-4; + + position: relative; +} + +.mat-icon { + color: var(--toolbar-icon-color); +} + +a { + color: var(--toolbar-color); + text-decoration: none; +} + +.title { + font-size: 20px; + font-weight: 500; + letter-spacing: 0.3px; +} + +.search { + background: var(--background); + border-radius: 100px; + padding: 10px 20px; + margin: 0 30px; + display: flex; + justify-content: space-around; + align-items: center; + margin-right: 30px; + + i { + color: var(--grey); + margin-right: 8px; + } + + input { + &:focus { + outline: none; + } + + min-width: 200px; + } +} + +.create-btn { + padding: 0 24px 0 18px; + background: var(--color-primary); + color: #ffffff; + box-shadow: 0px 4px 10px rgba(65, 100, 169, 0.24); + border-radius: 50px; +} + +.browser-detection { + position: absolute !important; + top: 10px; + left: 35%; + border: 0.5px solid #b1122a; + border-left: 5px solid #b1122a; + border-radius: 5px; + padding: 10px; + background: #80132b; + /* Old browsers */ + background: -moz-linear-gradient(-45deg, #80132b 0%, #0d152f 100%); + /* FF3.6-15 */ + background: -webkit-linear-gradient(-45deg, #80132b 0%, #0d152f 100%); + /* Chrome10-25,Safari5.1-6 */ + background: linear-gradient(135deg, #80132b 0%, #0d152f 100%); + /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */ + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80132b', endColorstr='#0d152f', GradientType=1); + /* IE6-9 fallback on horizontal gradient */ + opacity: 0.7; + color: white; + + .close-notification { + mat-icon { + color: white; + font-size: 18px; + } + } +} + +@screen sm { + .toolbar { + &__btn { + @apply ml-4; + } + } + + ._user__btn { + &::before { + content: ''; + } + + @apply pl-2; + } +} + +@screen md { + .toolbar { + &__btn { + @apply ml-6; + } + } + + ._user__btn { + @apply ml-4 pl-4; + } +} + +@screen lg { + .toolbar { + &__btn { + @apply ml-8; + } + } + + ._user__btn { + @apply pl-8 ml-8; + } +} diff --git a/frontend/projects/sdk-ui/src/layout/toolbar/toolbar.component.spec.ts b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar.component.spec.ts new file mode 100644 index 0000000..f11ed6c --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { ToolbarComponent } from './toolbar.component'; + +describe('ToolbarAlphaComponent', () => { + let component: ToolbarComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [ToolbarComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ToolbarComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/projects/sdk-ui/src/layout/toolbar/toolbar.component.ts b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar.component.ts new file mode 100644 index 0000000..de815b4 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar.component.ts @@ -0,0 +1,50 @@ +import { Component, HostBinding, Inject, Input, OnInit } from '@angular/core'; +import { Platform } from '@angular/cdk/platform'; +import { Observable } from 'rxjs'; +import { stagger80ms, fadeInUp400ms, scaleIn400ms, fadeInRight400ms } from '@sdk-ui/animations'; +import { CoreConfigService } from '@core-ui/services'; +import { LayoutService, ToolbarService } from '@sdk-ui/services'; + +@Component({ + selector: 'kc-toolbar', + templateUrl: './toolbar.component.html', + styleUrls: ['./toolbar.component.scss'], + animations: [stagger80ms, fadeInUp400ms, scaleIn400ms, fadeInRight400ms] +}) +export class ToolbarComponent implements OnInit { + @Input() mobileQuery!: boolean; + + @Input() + @HostBinding('class.shadow-b') + hasShadow!: boolean; + + isChrome!: boolean; + + coreConfig$ = this.coreConfigService.generalInfo$; + toolbarData$: Observable = this.toolbarService.currentData; + + constructor( + private layoutService: LayoutService, + private toolbarService: ToolbarService, + private coreConfigService: CoreConfigService, + private platform: Platform + ) {} + + ngOnInit() { + this.isChrome = this.platform.BLINK; + setTimeout(() => { + this.closeWarning(); + }, 7000); + } + + openQuickpanel() { + this.layoutService.openQuickpanel(); + } + + openSidenav() { + this.layoutService.openSidenav(); + } + closeWarning() { + this.isChrome = true; + } +} diff --git a/frontend/projects/sdk-ui/src/layout/toolbar/toolbar.module.ts b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar.module.ts new file mode 100644 index 0000000..266ff95 --- /dev/null +++ b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar.module.ts @@ -0,0 +1,41 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { RouterModule } from '@angular/router'; +import { MatRippleModule } from '@angular/material/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatInputModule } from '@angular/material/input'; +import { MatDialogModule } from '@angular/material/dialog'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { FlexLayoutModule } from '@angular/flex-layout'; +import { IconModule } from '@visurel/iconify-angular'; + +import { ContainerModule } from '@sdk-ui/directives'; +import { ToolbarComponent } from './toolbar.component'; +import { ToolbarUserModule } from './toolbar-user/toolbar-user.module'; +import { NavigationModule } from '../navigation/navigation.module'; +import { NavigationItemModule } from '../navigation-item/navigation-item.module'; + +@NgModule({ + declarations: [ToolbarComponent], + imports: [ + CommonModule, + FlexLayoutModule, + MatButtonModule, + MatIconModule, + MatMenuModule, + MatInputModule, + MatRippleModule, + ToolbarUserModule, + IconModule, + NavigationModule, + RouterModule, + NavigationItemModule, + ContainerModule, + MatDialogModule, + MatTooltipModule + ], + exports: [ToolbarComponent] +}) +export class ToolbarModule {} diff --git a/frontend/projects/sdk-ui/src/pipes/index.ts b/frontend/projects/sdk-ui/src/pipes/index.ts new file mode 100644 index 0000000..c4d0f33 --- /dev/null +++ b/frontend/projects/sdk-ui/src/pipes/index.ts @@ -0,0 +1,5 @@ +export * from './safe-html/safe-html.pipe'; +export * from './safe-html/safe-html.module'; + +export * from './safe-style/safe-style.pipe'; +export * from './safe-style/safe-style.module'; diff --git a/frontend/projects/sdk-ui/src/pipes/ng-package.json b/frontend/projects/sdk-ui/src/pipes/ng-package.json new file mode 100644 index 0000000..1dc0b0b --- /dev/null +++ b/frontend/projects/sdk-ui/src/pipes/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "index.ts" + } +} diff --git a/frontend/projects/sdk-ui/src/pipes/safe-html/safe-html.module.ts b/frontend/projects/sdk-ui/src/pipes/safe-html/safe-html.module.ts new file mode 100644 index 0000000..d2ea268 --- /dev/null +++ b/frontend/projects/sdk-ui/src/pipes/safe-html/safe-html.module.ts @@ -0,0 +1,10 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SafeHtmlPipe } from './safe-html.pipe'; + +@NgModule({ + declarations: [SafeHtmlPipe], + imports: [CommonModule], + exports: [SafeHtmlPipe] +}) +export class SafeHtmlModule {} diff --git a/frontend/projects/sdk-ui/src/pipes/safe-html/safe-html.pipe.ts b/frontend/projects/sdk-ui/src/pipes/safe-html/safe-html.pipe.ts new file mode 100644 index 0000000..975db1d --- /dev/null +++ b/frontend/projects/sdk-ui/src/pipes/safe-html/safe-html.pipe.ts @@ -0,0 +1,13 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { DomSanitizer } from '@angular/platform-browser'; + +@Pipe({ + name: 'safeHtml' +}) +export class SafeHtmlPipe implements PipeTransform { + constructor(private sanitized: DomSanitizer) {} + + transform(value: any) { + return this.sanitized.bypassSecurityTrustHtml(value); + } +} diff --git a/frontend/projects/sdk-ui/src/pipes/safe-style/safe-style.module.ts b/frontend/projects/sdk-ui/src/pipes/safe-style/safe-style.module.ts new file mode 100644 index 0000000..6a66fcf --- /dev/null +++ b/frontend/projects/sdk-ui/src/pipes/safe-style/safe-style.module.ts @@ -0,0 +1,10 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SafeStylePipe } from './safe-style.pipe'; + +@NgModule({ + declarations: [SafeStylePipe], + imports: [CommonModule], + exports: [SafeStylePipe] +}) +export class SafeStyleModule {} diff --git a/frontend/projects/sdk-ui/src/pipes/safe-style/safe-style.pipe.spec.ts b/frontend/projects/sdk-ui/src/pipes/safe-style/safe-style.pipe.spec.ts new file mode 100644 index 0000000..0304bba --- /dev/null +++ b/frontend/projects/sdk-ui/src/pipes/safe-style/safe-style.pipe.spec.ts @@ -0,0 +1,8 @@ +import { SafeStylePipe } from './safe-style.pipe'; + +describe('SafeStylePipe', () => { + it('create an instance', () => { + const pipe = new SafeStylePipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/frontend/projects/sdk-ui/src/pipes/safe-style/safe-style.pipe.ts b/frontend/projects/sdk-ui/src/pipes/safe-style/safe-style.pipe.ts new file mode 100644 index 0000000..fea9eda --- /dev/null +++ b/frontend/projects/sdk-ui/src/pipes/safe-style/safe-style.pipe.ts @@ -0,0 +1,13 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { DomSanitizer } from '@angular/platform-browser'; + +@Pipe({ + name: 'safeStyle' +}) +export class SafeStylePipe implements PipeTransform { + constructor(private sanitizer: DomSanitizer) {} + + transform(value: any, ...args: any[]): any { + return this.sanitizer.bypassSecurityTrustStyle(value); + } +} diff --git a/frontend/projects/sdk-ui/src/sdk-ui.module.ts b/frontend/projects/sdk-ui/src/sdk-ui.module.ts new file mode 100644 index 0000000..b598b7c --- /dev/null +++ b/frontend/projects/sdk-ui/src/sdk-ui.module.ts @@ -0,0 +1,35 @@ +import { ModuleWithProviders, NgModule } from '@angular/core'; +import { MAT_FORM_FIELD_DEFAULT_OPTIONS, MatFormFieldDefaultOptions } from '@angular/material/form-field'; +import { MatSnackBarModule } from '@angular/material/snack-bar'; +import { CreateDropDownLink, SidenavLink, ToolbarUserMenuItem } from '@sdk-ui/interfaces'; +import { LayoutModule } from '@sdk-ui/layout'; +import { SdkConfigService } from '@sdk-ui/services'; + +@NgModule({ + imports: [LayoutModule, MatSnackBarModule], + providers: [ + { + provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, + useValue: { + appearance: 'fill' + } as MatFormFieldDefaultOptions + } + ] +}) +export class SdkModule { + static appConfig(options: { + navigation: SidenavLink[]; + creationNavigation: CreateDropDownLink[]; + toolbarUserDropdown: ToolbarUserMenuItem[]; + }): ModuleWithProviders { + SdkConfigService.injectConfig({ + navigation: options.navigation, + creationNavigation: options.creationNavigation, + toolbarUserDropdown: options.toolbarUserDropdown + }); + return { + ngModule: SdkModule, + providers: [] + }; + } +} diff --git a/frontend/projects/sdk-ui/src/services/config.service.ts b/frontend/projects/sdk-ui/src/services/config.service.ts new file mode 100644 index 0000000..1330910 --- /dev/null +++ b/frontend/projects/sdk-ui/src/services/config.service.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@angular/core'; +import { IConfig } from '@sdk-ui/interfaces'; + +let _config = { + navigation: [], + creationNavigation: [], + toolbarUserDropdown: [] +} as IConfig; + +@Injectable({ + providedIn: 'root' +}) +export class SdkConfigService { + get initializeNavigation() { + return _config.navigation; + } + + get initializeCreationNavigation() { + return _config.creationNavigation; + } + + get initializeToolbarUserDropdown() { + return _config.toolbarUserDropdown; + } + + static injectConfig(__config: IConfig) { + _config = __config; + } + + static injectConfigValue(key: keyof IConfig, value: any) { + _config[key] = value; + } +} diff --git a/frontend/projects/sdk-ui/src/services/index.ts b/frontend/projects/sdk-ui/src/services/index.ts new file mode 100644 index 0000000..7e1a213 --- /dev/null +++ b/frontend/projects/sdk-ui/src/services/index.ts @@ -0,0 +1 @@ +export * from './public-api'; diff --git a/frontend/projects/sdk-ui/src/services/layout.service.spec.ts b/frontend/projects/sdk-ui/src/services/layout.service.spec.ts new file mode 100644 index 0000000..6494bc9 --- /dev/null +++ b/frontend/projects/sdk-ui/src/services/layout.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { LayoutService } from './layout.service'; + +describe('LayoutService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: LayoutService = TestBed.get(LayoutService); + expect(service).toBeTruthy(); + }); +}); diff --git a/frontend/projects/sdk-ui/src/services/layout.service.ts b/frontend/projects/sdk-ui/src/services/layout.service.ts new file mode 100644 index 0000000..b97b958 --- /dev/null +++ b/frontend/projects/sdk-ui/src/services/layout.service.ts @@ -0,0 +1,101 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject } from 'rxjs'; +import { Router } from '@angular/router'; + +@Injectable({ + providedIn: 'root' +}) +export class LayoutService { + private _quickpanelOpenSubject = new BehaviorSubject(false); + quickpanelOpen$ = this._quickpanelOpenSubject.asObservable(); + + private _sidenavOpenSubject = new BehaviorSubject(false); + sidenavOpen$ = this._sidenavOpenSubject.asObservable(); + + private _sidenavCollapsedSubject = new BehaviorSubject(false); + sidenavCollapsed$ = this._sidenavCollapsedSubject.asObservable(); + + private _sidenavCollapsedOpenSubject = new BehaviorSubject(false); + sidenavCollapsedOpen$ = this._sidenavCollapsedOpenSubject.asObservable(); + + private _configpanelOpenSubject = new BehaviorSubject(false); + configpanelOpen$ = this._configpanelOpenSubject.asObservable(); + + private sideNavExpanded!: boolean; + + constructor(private router: Router) {} + + openQuickpanel() { + this._quickpanelOpenSubject.next(true); + } + + closeQuickpanel() { + this._quickpanelOpenSubject.next(false); + } + + openSidenav() { + this._sidenavOpenSubject.next(true); + } + + closeSidenav() { + this._sidenavOpenSubject.next(false); + } + + collapseSidenav() { + this.sideNavExpanded = false; + this._sidenavCollapsedSubject.next(true); + } + + expandSidenav() { + this.sideNavExpanded = true; + this._sidenavCollapsedSubject.next(false); + } + + collapseOpenSidenav() { + this._sidenavCollapsedOpenSubject.next(true); + } + + collapseCloseSidenav() { + this._sidenavCollapsedOpenSubject.next(false); + } + + openConfigpanel() { + this._configpanelOpenSubject.next(true); + } + + closeConfigpanel() { + this._configpanelOpenSubject.next(false); + } + + isSideNavExpanded() { + return this.sideNavExpanded; + } + + enableRTL() { + this.router + .navigate([], { + queryParams: { + rtl: 'true' + } + }) + .then(() => { + if (window) { + window.location.reload(); + } + }); + } + + disableRTL() { + this.router + .navigate([], { + queryParams: { + rtl: 'false' + } + }) + .then(() => { + if (window) { + window.location.reload(); + } + }); + } +} diff --git a/frontend/projects/sdk-ui/src/services/navigation.service.spec.ts b/frontend/projects/sdk-ui/src/services/navigation.service.spec.ts new file mode 100644 index 0000000..037de59 --- /dev/null +++ b/frontend/projects/sdk-ui/src/services/navigation.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { NavigationService } from './navigation.service'; + +describe('NavigationService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: NavigationService = TestBed.get(NavigationService); + expect(service).toBeTruthy(); + }); +}); diff --git a/frontend/projects/sdk-ui/src/services/navigation.service.ts b/frontend/projects/sdk-ui/src/services/navigation.service.ts new file mode 100644 index 0000000..1136449 --- /dev/null +++ b/frontend/projects/sdk-ui/src/services/navigation.service.ts @@ -0,0 +1,40 @@ +import { Injectable } from '@angular/core'; +import { NavigationDropdown, NavigationItem, NavigationLink, NavigationSubheading } from '@sdk-ui/interfaces'; +import { BehaviorSubject, Observable, Subject } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class NavigationService { + private navigationItems = new BehaviorSubject([]); + Items$: Observable = this.navigationItems.asObservable(); + + private _openChangeSubject = new Subject(); + openChange$ = this._openChangeSubject.asObservable(); + + loadItems(items: NavigationItem[]): void { + this.navigationItems.next(items); + } + + get items(): NavigationItem[] { + return this.navigationItems.value; + } + + // Child + + triggerOpenChange(item: NavigationDropdown) { + this._openChangeSubject.next(item); + } + + isLink(item: NavigationItem): item is NavigationLink { + return item.type === 'link'; + } + + isDropdown(item: NavigationItem): item is NavigationDropdown { + return item.type === 'dropdown'; + } + + isSubheading(item: NavigationItem): item is NavigationSubheading { + return item.type === 'subheading'; + } +} diff --git a/frontend/projects/sdk-ui/src/services/ng-package.json b/frontend/projects/sdk-ui/src/services/ng-package.json new file mode 100644 index 0000000..1dc0b0b --- /dev/null +++ b/frontend/projects/sdk-ui/src/services/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "index.ts" + } +} diff --git a/frontend/projects/sdk-ui/src/services/public-api.ts b/frontend/projects/sdk-ui/src/services/public-api.ts new file mode 100644 index 0000000..6f2a3f3 --- /dev/null +++ b/frontend/projects/sdk-ui/src/services/public-api.ts @@ -0,0 +1,8 @@ +export { SdkConfigService } from './config.service'; +export * from './layout.service'; +export * from './navigation.service'; +// Styles +export * from './splash-screen.service'; +export * from './style.service'; +// Toolbar Service +export * from './toolbar.service'; diff --git a/frontend/projects/sdk-ui/src/services/splash-screen.service.spec.ts b/frontend/projects/sdk-ui/src/services/splash-screen.service.spec.ts new file mode 100644 index 0000000..8cc3b83 --- /dev/null +++ b/frontend/projects/sdk-ui/src/services/splash-screen.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { SplashScreenService } from './splash-screen.service'; + +describe('SplashScreenService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: SplashScreenService = TestBed.get(SplashScreenService); + expect(service).toBeTruthy(); + }); +}); diff --git a/frontend/projects/sdk-ui/src/services/splash-screen.service.ts b/frontend/projects/sdk-ui/src/services/splash-screen.service.ts new file mode 100644 index 0000000..c86a853 --- /dev/null +++ b/frontend/projects/sdk-ui/src/services/splash-screen.service.ts @@ -0,0 +1,36 @@ +import { Inject, Injectable } from '@angular/core'; +import { DOCUMENT } from '@angular/common'; +import { animate, AnimationBuilder, style } from '@angular/animations'; + +@Injectable({ + providedIn: 'root' +}) +export class SplashScreenService { + splashScreenElem!: HTMLElement | null; + + constructor( + @Inject(DOCUMENT) private document: Document, + private animationBuilder: AnimationBuilder + ) { + this.splashScreenElem = this.document.body.querySelector('#kc-splash-screen'); + } + + hide() { + const player = this.animationBuilder + .build([ + style({ + opacity: 1 + }), + animate( + '400ms cubic-bezier(0.25, 0.8, 0.25, 1)', + style({ + opacity: 0 + }) + ) + ]) + .create(this.splashScreenElem); + + player.onDone(() => this.splashScreenElem?.remove()); + player.play(); + } +} diff --git a/frontend/projects/sdk-ui/src/services/style.service.ts b/frontend/projects/sdk-ui/src/services/style.service.ts new file mode 100644 index 0000000..f5a65fa --- /dev/null +++ b/frontend/projects/sdk-ui/src/services/style.service.ts @@ -0,0 +1,61 @@ +import { Inject, Injectable, OnDestroy } from '@angular/core'; +import { DOCUMENT } from '@angular/common'; +import { BehaviorSubject, Subject } from 'rxjs'; +import { filter, takeUntil } from 'rxjs/operators'; + +export enum Style { + light = 'kc-style-light', + dark = 'kc-style-dark', + lightPink = 'kc-style-pink', + default = dark +} + +@Injectable({ + providedIn: 'root' +}) +export class StyleService implements OnDestroy { + private _destroy$ = new Subject(); + + currentStyle = Style.default; + + private _styleSubject = new BehaviorSubject + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/automatic_database.svg b/frontend/src/assets/img/automatic_database.svg new file mode 100644 index 0000000..de8e75c --- /dev/null +++ b/frontend/src/assets/img/automatic_database.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/bin.svg b/frontend/src/assets/img/bin.svg new file mode 100644 index 0000000..1fa4a21 --- /dev/null +++ b/frontend/src/assets/img/bin.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/img/bitnami/cassandra.svg b/frontend/src/assets/img/bitnami/cassandra.svg new file mode 100644 index 0000000..e5ab67d --- /dev/null +++ b/frontend/src/assets/img/bitnami/cassandra.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/bitnami/grafana.svg b/frontend/src/assets/img/bitnami/grafana.svg new file mode 100644 index 0000000..c6ccf92 --- /dev/null +++ b/frontend/src/assets/img/bitnami/grafana.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/img/bitnami/kafka.svg b/frontend/src/assets/img/bitnami/kafka.svg new file mode 100644 index 0000000..522f1a6 --- /dev/null +++ b/frontend/src/assets/img/bitnami/kafka.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/img/bitnami/mongodb.svg b/frontend/src/assets/img/bitnami/mongodb.svg new file mode 100644 index 0000000..80d3a99 --- /dev/null +++ b/frontend/src/assets/img/bitnami/mongodb.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/bitnami/mysql.svg b/frontend/src/assets/img/bitnami/mysql.svg new file mode 100644 index 0000000..b27d6ce --- /dev/null +++ b/frontend/src/assets/img/bitnami/mysql.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/img/bitnami/postgresql.svg b/frontend/src/assets/img/bitnami/postgresql.svg new file mode 100644 index 0000000..145ff17 --- /dev/null +++ b/frontend/src/assets/img/bitnami/postgresql.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/img/bitnami/rabbitmq.svg b/frontend/src/assets/img/bitnami/rabbitmq.svg new file mode 100644 index 0000000..a2fcca3 --- /dev/null +++ b/frontend/src/assets/img/bitnami/rabbitmq.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/img/bitnami/redis.svg b/frontend/src/assets/img/bitnami/redis.svg new file mode 100644 index 0000000..734ddbe --- /dev/null +++ b/frontend/src/assets/img/bitnami/redis.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/bitnami/wordpress.svg b/frontend/src/assets/img/bitnami/wordpress.svg new file mode 100644 index 0000000..280a7d0 --- /dev/null +++ b/frontend/src/assets/img/bitnami/wordpress.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/img/bucket-icon.svg b/frontend/src/assets/img/bucket-icon.svg new file mode 100644 index 0000000..bd140d4 --- /dev/null +++ b/frontend/src/assets/img/bucket-icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/img/bucket.svg b/frontend/src/assets/img/bucket.svg new file mode 100644 index 0000000..21d5253 --- /dev/null +++ b/frontend/src/assets/img/bucket.svg @@ -0,0 +1,2 @@ + + diff --git a/frontend/src/assets/img/cache.svg b/frontend/src/assets/img/cache.svg new file mode 100644 index 0000000..c1d6a29 --- /dev/null +++ b/frontend/src/assets/img/cache.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/img/cassandra-custom.svg b/frontend/src/assets/img/cassandra-custom.svg new file mode 100644 index 0000000..6d8f743 --- /dev/null +++ b/frontend/src/assets/img/cassandra-custom.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/img/checked-2.svg b/frontend/src/assets/img/checked-2.svg new file mode 100644 index 0000000..38ec0bc --- /dev/null +++ b/frontend/src/assets/img/checked-2.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/checked.svg b/frontend/src/assets/img/checked.svg new file mode 100644 index 0000000..7454991 --- /dev/null +++ b/frontend/src/assets/img/checked.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/cloud-network.svg b/frontend/src/assets/img/cloud-network.svg new file mode 100644 index 0000000..278cb72 --- /dev/null +++ b/frontend/src/assets/img/cloud-network.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/company-custom.svg b/frontend/src/assets/img/company-custom.svg new file mode 100644 index 0000000..4938456 --- /dev/null +++ b/frontend/src/assets/img/company-custom.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/cpu-custom.svg b/frontend/src/assets/img/cpu-custom.svg new file mode 100644 index 0000000..2f91391 --- /dev/null +++ b/frontend/src/assets/img/cpu-custom.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/img/cpu-twotone.svg b/frontend/src/assets/img/cpu-twotone.svg new file mode 100644 index 0000000..a50cfca --- /dev/null +++ b/frontend/src/assets/img/cpu-twotone.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/img/cpu.svg b/frontend/src/assets/img/cpu.svg new file mode 100644 index 0000000..7dafc0d --- /dev/null +++ b/frontend/src/assets/img/cpu.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/credit.svg b/frontend/src/assets/img/credit.svg new file mode 100644 index 0000000..4491531 --- /dev/null +++ b/frontend/src/assets/img/credit.svg @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/current_alloc.svg b/frontend/src/assets/img/current_alloc.svg new file mode 100644 index 0000000..87692b2 --- /dev/null +++ b/frontend/src/assets/img/current_alloc.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/img/data-storage-custom.svg b/frontend/src/assets/img/data-storage-custom.svg new file mode 100644 index 0000000..c06dc21 --- /dev/null +++ b/frontend/src/assets/img/data-storage-custom.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/data-storage.svg b/frontend/src/assets/img/data-storage.svg new file mode 100644 index 0000000..d4e0bcd --- /dev/null +++ b/frontend/src/assets/img/data-storage.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/database-intro.svg b/frontend/src/assets/img/database-intro.svg new file mode 100644 index 0000000..f19da28 --- /dev/null +++ b/frontend/src/assets/img/database-intro.svg @@ -0,0 +1 @@ +server status \ No newline at end of file diff --git a/frontend/src/assets/img/database.svg b/frontend/src/assets/img/database.svg new file mode 100644 index 0000000..e4b3224 --- /dev/null +++ b/frontend/src/assets/img/database.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/debit.svg b/frontend/src/assets/img/debit.svg new file mode 100644 index 0000000..2688978 --- /dev/null +++ b/frontend/src/assets/img/debit.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/img/ellipsis.svg b/frontend/src/assets/img/ellipsis.svg new file mode 100644 index 0000000..303aae1 --- /dev/null +++ b/frontend/src/assets/img/ellipsis.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/img/failed-bg.svg b/frontend/src/assets/img/failed-bg.svg new file mode 100644 index 0000000..d7f1f83 --- /dev/null +++ b/frontend/src/assets/img/failed-bg.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/failed-icon.svg b/frontend/src/assets/img/failed-icon.svg new file mode 100644 index 0000000..349a230 --- /dev/null +++ b/frontend/src/assets/img/failed-icon.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/failed.svg b/frontend/src/assets/img/failed.svg new file mode 100644 index 0000000..d6b1943 --- /dev/null +++ b/frontend/src/assets/img/failed.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/img/fast.svg b/frontend/src/assets/img/fast.svg new file mode 100644 index 0000000..62600a4 --- /dev/null +++ b/frontend/src/assets/img/fast.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/img/gateways/credit.svg b/frontend/src/assets/img/gateways/credit.svg new file mode 100644 index 0000000..279a74c --- /dev/null +++ b/frontend/src/assets/img/gateways/credit.svg @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/gateways/local-gateway-bd.svg b/frontend/src/assets/img/gateways/local-gateway-bd.svg new file mode 100644 index 0000000..5978c69 --- /dev/null +++ b/frontend/src/assets/img/gateways/local-gateway-bd.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/gateways/pay-offline.svg b/frontend/src/assets/img/gateways/pay-offline.svg new file mode 100644 index 0000000..b87005e --- /dev/null +++ b/frontend/src/assets/img/gateways/pay-offline.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/gateways/paypal.svg b/frontend/src/assets/img/gateways/paypal.svg new file mode 100644 index 0000000..4efe92a --- /dev/null +++ b/frontend/src/assets/img/gateways/paypal.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/img/helm/resources/c-role.svg b/frontend/src/assets/img/helm/resources/c-role.svg new file mode 100644 index 0000000..931ad3d --- /dev/null +++ b/frontend/src/assets/img/helm/resources/c-role.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/cm.svg b/frontend/src/assets/img/helm/resources/cm.svg new file mode 100644 index 0000000..3934ac2 --- /dev/null +++ b/frontend/src/assets/img/helm/resources/cm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/crb.svg b/frontend/src/assets/img/helm/resources/crb.svg new file mode 100644 index 0000000..dc2f9b2 --- /dev/null +++ b/frontend/src/assets/img/helm/resources/crb.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/crd.svg b/frontend/src/assets/img/helm/resources/crd.svg new file mode 100644 index 0000000..729ec68 --- /dev/null +++ b/frontend/src/assets/img/helm/resources/crd.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/cronjob.svg b/frontend/src/assets/img/helm/resources/cronjob.svg new file mode 100644 index 0000000..8c6aa0d --- /dev/null +++ b/frontend/src/assets/img/helm/resources/cronjob.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/deploy.svg b/frontend/src/assets/img/helm/resources/deploy.svg new file mode 100644 index 0000000..14d7168 --- /dev/null +++ b/frontend/src/assets/img/helm/resources/deploy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/ds.svg b/frontend/src/assets/img/helm/resources/ds.svg new file mode 100644 index 0000000..a25378f --- /dev/null +++ b/frontend/src/assets/img/helm/resources/ds.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/ep.svg b/frontend/src/assets/img/helm/resources/ep.svg new file mode 100644 index 0000000..f4bd59e --- /dev/null +++ b/frontend/src/assets/img/helm/resources/ep.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/group.svg b/frontend/src/assets/img/helm/resources/group.svg new file mode 100644 index 0000000..8408f5b --- /dev/null +++ b/frontend/src/assets/img/helm/resources/group.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/hpa.svg b/frontend/src/assets/img/helm/resources/hpa.svg new file mode 100644 index 0000000..5c05a91 --- /dev/null +++ b/frontend/src/assets/img/helm/resources/hpa.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/ing.svg b/frontend/src/assets/img/helm/resources/ing.svg new file mode 100644 index 0000000..6d5afc4 --- /dev/null +++ b/frontend/src/assets/img/helm/resources/ing.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/job.svg b/frontend/src/assets/img/helm/resources/job.svg new file mode 100644 index 0000000..6309807 --- /dev/null +++ b/frontend/src/assets/img/helm/resources/job.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/limits.svg b/frontend/src/assets/img/helm/resources/limits.svg new file mode 100644 index 0000000..10c6147 --- /dev/null +++ b/frontend/src/assets/img/helm/resources/limits.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/netpol.svg b/frontend/src/assets/img/helm/resources/netpol.svg new file mode 100644 index 0000000..ec2590c --- /dev/null +++ b/frontend/src/assets/img/helm/resources/netpol.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/ns.svg b/frontend/src/assets/img/helm/resources/ns.svg new file mode 100644 index 0000000..318ef35 --- /dev/null +++ b/frontend/src/assets/img/helm/resources/ns.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/pod.svg b/frontend/src/assets/img/helm/resources/pod.svg new file mode 100644 index 0000000..5b9afbc --- /dev/null +++ b/frontend/src/assets/img/helm/resources/pod.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/psp.svg b/frontend/src/assets/img/helm/resources/psp.svg new file mode 100644 index 0000000..8079d21 --- /dev/null +++ b/frontend/src/assets/img/helm/resources/psp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/pv.svg b/frontend/src/assets/img/helm/resources/pv.svg new file mode 100644 index 0000000..f81e0cf --- /dev/null +++ b/frontend/src/assets/img/helm/resources/pv.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/pvc.svg b/frontend/src/assets/img/helm/resources/pvc.svg new file mode 100644 index 0000000..6b9b422 --- /dev/null +++ b/frontend/src/assets/img/helm/resources/pvc.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/quota.svg b/frontend/src/assets/img/helm/resources/quota.svg new file mode 100644 index 0000000..b28f008 --- /dev/null +++ b/frontend/src/assets/img/helm/resources/quota.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/rb.svg b/frontend/src/assets/img/helm/resources/rb.svg new file mode 100644 index 0000000..f002619 --- /dev/null +++ b/frontend/src/assets/img/helm/resources/rb.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/role.svg b/frontend/src/assets/img/helm/resources/role.svg new file mode 100644 index 0000000..2b10435 --- /dev/null +++ b/frontend/src/assets/img/helm/resources/role.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/rs.svg b/frontend/src/assets/img/helm/resources/rs.svg new file mode 100644 index 0000000..8418fd8 --- /dev/null +++ b/frontend/src/assets/img/helm/resources/rs.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/sa.svg b/frontend/src/assets/img/helm/resources/sa.svg new file mode 100644 index 0000000..6c3cd72 --- /dev/null +++ b/frontend/src/assets/img/helm/resources/sa.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/sc.svg b/frontend/src/assets/img/helm/resources/sc.svg new file mode 100644 index 0000000..7a72cca --- /dev/null +++ b/frontend/src/assets/img/helm/resources/sc.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/secret.svg b/frontend/src/assets/img/helm/resources/secret.svg new file mode 100644 index 0000000..40a174d --- /dev/null +++ b/frontend/src/assets/img/helm/resources/secret.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/sts.svg b/frontend/src/assets/img/helm/resources/sts.svg new file mode 100644 index 0000000..1d80ac7 --- /dev/null +++ b/frontend/src/assets/img/helm/resources/sts.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/svc.svg b/frontend/src/assets/img/helm/resources/svc.svg new file mode 100644 index 0000000..562cab0 --- /dev/null +++ b/frontend/src/assets/img/helm/resources/svc.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/user.svg b/frontend/src/assets/img/helm/resources/user.svg new file mode 100644 index 0000000..072d28f --- /dev/null +++ b/frontend/src/assets/img/helm/resources/user.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/helm/resources/vol.svg b/frontend/src/assets/img/helm/resources/vol.svg new file mode 100644 index 0000000..2e807db --- /dev/null +++ b/frontend/src/assets/img/helm/resources/vol.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/ic-klovercloud-logo.png b/frontend/src/assets/img/ic-klovercloud-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..05abe586da032e8860106c294b160498de7cc5e3 GIT binary patch literal 12711 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 literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/ico-tool-tip.svg b/frontend/src/assets/img/ico-tool-tip.svg new file mode 100644 index 0000000..2cf3275 --- /dev/null +++ b/frontend/src/assets/img/ico-tool-tip.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/img/icons/airdrop.svg b/frontend/src/assets/img/icons/airdrop.svg new file mode 100644 index 0000000..a796dad --- /dev/null +++ b/frontend/src/assets/img/icons/airdrop.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/icons/application-build-config-custom.svg b/frontend/src/assets/img/icons/application-build-config-custom.svg new file mode 100644 index 0000000..d847ffd --- /dev/null +++ b/frontend/src/assets/img/icons/application-build-config-custom.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/application-config-custom.svg b/frontend/src/assets/img/icons/application-config-custom.svg new file mode 100644 index 0000000..a58205d --- /dev/null +++ b/frontend/src/assets/img/icons/application-config-custom.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/img/icons/bin1.svg b/frontend/src/assets/img/icons/bin1.svg new file mode 100644 index 0000000..8e5762e --- /dev/null +++ b/frontend/src/assets/img/icons/bin1.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/bucket-settings-1.svg b/frontend/src/assets/img/icons/bucket-settings-1.svg new file mode 100644 index 0000000..fc86a5e --- /dev/null +++ b/frontend/src/assets/img/icons/bucket-settings-1.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/bucket-settings-2.svg b/frontend/src/assets/img/icons/bucket-settings-2.svg new file mode 100644 index 0000000..269cc76 --- /dev/null +++ b/frontend/src/assets/img/icons/bucket-settings-2.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/bucket-settings-3.svg b/frontend/src/assets/img/icons/bucket-settings-3.svg new file mode 100644 index 0000000..730b48a --- /dev/null +++ b/frontend/src/assets/img/icons/bucket-settings-3.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/bucket-settings-4.svg b/frontend/src/assets/img/icons/bucket-settings-4.svg new file mode 100644 index 0000000..4fd03ff --- /dev/null +++ b/frontend/src/assets/img/icons/bucket-settings-4.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/calendar.svg b/frontend/src/assets/img/icons/calendar.svg new file mode 100644 index 0000000..7333bcd --- /dev/null +++ b/frontend/src/assets/img/icons/calendar.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/camera.svg b/frontend/src/assets/img/icons/camera.svg new file mode 100644 index 0000000..e7bcf12 --- /dev/null +++ b/frontend/src/assets/img/icons/camera.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/cancelled.svg b/frontend/src/assets/img/icons/cancelled.svg new file mode 100644 index 0000000..8d59523 --- /dev/null +++ b/frontend/src/assets/img/icons/cancelled.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/img/icons/capacity-custom.svg b/frontend/src/assets/img/icons/capacity-custom.svg new file mode 100644 index 0000000..7f1ccaa --- /dev/null +++ b/frontend/src/assets/img/icons/capacity-custom.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ci-cd-pipeline/custom.svg b/frontend/src/assets/img/icons/ci-cd-pipeline/custom.svg new file mode 100644 index 0000000..167d502 --- /dev/null +++ b/frontend/src/assets/img/icons/ci-cd-pipeline/custom.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/img/icons/ci-cd-pipeline/env-dev.svg b/frontend/src/assets/img/icons/ci-cd-pipeline/env-dev.svg new file mode 100644 index 0000000..59d0ea6 --- /dev/null +++ b/frontend/src/assets/img/icons/ci-cd-pipeline/env-dev.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ci-cd-pipeline/env-prod-success.svg b/frontend/src/assets/img/icons/ci-cd-pipeline/env-prod-success.svg new file mode 100644 index 0000000..7884071 --- /dev/null +++ b/frontend/src/assets/img/icons/ci-cd-pipeline/env-prod-success.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ci-cd-pipeline/env-qa.svg b/frontend/src/assets/img/icons/ci-cd-pipeline/env-qa.svg new file mode 100644 index 0000000..2d72c01 --- /dev/null +++ b/frontend/src/assets/img/icons/ci-cd-pipeline/env-qa.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/cloud-server.svg b/frontend/src/assets/img/icons/cloud-server.svg new file mode 100644 index 0000000..0bacc75 --- /dev/null +++ b/frontend/src/assets/img/icons/cloud-server.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/cloud_loader.svg b/frontend/src/assets/img/icons/cloud_loader.svg new file mode 100644 index 0000000..4dad482 --- /dev/null +++ b/frontend/src/assets/img/icons/cloud_loader.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/cluster-icon-2.svg b/frontend/src/assets/img/icons/cluster-icon-2.svg new file mode 100644 index 0000000..4390eb6 --- /dev/null +++ b/frontend/src/assets/img/icons/cluster-icon-2.svg @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/img/icons/cluster-icon.svg b/frontend/src/assets/img/icons/cluster-icon.svg new file mode 100644 index 0000000..e48e304 --- /dev/null +++ b/frontend/src/assets/img/icons/cluster-icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/cluster/cicd.svg b/frontend/src/assets/img/icons/cluster/cicd.svg new file mode 100644 index 0000000..412ea5e --- /dev/null +++ b/frontend/src/assets/img/icons/cluster/cicd.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/img/icons/cluster/cluster_name.svg b/frontend/src/assets/img/icons/cluster/cluster_name.svg new file mode 100644 index 0000000..38b1214 --- /dev/null +++ b/frontend/src/assets/img/icons/cluster/cluster_name.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/cluster/desired_node.svg b/frontend/src/assets/img/icons/cluster/desired_node.svg new file mode 100644 index 0000000..5fab480 --- /dev/null +++ b/frontend/src/assets/img/icons/cluster/desired_node.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/img/icons/cluster/disc_size.svg b/frontend/src/assets/img/icons/cluster/disc_size.svg new file mode 100644 index 0000000..afd8d70 --- /dev/null +++ b/frontend/src/assets/img/icons/cluster/disc_size.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/cluster/max_node.svg b/frontend/src/assets/img/icons/cluster/max_node.svg new file mode 100644 index 0000000..4280c9c --- /dev/null +++ b/frontend/src/assets/img/icons/cluster/max_node.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/cluster/max_unavailable.svg b/frontend/src/assets/img/icons/cluster/max_unavailable.svg new file mode 100644 index 0000000..38b831a --- /dev/null +++ b/frontend/src/assets/img/icons/cluster/max_unavailable.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/cluster/maximum_util.svg b/frontend/src/assets/img/icons/cluster/maximum_util.svg new file mode 100644 index 0000000..203ef26 --- /dev/null +++ b/frontend/src/assets/img/icons/cluster/maximum_util.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/img/icons/cluster/min_node.svg b/frontend/src/assets/img/icons/cluster/min_node.svg new file mode 100644 index 0000000..cf0f78f --- /dev/null +++ b/frontend/src/assets/img/icons/cluster/min_node.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/img/icons/cluster/name.svg b/frontend/src/assets/img/icons/cluster/name.svg new file mode 100644 index 0000000..aab1e56 --- /dev/null +++ b/frontend/src/assets/img/icons/cluster/name.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/img/icons/cluster/node_type.svg b/frontend/src/assets/img/icons/cluster/node_type.svg new file mode 100644 index 0000000..9e651b0 --- /dev/null +++ b/frontend/src/assets/img/icons/cluster/node_type.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/database.svg b/frontend/src/assets/img/icons/database.svg new file mode 100644 index 0000000..b4f36c8 --- /dev/null +++ b/frontend/src/assets/img/icons/database.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/database_ns.svg b/frontend/src/assets/img/icons/database_ns.svg new file mode 100644 index 0000000..0b6d5ba --- /dev/null +++ b/frontend/src/assets/img/icons/database_ns.svg @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/db-security.svg b/frontend/src/assets/img/icons/db-security.svg new file mode 100644 index 0000000..375444b --- /dev/null +++ b/frontend/src/assets/img/icons/db-security.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/dedicated-externanl-endpoint-custom.svg b/frontend/src/assets/img/icons/dedicated-externanl-endpoint-custom.svg new file mode 100644 index 0000000..6c05d23 --- /dev/null +++ b/frontend/src/assets/img/icons/dedicated-externanl-endpoint-custom.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/delete-custom.svg b/frontend/src/assets/img/icons/delete-custom.svg new file mode 100644 index 0000000..f39271b --- /dev/null +++ b/frontend/src/assets/img/icons/delete-custom.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/deploy.svg b/frontend/src/assets/img/icons/deploy.svg new file mode 100644 index 0000000..de91ebb --- /dev/null +++ b/frontend/src/assets/img/icons/deploy.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/img/icons/dev-computer.svg b/frontend/src/assets/img/icons/dev-computer.svg new file mode 100644 index 0000000..c8fa329 --- /dev/null +++ b/frontend/src/assets/img/icons/dev-computer.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/img/icons/discussion.svg b/frontend/src/assets/img/icons/discussion.svg new file mode 100644 index 0000000..025b75a --- /dev/null +++ b/frontend/src/assets/img/icons/discussion.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/docker-icon.svg b/frontend/src/assets/img/icons/docker-icon.svg new file mode 100644 index 0000000..c082acd --- /dev/null +++ b/frontend/src/assets/img/icons/docker-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/icons/easy-icon.svg b/frontend/src/assets/img/icons/easy-icon.svg new file mode 100644 index 0000000..7e6d87b --- /dev/null +++ b/frontend/src/assets/img/icons/easy-icon.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/edit-custom.svg b/frontend/src/assets/img/icons/edit-custom.svg new file mode 100644 index 0000000..78f038a --- /dev/null +++ b/frontend/src/assets/img/icons/edit-custom.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/endpoint-custom.svg b/frontend/src/assets/img/icons/endpoint-custom.svg new file mode 100644 index 0000000..d60b094 --- /dev/null +++ b/frontend/src/assets/img/icons/endpoint-custom.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/external-endpoint-custom.svg b/frontend/src/assets/img/icons/external-endpoint-custom.svg new file mode 100644 index 0000000..8298652 --- /dev/null +++ b/frontend/src/assets/img/icons/external-endpoint-custom.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/failed.svg b/frontend/src/assets/img/icons/failed.svg new file mode 100644 index 0000000..f9fd47b --- /dev/null +++ b/frontend/src/assets/img/icons/failed.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/folder-explore.svg b/frontend/src/assets/img/icons/folder-explore.svg new file mode 100644 index 0000000..cbff993 --- /dev/null +++ b/frontend/src/assets/img/icons/folder-explore.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/img/icons/git-icon.svg b/frontend/src/assets/img/icons/git-icon.svg new file mode 100644 index 0000000..dc78f87 --- /dev/null +++ b/frontend/src/assets/img/icons/git-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/icons/hosted_zone.svg b/frontend/src/assets/img/icons/hosted_zone.svg new file mode 100644 index 0000000..2fe3dd2 --- /dev/null +++ b/frontend/src/assets/img/icons/hosted_zone.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/icons/ic-active-deployment.gif b/frontend/src/assets/img/icons/ic-active-deployment.gif new file mode 100644 index 0000000000000000000000000000000000000000..73cc7d3b7cbd018c48727308d303909f51a22db2 GIT binary patch literal 4009 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 literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/icons/ic-active-deployment.svg b/frontend/src/assets/img/icons/ic-active-deployment.svg new file mode 100644 index 0000000..987da4f --- /dev/null +++ b/frontend/src/assets/img/icons/ic-active-deployment.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ic-app-deleted.svg b/frontend/src/assets/img/icons/ic-app-deleted.svg new file mode 100644 index 0000000..0b1d165 --- /dev/null +++ b/frontend/src/assets/img/icons/ic-app-deleted.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ic-application-others.svg b/frontend/src/assets/img/icons/ic-application-others.svg new file mode 100644 index 0000000..78fd2e2 --- /dev/null +++ b/frontend/src/assets/img/icons/ic-application-others.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ic-application.svg b/frontend/src/assets/img/icons/ic-application.svg new file mode 100644 index 0000000..f6e7e15 --- /dev/null +++ b/frontend/src/assets/img/icons/ic-application.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/ic-bitbucket.svg b/frontend/src/assets/img/icons/ic-bitbucket.svg new file mode 100644 index 0000000..71aacb6 --- /dev/null +++ b/frontend/src/assets/img/icons/ic-bitbucket.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ic-build-success.svg b/frontend/src/assets/img/icons/ic-build-success.svg new file mode 100644 index 0000000..aa9a77a --- /dev/null +++ b/frontend/src/assets/img/icons/ic-build-success.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ic-certificate.png b/frontend/src/assets/img/icons/ic-certificate.png new file mode 100644 index 0000000000000000000000000000000000000000..a409f0424906c7d2f032f44e2a7ecb32c879c1f8 GIT binary patch literal 3459 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 literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/icons/ic-vpc-intializing.svg b/frontend/src/assets/img/icons/ic-vpc-intializing.svg new file mode 100644 index 0000000..da9977a --- /dev/null +++ b/frontend/src/assets/img/icons/ic-vpc-intializing.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ic-vpc-terminating.gif b/frontend/src/assets/img/icons/ic-vpc-terminating.gif new file mode 100644 index 0000000000000000000000000000000000000000..ce8bb5abd611e0d8b3a54e71e303ef38a930fcdc GIT binary patch literal 36681 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
  1. +$bb{Fg_1O=kKIlblG|tufU1d$#U~CGV!%$% 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 literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/icons/ic-vpc-terminating.svg b/frontend/src/assets/img/icons/ic-vpc-terminating.svg new file mode 100644 index 0000000..6928bdd --- /dev/null +++ b/frontend/src/assets/img/icons/ic-vpc-terminating.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ic-vpc-termination-failed.svg b/frontend/src/assets/img/icons/ic-vpc-termination-failed.svg new file mode 100644 index 0000000..a2af072 --- /dev/null +++ b/frontend/src/assets/img/icons/ic-vpc-termination-failed.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ic_build.png b/frontend/src/assets/img/icons/ic_build.png new file mode 100644 index 0000000000000000000000000000000000000000..3e0dc9be93184750c93b3e79b43e51a3b2e83471 GIT binary patch literal 3669 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 literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/icons/ic_cluster.png b/frontend/src/assets/img/icons/ic_cluster.png new file mode 100644 index 0000000000000000000000000000000000000000..e02ea5d7ac81516a5b6bdb408b64293931b55371 GIT binary patch literal 44592 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 S&FCNq{F9eemMOY#6!3p{lrO3P literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/icons/ic_cpu.png b/frontend/src/assets/img/icons/ic_cpu.png new file mode 100644 index 0000000000000000000000000000000000000000..e19295ebf65d040a18aec4be4f86d30ecd4900c8 GIT binary patch literal 6258 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%0AFEUM zd-t^Q_X)Hnk2hPH9jzT`<8Lx&4Eur9kloqSOTbKb)j3X5a9tNM^}a+M4560>g^t?U zB_7mu^>pK=4Dua^@mCCwKyd9bzx#BBN#+hF>&3PRkP2`TBl4F-cjrUw{?5Jg+F9)|pveY!V{ENoc z{#tzJR$v=W_Rx6e^~SCUf(O_LU3zir;vg(3EjJb$D9-Tq5ssOEJ3OxKXBk;S@Fu7r zmzjQNriH6_=*8Y)2tkNXTyGpei|dGGa-0lGiPyl1!NtVmE7IWK)pylbdu|ThO75gY z*S5iY*{iVI#nVZIX=I~SjaYAq zb-sTMWW89hcFAuost+E_5GZB3SZrAO@e`e;7%)DbBozaMF$q(_b}Usr%~je*VTzr zgeIJ*fne~NtH@~^a1|tr0==dCZS@}Lqy%zO{vtDkY;T=!NP_3m`|eqkRKJ%ar9vsd zqAVR%x6=;O_=oJA+7BGW3o+^7guUbBGgE|K^tVoi<4Yp&{k>;n#)&ZD=&;T7SB|XV zuG*x$eN)>$@RnB0M%4;a2Lf+v;`UMn-aVq5&dUk>kn+`At#&fIqZCIE^k=!8r`r)B za)bSr&`Ij305|ye**f%MHUf#h_6a45K0(A%Mnm?UODaJ1Vwkpl?-IWO^%deFL4u%Y z@`bMtPv4z&FuzN1FxsvG%ne^HyGV`ybKh^Z_ii_2_4vJfli#XyX78Yf;6H)uqKFrZ ztFg_95c;Z?nbg5zkW-%;ij zdDXetfAac`kd|hplKR(A89LxGzbN+b@$yb1$DG7_{84s^Tl5Maf!jY1vEo0e@vW#W zD1mLEi^-qzN%{-qMn(FD+W0s1ta49%SQt(JiAw!QuH#m#K2WI7{XZKA>mdiPx8^qW5oW#kER_M z@eZ*DIPaSFds1bh#aNu-im0S8gl$uVef^_-gYJ4PxEam!e^BQUZ9*QPJfUq z9s&NRSn`3@T8`zj)EeR`85gqOgQ#+pNGPJ(=&L>_Og`nyqszpB_V%uW#$@T;Tq$BkUO9KPP=3sjNdkBgtvOb!xv+FyoR zK|U1I6f1jN%*Xc`2B}!Q*+l++sCm literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/icons/ic_docker.png b/frontend/src/assets/img/icons/ic_docker.png new file mode 100644 index 0000000000000000000000000000000000000000..a2adfb41900f42b782cf39807cf8ab51d1222af6 GIT binary patch literal 14362 zcmdtJXIK+m6fQae1QZY(@*!QCbfv36qKFWxBE72A0MdK6pdX-=P$C^6fOP341QZ1f z0m0Cu1P}H<=nM%006MS zH6IuN01fz+24JKIPul?l2jJ1_wEd-H+8Rfq2r2kybBDpr4N{;eM31`l7Ppl(_Xf-`8n=Leq}QuPBt?rZ>` zobrovh~P1woMHGk895e2VvTP9%bWH<+tZso_7-(QX5TsX)+sX|`KQcWva!9lv-g(m zZ+09F=~wlgtkn)%YoAW_|GZD1o5U)8#O|DN!(6P%L(ikPrsmho22g$){6Bc~9}>!y zqSwkSTc`PP%BxvG1{Vzw|7LF@L;Ab~g{8eotH8V8P2_QTCmTX7&~;Yd7f%|j8H0E{ zX9QqR+g;xE8WG)5E6p{*2q|jIYzcl@Y69se0>s7v09_Jq^Re%3Qp+5fg4jdSCvtx- zIjJ7>WrxQ5NdvJTKncQO!r%7V;uc9n;3yXD8f;<>RoE#q3MRPGef_PDPy}jXoQ+)C z+ij33CgM%1tHJ;mrz`*iBIWC`ZOVH&`{7H7HREt2`&A*#G$zuHsNYi?S8>JuesOOZ@^$MXFxnpM{)?R<<>>8n zkBR6|qg0~kQKYEu=3mx!BmMdW;f>?5em4j#T>z+gIbHjGzId%3@0%sD>IML15kTKG z`E`Bkuccji)LbEv3CQvN!uTa}C(JIu6YW%uZ``K^^v*$YB8^JS#X)Zg1psqaNRB$& z(D?4T#4!0)RZvS5(3g9iG$B?w%L;fnGXj!ge#g&8RX|a8P&9QrwYNTjj%jOw= zv_Qm=I^blbOl1HvWKLgw?tj4pjNv+X?0d-w9)0-!*Ozn3YdB#Fe-<6{Wy<5+n9M7z zRL}2hzbo_4E$Hm$V2AZz1o+@pXYfxr6axUK#5e)-Fzdb`5wWmYi=y{TIg|i!HUHn- z=YMni|8JL1Ckp^_8k=2X)=P~GmlBWPqpJmbl52)_p#SFI6;~lWW3f_5^-6cT1U_v| z<82c+^R?TDHQMW6*iV-8*Mc(P?&5lEdkByHMABvglpu*RNuLx=i_!qi)X~JCNZnI% z+-uy9y}ZB5Bt$e_u_0$ix+q}pEKbBrooXyPN*fCwC;7wg91BwWwyw; zKUWbA0tN8m^ZL@*RrP2ExLDTnsAhQf4G?@P+6KQ@oE_n;dikG(LnBqcT-L$r=T49; z@yS2q+n8?p8unBDsclmm`BGNbzSvFJ@k;MXH{OK?94^xgsYior*!S>2^@tQHeEjS_ z$%b9@z;7?@FF(r*2|+pfv^S@U(Z(f2bcgc^+NW{ZwjDQ3j4WAKmj31$|3#qr(rD56 zx#986t{btF7qqnnVh#vv3#Q}8dHl;}z0L6?y^s3(bY+fADGcD!hfsHOc1GuBZXVk8 zy?WXHe}h(syqgUaNnxtN<#!og{TMM96XMX1TNfE2Q&`3M7+UQxwaRkj;y4Jd@t1~Y zqH8`WE07Dz8qWS2FIiKfrsma6E%_boT(laj9-5){&(niC4}$PI$m9&J*2JvwKK4~ zk1H^%o$Ru5%>K)o;M*4?<^4+);@tHytnf+MdZYXu@oXK;MJ^i+`iO}*X6bUHofq&$ zWv4TJ=j!}PJGM`<&1*$gAI2_5f7pt#YJVpvsfS^Mdm+NFEF%eTji_mU(n@u)Axt^u zgXW%_3?8od5;m)BzssFZezLh4K9o8^+7W2twg;yN(~Z$Yrr5F>2jHBGTX1CH+CAT? z&ht~~MvG&k4;)pC+3usKm z%C4$9;4QWp>q>e3s+9nLXw?#>V?=|v&UXnkLgXG>o(fX9qu|v3sN0j47mE%^3M+7^>lyTu=Y913{z zc+be^JI{qG-@%{7uGGk8?ZpUN>|a-RY&NW#v%IboUpWkc>&)2oTMYNuWFJ1{GHznnMrYRCl@r>1iJY&rAu z;^vo~(b*ZN^oo)zJEa`f=Kja`H`=hYA9y=u9Lsa7ZAtIDv1jdh{~-UIdRC%B&}80TwU7X6xVX-poP8%!7tu^ZT*~eb)ij~?D~)Ja4Bhvu&h#y zVt{zBBLNfb^43IH^}?xDjQ(3fyKjZB_4e1Ojb4F^-CO9j#!q8`{KGxo(2%iLvkXhF z;HvyA&Zqzt_6hXdu9X)~SvIISGBW6eck^VV2@RSLJ0|j=!N>yel_;O*0ZPL+R}?PC zdPS#T4UBbmJtOep`AQ9oZ4Ve0Jx+DyOnhs#d0v&xXg;7b)atS8o13xHZK8^K`RIA> z&b0&jn8C~U!DV1BE(uDY;XSeqWop9?Pa4H%QnbvHW_Lzx9%p3j_s}scIGt*{UY*Ti z?QI=_q0WD~ALlxPPbA*z+wsIw@ln!u79O06a4Gs@Z#lv7xFCHda|7f+e}&VgcH401 zQ104VmpuG@U(u;CZnev&+lV3HKhqTUe4DgnZ z7j^vMo69fV-P!}E-!b|3pBEnZbz1FyLPz_Hfv9iyUVXRYD_j2U&XK+Fx?Ih=ZF^i9 zgU4~f5VPVl_S|3pxtQlLm8~kvcMs=OBI#9-St<6K^f~rQwI zd+w}Ol-I=9-`zd>BP?l=^nyFuVp?6iC%=V6MT*3VB#Ovt;r`t5l+RZ_q{%JK#c79V3X{ zNPMPGZRfPNe1~rw#~5Y=g~DH_XD5Zk*u|wTo+!nxRc!B^z|`0WXhQjl{(I6N1?~6h zdqo`tfY0L6%jwckximi!krE5CiDrfo|@KsI9#Y&>#RT8 zlO^$=DR3zZbnXcK&(^97L2VNKX-9`&M zHq@qfX@+Kk1{~zE*M4tVJu;r;(CJk*(N9>*H9OGVbukDr@pOI;;^BVB^wjFTJ%7fR zpc{---f*gA?g2EBJ(<~lObAoK#n%SgrkhKDThnEgjuMd~UIql*b#TqEGQW_}JQsv_ zJKG!%6~{6W*7$UV`-LjE-P^zQOm^GUQaTB4|H=c^vw33#H-1LdSl7QZ3ou&>Ph^X= z2FKym>}4cby~tb-lUQ?XcZEWX{Pq`$pWjKSnc(~R$3$Zp{?t3haKqD%iC1HOQS^bz zPT%rOu1>cc^@8}XC;m$p6Dg6tTwoFX`nwIH1M%(@Z-DC0X@0D_3CqZ;8ntJ_ zBho)^ABOEsZ3H7TSoltD)bNfdDYfwJ?#rFsLgGE~kMo4=tHZ7*hqq0}DATVI$8Izu#TlK_jsBdJq4rtI6`f!-VNBv({`td@7!eaxO70=Mu7-M zg`wP->l$AFC*fQ2rXp>Sj!#|tSF-(!yxdZ6Dr|FQ`t2jqom+t2{EcxQ$ey;6qWUPiB;-&ph@C7b5Sh%ergXO(rx27s&V6Z=Ri~(6v!z3Gkris zOb6ug#{`xkam0wYU+A^KstYP#A9ksbLe} z?Mi8W@cVWJs>iDDJ->f<9ZZ8BfESnA>{#L3p~8zTHNlX0(LJ;AojfqfZ5dm6>Fs&N zhyLqKnxX#FaDFbU7K^%VQk8v0d=oi}#kSzk(IU?l^p@muOn^(E3#GGX+XWd8T@3@! zxK{T98*z6@Y5?N9bUyjtn_@qn@j^5|3@$s}Sx&E5SQ!@alkhHe8j5*h;qua{EgIa1 z|6t2>Cm5j2cl(?Zd;JkbqG{sr^8I)-x5D6%o2wIg^t>8%HTcd=OJQy=gh>*fXwkHm zJH8)XvdrZG{6!hpH zc~Y>E!PsxCYe~iVf?Dh1!JFQnqE9mcHLYb6*W?;SJ6&iER5tieJ=R&h1$yXD zy>zO+V;o&^M$)W8OZMHXlphI{g`tk9*MHAo4^gKua&LFAkL|dxrB7%xB>ybsfkF2C zm;X7i(|I@Ulgq(=OUJJW&9|M={?IJLovHu%Psce~aX+nHkG@=MRL35jWRxRiLgcb? zi0Bcq^#KTit}@hjeL}}mj4_bQQ;7_-wgT{E{n<5}(-0us9_@%7K4db~Cd1F)V<|RH zh!a%UsX(ut2%UyH1K-spck!2HxX?)j2gvo zYu&M!kYNEb!S2=TKO)Gc|M5&_o-2Q8BL@C_E-;4Y`gCsmE}TtdxWx61M=EapWQLAm zN)876%+OYxBRl$LS7cB#EZN|ZIXg3^E#Vl~P3>1Ht5?FFzB_^us&9nZ|9hDl8wr9X z0<-(8zsY5AxM^gWwEINn`28%c*2ZIO+!OD+eKJ^YVag4?Km)-_zqWyU^mtq+vp=cefk`{)MwMMEq-sA26(k) zS&q;?Z?1(En>@68C31+3$A`C8h3)vKE9B5HL`)AXPp*4OodA93&Uu5mfQ2PlEsu<~ zK+pY(4Z&8`l5q~_Z=7KUu)G}BmL*F~k9Gh6SC!QdrUrK%&WrL8#dP)Mf@iG)D_XHf z?f5iu#^1(QXCi_Ip?qfkpM!u1x>Vd;W|klOVoA50-_G3{=!f6S2|gpU2im&@w*tNZ zQ&rmc2WbF7Jbj9m759O0opu^eV%#cHpGT*X6%*ue+~uAx9}*Ar`R}}lDJJ0620&p6 znohCDl}{7+Y_?r>!51tTEQ_7)5A7Oj?jmB% z%~a)wOn*aVv!cqbb=Oo5cvF)J#fF%(+l*hs1a-Ip*z=$RHc84w(aC~CD&`vd5!rC& zIaGeAlqE#()v-6CVA;z2?v+9!{39@R2Ze$|`0~yXqrtSi2Q(PBLj27*QZk2Gpt*Gx z5+%$Dtx$Zyo0&LArha}v8f;pu@*2fzexiw39OnaP_RX}?#QclSkbjdMN5jT&3E5fw z>ad`hK+K>1u^+*H&*{25aT;u~9aEe>tNJ0`GKPQQ#zluAjg76oBlcPe(SbbIR`iTU~`eZ!C=Jx@U z?5$O*W%YT`8Ah5v8yngD>i_^E{HVm8U#NqtKM(X=G9G4}k)nLdB!^n`uL&AC?BWd8 zLt9IB7Nz&^BFz{g8XV?p7SPN&(ie{#=o^aZ+TrC{<# zg%xEOq39)1%?gm!`L96$kTD}0^ePuQ!iM^#N%Lr`CDpW8h_X;ugVF4d{kcL&tre%r zf@G585ag?6p*NKkfXp_b*IGK3j@MMpD(5$%Ld{yHsW&IL-ppnO8r|&gFi1LlVdeig z`j9ERVWb!MC|Ps<_&a^XWe4GyCUkl8fRU?fN1}9BQ}l;$DIe{|`{Gv1HlKYoRR=E( zw|ucobU10%axpp1x0Cd~$9$7^ib+k5tb=_ii+(A@uT29>lxx{bS2wsKf0d-(_`P@0 zg3=ZC{AjAY#zOOD_+V4hiN<16OqM1lF;RXQm?E_0*bGIkb=0tf~1b$rq z8p%)nsWLnWxoi(onA4`Jbt0=$NaMt9$H!Mfz2*+sUTmg)U*Ux`(BHSNlw67z5CaK~ z{ZH7{<}n*$e(S&EVXZY`q(p?`Wx`55jRG6Z_9ip9&N-0{=+~J3wd+cW+#Zx{Q>hb6 z3K)V5i29fAbJ1Vfeu|Jim9p=CkH@FpnQ^G&xw%+iQ07yj>OG<}+9N3H4S_v=xLZXJ zaG`j|Q~j9uT~W*KGp6;%?xqx2N%<1gjGqS92W|u+hNeiO6uT0)qZxg;pQ9l0PJb{p z-04O-!!D>r7Lc-K0jb+p$C5sK>uE`g%gAt}uF%@%wcO6TBt5E=13Mr^{Fr!U`x92( z@&v-SB_>P8g(Cbt<)jw*{V`+LTkq~JtS$X0UtdhYkL?;oKDmVfJRC0dQ%fOWsu07v z(%seq?e|gL8b&cCq=RrDkaF^kn9h{yPkOeafcx`crM8b=3t11@w zm5$%`Qa}S(HRX!|$>uk1grhog6I-0nqklSY9s*CF(MJ4-9);$}I1yPj-o_yzgMT{Z z4uPqcj=*V}a(i>ZPc)TdG(6R;^`I4bG-N$Ylr?1?-X zll!3;wwUS*cm)1A<~s}CkVT5pQU*5)&mnkI3((Os`wrZI#D)M+aS40|rjVrwIc~qy zVObsCyUpnm1~P{n5jWWPFT!p+-3GpjZkV?0;T~wEk6=l);_I4dCA~kTw6I@GVD4%t ze)fgzSwQJ=m`A-K3+DH-Y^}Q)V93Y#jI{Y^>95 z26jabPy*Ml&qq~0ZQLcC;DPvF9Ijieq-U+*2y{KUhlc>MJu_(``Z5*A@M64=u0gw} z^D8<)k%<#<9_(NRVBRZZDdT1mYl^7h@*u&~X(gj)4#4zRkN`r7sG;ZpE?hT1Wq%D_ z%-bb?5&#ZgdPNtZl?}a^`-}DOEdUVgwWVZ9!pja5(^XX(Pmo_YJNW;-DGR8H7m!{K zLy`(!r_h3k%*&M^;{Uxi&p>kWqoHTF-e>g)nd)G*LF8$TDyk%9Hcwy3cw&}!&{1lp zw*39MtAJ&bh@m9h!2WICO9-E+6qvCJ>d(PcWij;whhJ@k47l#mWk5D^WC7%??7REm zOf?DnJe1jQ=;C0j9V*VVb>yl9kW?CC^Vz)jV-}`)E|CmnuznHXbqmk>7eU_x_&u*MpVt~?H3Ij zfE>E3G${q>AQ>Ap&=(crDu`PR6WViO4Lv{}<5(gdy`qnpVuFy!96YoD>_Rd!WOC?7 zSNh7D!Q^px+8=;X%nA6njOQfh-D2gG5F}@&L7XShF#56uYJTTqWO$jN6YzPLd0a$v zfe@Ol<(e!8_%K5ow6%77ilOCh4NCiCPc`-WfSgZE&N7jiXFhjp4tn(=fxgFD?`98? zV;dTTEHA0O-+~OVfM>L@?~3=?w{f(ez%Zk+5v03Wu95u5fr=d8hWZlKb%yIcPC@v} zJE>ev1<0{d8ekNqJ-XFkC@FNi19e(DN*M<dD^vy-3%DSo$YBzOCqcP!{zT?j4Y7Le{2}656diycTxYcE7h%=>RUQF&=t#8- zSX^^|BsBlXa0@S_ee)R~B8o18;LGlwynOdwOot~@!~_Df*r+5Deze#z+$u|Le73V| z$8e8uDTt0Qb;M&M7asnY7ABsa6)zIpl|9>3GVV>4#GQZTpeX?iu&Dz310R*kBc+&t zvI=A4=H(j!WvM0`gFm9z4!qlV~ES!k8xh8+erVXG|+M4i7R^v@sX3(7oFI7jb=Z_+4GjTnNn6CFx(SE zvH-~GrjzRdzk{sOW|Lt6cd>cGdVp#4=M88#jybYboSZGc zk84#uxyvTleeR@hf^~(_3e<%Y;vFF*B|avu2;}>UQ-wBP#updRMJ#eo zR#_Ba?ho%2y*3EE<6{O={LluqiHy)k3MND4rep74#+Mh+0dTLqjTnefJAA1> z-yhiH0HK;S7AV498ic7$!L$d3JL` zfYG-oVYYS6Bd5v2V_T5p?Q&p#;|hw!3s#IdUM{*@SIEI>3&3)ll_ggLG|9p%t+qim z8F;Lb8oOX{>`j@XMaa~KY=Jwy^hzZdg{SNxIcCkuLX#()6ID*Alcg<30t zQ&AYwa+e`$fO|~bNE@C+AMqd%p*4DvGmsGzP8^q(Jmsc({$UteQ0-KvkwTMx3+WdErWOa2dD91iR*<%d2`lBEG^VpG)!y9}hA z0+qMa@8r?s@PX2A@m7oAy5wgChD$C+2|6EUiKNvAT?O=r-EXG3S-WN&td2sTfF#jt z-D}JoD085%?~MGD`_%v#==LWBwP<1g^nZwHofgilTRy1wDkFrZYTTl;PNbBQRSG02F0Iux+$d1YchgkE(#WLAt^##sixE`ODQ zW|pw?vekI)W#f~;Ck*P^ctao_9nx}BP&Dk$|QNX?Bx3#>w9BV zBiOz|Y6;9v_OUV833Yv-8pu~f2JYZM_bFpV`cK27@ zl}Sla)Pqnw31mZ!K`Q4l4-Dgt1Btdc)#Q%Fyh>cyYsZt1A09}R^Z%fREw7blhm2X` zPSzjLZ%^bWhL`W15lLX?rSPRGwj|Y1ut*z^$2TwjG>!{KMn2*de!$;E$ zL#1^^C$^NvXaS{X)>#J4s}Rbk0=KoT8suzAU@tGf-5tQ`IK2S9Kz`8q@s9}fr|~x+ z_Pdbo%8TYn8^qe-@w?7!xwuJ7>-syXEd70+RotLw50~v1YlkP#{-fGtl*Xg)1$Ga0 zg9+N~#dZvD;%*PQeILG3K5tifSF)Qgz3t)vj13KlIbwyWu;-ULX1Ns(%k zi9^-obAPCuc8vAtc=T)kaZySnJPz!K!(Yu9tjZPzH0JX~5wn#NT$fvVXWd21 zERK6>IPc9n70Cm=GSWYG-Ei4jL4uR5*h+mM(Gzy~uPwNv0N)&3TRXMoMs!$G3^c7Q zf8B+Z_n&P^I1wIazlG}3gBG?!ZGjMSPRRP@)IWRQ(H7d+-|o&%?LMQ}oUNK8Qt9E+ zU;m~>>GWGEEE)V3A+e)V{q#Or&SoupQKejG)?}=}s+N~Z%yE25T?3MBm^u7mIjg*_ z#IlWq#nC0b3v}j@o#f-YB!;>|?9X+?406KQx?XJLLr=tvQ|gC^*!+`Xrk068mAyit z%*_3#B+(*ep=ApgBT&^XlszszN%@lW0TTv42_2ltmUeIW_#!l+sjl(Wj#cPbZZT;s zp{AK*#>_w4bwnIpeqZ)2t;Z!W98K<_<>XWR#Cv5zTP!8RA7wYX3a=UiMIUG)w!3q` zh9?ho#5nf@TFrAZA{n_?W@^)j-Q zRlYGi>JW?A(nCq!G3lypAJyW+D5nVTg6yNzVAtuW%TnR)_QWM>qMyLm%9_>W;*&B9 zYTj}o&!P#klL2ZIXs&u&Y-by9%EkC*zA_}FB4jU*9ECNo)W_t_AHHq3YBjZPC0igA zX}I)b+|Gnt@5Za_+1OXj6>Mn1PX_$an<~28SDjqe$dwn{^(RCow*rLyHiNUO#>;Q) zO;Ek_Sz43!uaaPlFAf=}IM%6Nm4B?TYJ^_J(3KPQXs|9+RhQ`mL9%s{H&w{5@1mWB zR^4KMcCUR{-o%J;8bg!(q`%^vs33NlxMn>+)W6GP16K z&jf=nyH>69=qi^kQK!}B8Yczq)~H;qOQX@x0VWJ@TYg(*WHsoPD;C~rW|2t93{zmD zdudyg0@m|zU_DPs50h>iC|I{|HCW3&nF$)JXek5WljmXRE;`AyY)$Igr{w0g&sRAD z8> zU~%;P>e<|$M({nAQ@Eb3`f=0jWZolGlzs7azl+JL7KV+l<`uH@QtfPrh zJ3XNLXmt4(63<=GE0f?I6VLt!x8f3_F{h8)IUyem`lE?w!6#G+0;ftX{ILAFevW?VlOWq76%$}6Cw)sC0KCU%e9ZjuuA4%|&hRI$4vhqB7 z3QR0qZBl$3K#CZdtEu4eP=Ilx1E}f{lGfLHw<|Aov@wxygsY$G-3Nqh*!96UY7G*?4-)=a(GP5C%MGd zdx};{34V8B<_&MS)WAMSf6THsat=+zZ<$qU+<8&tI&mL2y8lQ6Ef7nRogu3o=HqB3 z?_#OSZ18M+@bQzxW$BT0KUvr)BhdM{A!uLT;Q)!|g=0_xm7le*nM(9n+z{U_Af7i* z)-KjjocNv1h3b6|pD-xdixcvru;(g4e>}#1tp<0X)5kVhCKAR}!vY&UOtNj|^SFUl zQ-wXBqLO&OyFZmGhS7_j2z?fuD8^Rk_{q*9UEjy z@HEmj--xD;6DPq=bdev|&DJAa*FuW?RVyz0A%l!my*1Oa;vG6j`J%Od3Y0~9eJxft z3yV3WS`=4}BT5B;jOdQrG{YaaF-Y_IXlG>8eAmI8cIcKpg{OsPG!oM+BOuO;?A1{) zUNtG`Un@3Sk|GxWf%d>dzedfBQ6*+88fR)BtDG>UTBrL-7Ya^FE_27vZR3OHD&2C7 z8qnrNo}Z-k71qf3M9Id(2?-;iV|P5MT-wV2_hp14ZOt{BudZMVtB<~K_yCDFIY}Fn zX(rm8(32_xqT}4Qb|B5YrD;>^)Rg2x5~--8SNjQhH$ZaT@Pqb2;!kJAsu$88ON_wF z*$S>OEa`|K#a3v9Jmx@u58M+_{dchz^kuq`rF~V}gNWA{o_Aqhd z-)>clHPO&}YAD?TB6A<8ho6N-o!CF$`kgqeWsdZ_8}*ajo)~ISX|lAI$Tp`*$=x@& zqZ;R8kUy~hI5WYd%fRL{;*H_-{xu;LVG>i7<)@4EP3H_u?xjfo z^nMr4Lz;bzl0ZFKvO$LJOM7A~k6&QLDu(SmjjT(!PimX4n2>5aT1{%N2dWTT#yb7& z4?=Et9oLp)7M_mw0ITnTKDzdjcj554VYnX%8g|xFBI;IEpS5{Nc8_PWiGrfY)N8Wm z6W}uPVf@JM!F}D$>h!S&?TP*Qj*5ovnU1a92C4Q+@JnVOmtvSZSIoOLT}7dhvdTfI zjTPo#>;qH>fC~U}_`XMmAC;-#{z{M{PHKIDRz*dCI5B!rbF&rpCKr~n?riI!sO4zyQ%!vh7~)mY zlXL?cD%53x##oJp0|sc0fgSz+d)b@kQ8xUG@`!p`Is=)-*gwZZTA-NI!YhMO7RdfH zx`=L%<(8oSaQ~R{_?r7iBRM-sLdSWyR#P!Hg~b9U5rP}z*WaEAxSZ3rf3dnf@!h?j z;15usUvIr{^eMDU7sKXb{(NF};--s`IP6=cZ7*L?kvXn2z4`CTA5lbNqq~^y3Wc5M z6{x|h1JsDoz_dNmy>~L97t>oU$o23geT;xl(w}^cz=+9m=|=jNX{U0 zXddRKd`nmNgye9#pgN-djo&O-kU-&E%yH^AjwY%(#}@!|)82O{Ywv?pspoN%QXmK) z-edCC?ONfKp%yDQm7G>3MiN+^-030|Zq0Y;;%739wd%|XoI<|&LjWL|F@_S}iH)`cRr%R(bI!$(eSmhpsJ#i;-N`<|@8lx){mkukTY;u3(@ys^4|*(a zv6LTHzwuW{)=Oj*ZpR=s1y`#>$gR2SS{049Li(j43biq_b^ZC7k5}%hR9KOUj{Jx| z&u*_ighT)lvtTb=cWP?&17FFKbZPlG6wWnOTU*!MwJJ=JH{JzCh(O;TmE@g63fre8 zEk~efk?Z~=5bxE!pSv2By#ETU#!c_TGOCXwKi`z0EGov4m3d$#d|>+`n1~VY%Bwv3 zF!R##7sKf98s%s1tMRS1EEBuH#(Ap`tr`g=QdfI<+N`|#;~q=jM(5~e;Ub61 zCGcdTvisSNEc!&*Xm318G%GqOyGuOl&Xr!BMOjozLp&|m5AlECC&GA(N}C}6a3M(P S>X*~!gRAR3D8K*o)&B)E2nw_S literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/icons/ic_docker_black.png b/frontend/src/assets/img/icons/ic_docker_black.png new file mode 100644 index 0000000000000000000000000000000000000000..f9c5a2277a4cbf60970c7eea7ea6e7d6cfdc678a GIT binary patch literal 12795 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 literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/icons/ic_dot_net.png b/frontend/src/assets/img/icons/ic_dot_net.png new file mode 100644 index 0000000000000000000000000000000000000000..352c912e585a767a3f3170b579b85f743c17fcb6 GIT binary patch literal 18989 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 Yk^lez literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/icons/ic_expressjs.png b/frontend/src/assets/img/icons/ic_expressjs.png new file mode 100644 index 0000000000000000000000000000000000000000..4ca4755c2affb2e73b1f582029844088b9cfc754 GIT binary patch literal 16788 zcmZX+2{@E*8$LW^FqLIUl4Tl8$eJxQwhGw^*_Sj#c0y!p{8YwPN%pP9k}M_LBr;w@ zi>*eM7@9^UiAY&1-!;GY{eQ=|bR2E-%slhl_kAtrbzbKs^`x~4&n}T&2n2%1%+$yZ zfj~CG?{_;m;T7(GMxG)N;s`UNW2a(@7p5*favUj{-CEP;Hn!c4}HG2;PWT^JuU%2k0Ffe|ZAZGZw!uDQ^?c}~m&E9c;L%L@0q^9cS zT8XARJ0-62UA2htS2hfddiC^d9$*>YyRvR4(DdybA4 z3zK_vSsU%h;g%$Q(NXs-)~Gz~RKL+C-1S8KZu}d3pKUuQJ>Rbi$?9{RvgVxJEE->haF?RgWj^0B#@0A;V>%llD{ia_}#ON`jwqre(B0cD6 zweaB;xltGS0G{ySUwBwEPnSEIV!g>W|wpMJ->3fQ~l+mv@FGR;t*;k zW9IF^F^09*#Zp0ZZ8s_7YFfcty8zC3jxe;!fTq>Lg5)%xZh>D9|GbK%)E$CM^Gvc1 zmW*-s607hZ6__3Ngxynfm-n?3)h9opcu+P*T|^cyGG9Gcf+xFb-eW0$=rGE2m%GKE zLgd)U83xkJzf^DwzDX=St>Ba+e3Mec4J);4!;W#ODYx`%WqR$-!rjdD$t$UbX%Tge zI}i^Aw)CEz!y5UB!v#5gG6&Ua$j{j?3)#U0V_?Y&Nq`@XH@d%y*uq+Vtj3G z$I`xr)a4L(XfUE)J9Wm8z}k`KX5lc81=(pLy~wZU*t`lYMBbOsi;mvez%gPuuc#(J znQF071`ArKAjnj#bd?-07Sef#Pmeq$9@6F+h&7rp>9I7QNiH&u-~Du4J1uf-m@3md zS(j`Y2gf?L!I0TKOAR?bK%8WXhhZKm4yFAWJyX5`+Z_l`P(zZ%+8n-S-_lL7pj7^R zzmlZxe;S=VMHMZOeM@z2GwZQz`wu!=CfqaVS=3&X4YKtY&UdA2fIaukp!%35-&$1% z0c%tUZ^OSrYhlQu+GF_iB#9Cx{m1a5)8ZF)zYBuP#&G#RXsrURLL|;ltSV@dWHDSO zIvDz+%fr&0PrZh#;K4VQB|g|3PuKu%d0#bomWTbK5GKaB$tl{nm`kOCDJOn#&?=Wj ziIc=sY`-IVi)597vlH+ZRuWVfR>jddsJ@hl+QwVob}a2^C>bubjz5N@pJHY&j5K|J zd4VhZOZb&2zUo8pW=$MDm3pLXxVCYhvswJiRAm2<7!pU1XBN-6Os#JUwx(&%lDqJv zx7X7OxC<~L_y(c(g1xqiL6Y^oan%_@a0ph40nhW6V+B{V!w-K^o)@>n$@`wS)F&?= zD=bx6-V@KrHvp?LVxVd*`HT_OT6yvUEMUD5Rvq zCxsZ7r1PWpO9S^!{C!0kHYlXqu_|B@Wf*SL2i-*DV`R;x66XSdi1ECd6>qAg-*{`4(*X7gej)Vf5I8esnZGJnO|y zumjzlimw_8Rq$R#c(3UIQHZUT4T9FKV4?7`k?e_34Gn$r46!d&OMe(%T|k64K7kBD zjM_KHE!bEXxKTtqMnUzh)Q*Q@E3dgG3N&SpZ+w!Q7gvjw_dWbMStnEb&}i?6yH%ua zW1ZS$jbr$lkRuCXrHPs3wXo(WKH(#RjUwg(8_`He7^;u1uJ<+$;!OoAt{9$1S~m|8 z7)O}d6OM4Zc(@(yhxF(qNnuY}BQK3ppUjo2W!YHAI`c4tu&0Il#$XS5$_E~f@o6Qs zgs;pmQ2tE(cCBxE_cxZwb81p^vZzEwS?V6aF17@tNHG^7U@U` zOo)8A^Md?Dv`~B2`qkx|QG7@6IC=q9v<{BLyz%;{ccP+7k$Pvw9yv0jifUH0##_u2o3ce~QuLjg21UTJ&Pc{Lnen0h9U12#pMm!9j_ z1A&B4^=Z=Te>sd6DevpSOfIsZd&QQ5Pd((D?a_2bXMH_)QHnU5s(@>CM*GVPHu3`a zky(BGGSCN}QR&%(w6(qw>Lo3EmJuIXPGFu%=#0FU=7L@a&z$xjY#6jtoAQ5kzuY@B z1Qmkl6@dUZPtD2@s!P^LN_%&3onb9Lh%63)P_&Dwb@wyE=PfG=d4ws05irg&#a198 zMpY6t+4RZ&)Y3>NSFqdC^~}~+c#_6-%;G5~57P`z{Q`ST#yB;mH7Xx(rz(22DfIIS z^-R`sZ}_Xq1a&(R9K8a}Y#7Wp$YA-zhUY?`*nYuAi631F#p?ryyIB^%w%@t(8mC=l z_0CE`In%XW z@H6Dr@E4alqw*ivs#^S;SoJlMMY-Gbo{)c zv<{mtx8lo20sy+K4*?gq$UM|JqEl`1sbe+ika+etkV*oS6k>3v^OU9xk)SyhYZh*s3t>t|AOn!C3@bov0=9F7mGLan`dCY8sF!tlHGEj06b z-*M>aM{DJ3^}ds39bbr->JquI$UOVk5$-i!ufpI$+Je-x&gS~L=)klB%;IsT3N?uJ zi0pJOde*;~Gwbm>_?4FXEJYjKaq_rWlFJ!vxnkxaUwyJbYMi}wBOJC1D{Fywk(?oj zB65*=tfNjN&$TV1KWVn)SJWf>h<%VZoGsixHTB|2rVd~{l7m$x1X$<{B^Y4%V_uq4 zrUKk_nR@0*%W8z%Ex(>&SpI`o=xF}%S7!ieKE{dtnPNtl%KW)v9IqWQ|6MX32 zoo!QNypj^<(S>_8vv z;4Ey<3U#HYh4r;HxwyAmlHsm1QS;)@?cTxtip<3vpBApxskz#;E4V_%VI+y8%K`9{ zb@P*Z$4?NLk#-0nxIZD}u3n-Wxij9h{J}jXb&J@H2DiJGE5(Q9@s+*xb@h{T!7L+Z zlH~U@-Kq(r%#sasl1|d6i;iNCc%>whSGqE#1}l`d6T4$>zwK8%aRHNr{} z3^Rg_^RVdoY{KY|h^sBToem~G$CF5rxtK+Freqdm4D$;_?dxCaD$UK6e5-|*K2fV0 zT1pU;hV;u9FA2)p7?-QlD(3@9>C!SR+-1#ddTD>QGt3{XJsQ7!?bGGQo{f^%5Ey~H z=EVkB#3$3>wY>t9iE-fEV=uPMrFT(09f&G(0u zN=HLFPmZOz;15KohI`fqM@x&Q8h?`pgm1^APaY=Svk%sJ@Rcuo{tb3YH?%>aN0CP^ zF?lsuzBV}9nt$$DE>5ytkX-9FTNTxmUy(X=78amc{bzZnq+O}T`5XbKsOwtS>?@@x zd8EJ{_}K3E4TN0lpg)>nu~pA}tu&ZkI{b2FfI^p%jPu}-aXZ(~$=a~ZnW|c(>;5gh z(0nK0ZPtt=0qRc4aQy`hc*_La?_=PEI?FvLJo;(;O4~={cpE0I<9Ek_!;v)7F^g|^3eJrr6`ZF*Y4+63Q-1UP!L+CCj%1X9jQZ47klUxI}ShAo?V)^e`0U1DoDykcqe;J{Ft6EPZ9CZl=o z++B-=FsX@3mD)2WaCAk+tj728T!4lYn)PBFAOGCd$c#}*rvI2#oWZnB{Ox_CH~)Ol zFG$Gz{HIF~)2=s^R^;%)sGRpl?Rc4APcX$Tsj6-za-5yf_2F-&gh2t|P4>UB--uqqWCLWW9ds?^5~uUw=& zPuYC=JYLPhWbbdqgb!`8yPY8*T7&&bo?Ys)k`8HmR>)uL{*YvK(Xrk8V43zU!Ug4% z8Tgx-Bh-rxEPpdnEN@AUM)|q<3EzqMQR{rM)<)!2<=jxDxaGSRw$_g>%UIUka_t1( zN5qHu38YUf_hwz4SEs0^zq@VYTdg&|ZI!V3&o4e)4emuF^9IllS@LG-8})1yx*Los`6;kk^G8<0>;5ylCNir=<5zupteA1UVTU#9ty;js?=-4z4N5+|QAWdk|$+ z`r#HwC!WR$FL%6qb^EaYBZBXfo6FTdNeYsZf;XnKl`w4BCK(>b{@x4PFT#FPmYR)? ze7v^1mzvRaW)6CLZwFW$H#TCIpFCUrpvMwy^92x3M&+yj|3ANmEme{t^D!a1D*N+q z)Hk$W#0?!_cD3sLN&M^8#>n5NpufddyT*Xw?Ui>MSh-9HP#Vy9Z^XuffX(7Mg+DSeB zyV6i7AxtN=>SZV*k-K(;|D@VJpy_s*^~`fKFvMY!jaRVy{lj`5e!u=+#)M$_h~H5) z#IZ=zhd=G0cCO%H^Ozd~k9!spKh^f5YXGIpJ}9A|G`Dr$%bvJG<9I!j94B~?CW3n=!3I%OF>mo=@)i(qYqypPKhp;O^NAX9XIjJNz`YCc zZGUSpA?iztOTTm#S|)mLs@>1u$toN}&qRpNPwA7LR%)I7mL@8IHblCki?2VMeWfO} z4zy8xSPju6X_h9DO*^{TyPIfF6yQF+eS$e`?!C_FWy@o0MXY4ZG)>LTwGE-y_?95V zKeZAtdk)V=6^zIgQUCZkSrqMVs7M&joOuyi$QIAPZjYl2P_V8VG%wk9XS-X>(y0x=2>_pcdk|J+m7K0dml(Kur9c8^q#tV7+ z)gpAGi%3#I?2p`%ly_6ZB~sHbt;yZ*Vz6DHKK(yq}R z$tcn%_YsHu_3J!;`pBqp>yw44e_}9qkB^?3Wix;R>kQWDs&$X04=Fxu7G=NzWv--$ z7IM7}vk0I3JKJu?0nDx#0DNs6{XF9-b%j!{r;JRzx#?$qg~jGZuBSD%=POIly|5G;VS1!F|Vyv3)yomOPbk4j9yV@xa_B8d`=Ps|_3(H-C=U^QJ8q9U{h z@F^OvoM@}Oas`9x*^cIQ4{}{*RW9rs=Mu9tm@Z5F%NOQF94e!Tei!zpU9yoJ6rSri zP>6`<2^&2&abg=$Q5S+P#GkpeV?4LMjbIvSUQnf(o~vMbu*!|D&t$%o|&7RrvS1`9~`jny@OE97nZt)}sFIbcSp?`q=QJ zOE}5dXpNui3y~%_rB1rCz|PR4q*97^6LRO2adfV^A!Bo(M}wO#Zw?B5M|-mU<&BXZ zN>l2+coqJVqO3-C(6?5qw_eFnj!@pc?IaIyh9KIbZnOZW=4fWIeCY9@swJ8@o78z= z@1x$Sg;|#dOpK~W$3W>2N*`Gqv@cj=F9h+$k74yr`7!8K2QsYJlENM|0q$O6I(yIET5d* z<#Gua`m2Y(00kfLnfup0 z7#36xSqCkSb#fF*^R>#orkAp{C~kt%l4^PmDJuK(?U0qO1nfFz_y^ORsU5l@*t>J! z9d%%tyu|?}GY9vhrmK!?>iSF1ZV`Kq=9CeH))@~rLm#TbyMk>;1T&(c?0=0n@~F5o zzP*_2hK^7F8ghC2z@rJgQTE(R%Lyi?4#myz6ns4RqLCoIl=$GO_DAMhY2!8{VDArg zq!x#i+$+mVon$XJ1lWLyCkE_oN~I=5(4?XJz$weW#p&3i&&YPI8@~uUa6ofI?_9}Q z1g?emwGZnJ1yRJr+>b5|!+0ZmKy-W8Z$({078k|Zn+tuxI8HFuYEeHM&@oiJ(J*Wz z_tK51Yl$-Ue}dVYf$I(q`zMO1zu4D!H_gz?Dw3ipulrsW~;z$vp5Y;2SUNn#(A1(-}Ti z5rX1%OEK-;?KEbd0!00=RU_}~=LRn5bNAlLeA_uMmhkphe2Y0Sua!jv>}||1&!$E? z{wU7D)njrWtS!<(-dCp<)#OlE6W@h5v8xzq&V){c)!KJhQ#b{GwC~T8D56g(#@cFH z2i&!=-rVDD&Ep++>KyGdpJh5sD${mAMELY(ihSoS*NV>Qk(*COk%cE9zUWSz_W52k zirlSN5CtJZ!z0Jl#Hy87ynPo`#>n5-qKK8Y@K`l=szt%r+Y7XlGkv2+UT0cCcsCpV z6FQGbXdl885lfg+Bq?~bJQ?0G|A|zDfpeZGkV`Y!juF`=Q`sV z6x<{D8>S`a@@*%)P~jZ!eCEXsRd$j^$P?(+lJQR+2+t9f@)vJl3uivLgj3OLyTY=f za?cd*q~EGX>67!4I?;|OQMq zLQ2mr2A>L0PAQh`gXThj29&5dMF!S5t&c9Y71OsQJ?;@?>TUp~f(elh)qSV&ra01r zz9pbfo}%+KCO`#`$D2{}&TXodqt%p4(o4*(VTV?4gRTuDkSGYkQcM#hnagRUP z)vjPE{WrlJi9Mpmq3JEWBx&%AA`_zVmoRG9zHZT#^PxAdD#w+5jpdr!>lIik=!pGV zAq`LC0G{?G+3jlSVB4MOFF%_8b~2JDEfga=Y@#|pX3F9ZyXM-0zi7tpSQk?n!keaB zT929ixzvRoGju2Zz%Q-*3>R2VwT_5XI{=T42eiA|mB71hGOx%+)r)Xx+r)oMjw^Ad zC$iO|MaL;0X~+mD`O_U=#N*ovl1 zi{A@}9ZNnnx`)vp`D>zVBCZaZxZ`r9V?onpI2FM7TM1z}>1P|6je}D6)RGc82GOml zi?eENo|!9_><&UiNMb0x->ShV|&-`FJ!9K9JRv)+P_2U+k1 z5cM$SyTJ7f{sJD|9lz5tA=Q|Wn^EE$&?AyG$@1%oWlT}jM_tO*WKgHs|JvZ_Lchu# zv2ZaNa>40RL7Wt?&SLYRRE{dYv$UINAbLgkYS|Bu?3LrW&qYYUPH z?^MI<@7KBpns|pb;iFRU(KKC!X`c9f&VKOGnLUiMgfKrBw7&psn(eDb<_26vwF|}Y zzJB7WwsYMLNB;%L^fpz*k@dSp^*zY#aYJ^i7yLr^Us8ShcEd_(qb zC^1bQ*{R4@%%bHypH=zOWBlG={0PTNE>>Gz^?)quyBRJ@cS4ty=!1)kL-5P92e$79o{L)SKzxxGYO1@%Onwit_pjfC{58*QMB$U*`Jz{Ti! zpv<3_^dA_U8emJ*N+>STxBedTYC?yX%&}hkzjyNYH8NE~`zJe6F(HZ#j|Qy9CWoJ2 zq&g(9IjuAHLTs4Co0b5qHyvZ)$$Pp}fXd)0*%%&kGi(#ByCW3CIKqe9Gj606kn+Kt zaer2ak)W~Q*UIcHiuotv#0nSP@1&}zprAT`^(}CIq#&NZqqtB{4EVjykZr|4gpz^^S+W_<%8_{_98)Ej zQ-#EFD9e=oa5oV`q}Lk0%~?$$nbtvGfxej&ga*YWT&gUeE=ugNm1fWi&G&*ZQm-J@ z)VsWnO(7|V#Y&G*2HyIKQs$_~6}!u2)%pF)0e}NfBTX2)=|)Tdc7~ZSiu?-k-AF`f zC@uM-V+^B?BG4Ot?QBvMu?@=TEJstDfHKK?k#7xy5peiYtkhOi#BH60jX+9>(%UJwfb{VB`jSR((D;+8xW;bTMz%blx_Z zM?}HiTB-Ko5n(r@5W>$Qzpm~AY-ZWQd(s3_!=CL?JVNC?o|rNI-Ua>TUVVqO732c@ z-HvzG2v{Qy0@T+q7S!wt=nhN>ZsvWRGM#5~^wK%no~=3*VkIF=pw{rk z5}eSE@v|j{C!o?Syt}LCn>J(5Jf9lD!R5_;-@Q^`?^X?C_@h4(=MidzlseP_hnKbr ztjExSe^_&7}1 z+2(xs;R@JM#w8Sc`?^0xa8%;sczoDQ(r{hG&pXhagSG4ftGI`^_=(JY(BYuujyUy6 zF4nJ9(BX@(JqvMYIDAdi7jzE79=|ph!NSsh*xU7RcK(06@J9`vU>4coyHs%QoKT?L zyS{zqe^(t{(O+h@8E*cbCmzfy&m;cSHuIizg8LoxpAKpS*#DXBbStk!=Sy_7^hm6{ zj#2Z~m;Y|!7oAZgXIKL!KRP{dGTz zc#Qrrd8?F_B5!D#{ZZTI*M5iZLyZ3G3PuoX%>4V^?+4ag|KPncKm@1k#^!zwOW0S*Uv@BWol(lMAM%o@|8)t$ zZ42T&aicf1#mernvlLkWP*q>|O!f1D1_r>H%BZvHnm0b%^HR7PgPsdN+5az-0nGpqgN4ew%_km-zhZx z78(9FL`a|f=crBF=3nv}o=wcUb98=NdNKWLAluUS&EIRS_VoO|%qmnnm1i&q;;laH>du8=Y4O>Z}Y8b9V8 zKBZ~&rmn)MOUgM(@X34E*(PfZP3LRbpZQ?#vTE5VyZ61A<$);Mr5VHU)p5slk!43lfph_;u&5O~_r6gf$&N{5Yi!9W-2a>WF%`_#+ zV6c%XI4>Ry@v06A;BJavYG0)>{!aAHzq{aNC{x)WmF#FRBz=DE)5MF!4K&{Un$oSA z27J`b>G(n9s*7LN#8;#~C=@}emYBl?m%QmI{~2L58MmC zbQ&=b{o-T?Tf0v11|Q@^Nfe~r&{Dxm?DUM!Z$5sxhBz(5tF+k6JM0S=0b(*enf4Q$ z^NMyybch&OooR{QHx`9wSSt7s*=eH7^qd;xVC-a+6yj=lu}CR3cEC)Wf1xdVgi%8g z?#-h1?q#S$Y4Dg=veV4QSF#(9xKdZ)FJfKg(Fp$fEnkC2q;-v!SK8^^K*RX3!-?&W z(Fsp_p**8a(=#EO5Lu0nPf$_1qHiYo=iB;RrulcRZ8G+A)+6__4F}nqrHCO**+PaI zkH_%_vhHzj{{KOaWr2}DkY0e#hg(FSn1Fj>lgOcgM-sXrmVTssp z?EBgGk0v(6LNcEF=k4D4vmlycoM#ME+$T@bhWHuA3|mG|6Tu+>vUqtqgboh+PWoJO zAMrYy5K`STxp^{>avC`VdozsBhy)F!so9U(9Y+x%t6e4R@$6)TUPI0qr6msnayU1Q z6TU?ib^z~%ee@cwC7_)h^Si%*a-c7Wr{Vhe@3lCp1a+$SVtF3`#tgt=*ch=GIw(~i zA+$MSa5s>R-)JMfo?bjl35>H|$(zzGpoBENQm)1LH5a>sg4V)n@6-m*Y#1MCdF71U zO3f@ALm9CBllzACzMcx>T?$_!o)uz3B*PC)x-;tLX577aRi?##wZ5S=Q4dj_rns@d zK?_cBWjjOQ+4xdMMt^P}W(o8HUQW-q4nOy&_;{JODW*@CMlP^lsJgz*79>?V-fp$k z;iC=DEFz*);FI=dI3+qEEO^>N zO44qp|HGO0UOI;lpR*DPLcZW-%2+8hCY5b6LePsNJ0D6)elo}U*CTShJ9E!G_v+Mk z&Y61qL0n38zcc4=piCNAJ+&4V)Bl@&o$DKyu-H8ro>iaKVQ3s>7EoH_!?aLZRf{u{ zlC(1{QR@`t;;74}@V~8~(F@w9vObjS@nJ&9pO$KSvmi!_u_-k+bW3( z*tZ9164g};=NXdoir7a%_sg`)KYfD$bi1(Ve#(3#Lsp;suqyRrsz&QUy9j-9sy_KC zv1~ZwcnjonA!y-tzY|;IV4%B)?9H4ILR*Ynq^DIzLE!Jr=f!lvtfUP_FTzP+mipke zVS{~$@SrT_;=S-v!I~u56l_&nFRE2QDAhdx+iN}%6mk*Ic5cwp$B5OejoYhl+PLeT zRQE!c4!uQM3pGotHE5cnoCec7Fjxf$_|)T#@rPj$AcU_*#w<@!Tt;2myo4TwkvsjJ zm2R^zOZ<8AAv*zC7HCPBL~HfoEmH?ucoE;4dByF}`s8X@8FJfFolBT<7V16G#ZZw8 z2HhGG(L-UEPG`Cs1rg%&Fd=uN@^{Dg;}Ijl=aj%5hF9vSe+W+Aam)y<1n3Xvnfwqn z*+ie`Qn@Qso7!;Hy4dEajMXE}Yna6Y-)8#|e@E~{Q-_M=)JxXxA)y_zO+}7~bd${@ zlT-abJh8>Ik89I}>Qm(?WdcR}oX%+14_|F|y`K(}6TWIthP~7$>62p*^m|U}!Hi)hR-Wnd41O^HwkEI+s zXCpCr6unD0@Un?NkhdQ5s*CB9=aU|~&YE6;F2CETgi&pI zN2$~9>%Ik`Wwfk8=J^?$w0w^AF}8g00Ea03N*$|7O{I8HbFMf0W3%@r(1QU_R}MW* z6LY|yT$iN|n@ya0u^;*Ow*3`u{7;|JJj|j9p=vX{>*#MYA;f>h}ln`=dD#MB1BEeQ zWn_HWSEbR7bESe&ItWJ}BU)0IMN;6tM091F8;S*Zl&0319&)}*^Wlt|)SB}$QS(vq zU&R?opXQoE?EOCxko}Ja)rju_$3BhPkriT&WWRy{+hd=lb;rood(;snMa$}4Mh%Nx#NYF-Fq~TaO)xzv1V}(K75T; zozLkdePamv zE85>5OYNzJ9gAeLWyv?$K3-B=a-u}zpWLi+!be6*gp*poriUp*>%mIFtAc~J#=ue| z1SWm;!X@Z6pe>r~;ZD>myKp32Ke*8N>Mrda?Z=DzV*NFuRanW1XQ~XLe0zWQ6BFWg zvF3F8Tc|2@8>;4yKR8nR-byEFk|=93d^149GR@`T&%91Pa?V!+-`%#M0`Cke>wbNXk3($2P~v1-i8Zs7L`P;RX-i9Uk&U=BujKl$l$q z!k$iVtdDq(Zk@(Z+H6uZLJQ^bzD&Ggs}L%Y4^Z_icX@FAzDa&@&+1BTO3dnq$r{%e zx9{5cCN#$nM+pQYr+u55WRU z;VFT0BGSX#_1dAFoYnAYBX@>s7bx^Dpwg3`uheP>VSNt-xb(;R4@cDnNmz@I{SY-S z1azH~+!1wOn9TL~(XVi!NvB}JHY(VQ1Ac}*gW zS`^hQ%mY!W4|Q_66W)PvBrFvKyn(4jrDM+Mx$+Z&jh^sCa(dJcJ?2gASrlA#KM2qUb-%d!Gi<;DD z3cLeRFHPCM^mi=t^ZS;8?C;Whmr^F$@)~n`YMsig#*QrLd~O$wC1Rk69>tTIEYh7+ zaQ_t}zxgU~!qwy7EjPJ;!)(s=S!*OmxM?_0h4Lp==kI-bzwcfHRvV%g=w8dQu8F9& zQZm^)2QJ&HiXIhtOfI>g{0Up%Ou;punR_^HVUIcz9(z039`%$Y`mF5jMPewZjRCJ+ zr1DM#f1A|YgW*d#0==UwUyJk>WoiA)=HNG=OGNcSZt=oaJ~-8Xm4c2IS+-tspH~!Y z5M8%~nW@@j(-qd-g(ga$r5mjxDc!%|jIPEDHl8spQt3P@Ru$@Yy4BN$e@J=~CUL-K zw2H{bmygdYa*pzK4vo5?tGNUl`Av(|94t0dG={b)OY*aSyzEOp|WGQy7_^ik|ugN5#q)=2%(kM^H$&^;`q|X<~fDSD}Y@h7Lm5JWLb*Q{mlR5 zKA)K2CKsLR=LTXK$wm96OvrxgPqn(^ZL(YuE%1~h2;G9{JTT2uKh${FPou#21c-ij zJ}O?VMJz_`APbQV-(Q-7aRggnNvS$xJE{NCTs~M9yF>e^JI@H}+ptI3sZ@-z)L?pZ zL-yeR24ysW{3Atz&_ia~?AvbE;qb4Wt#9C^?S)d526x&?JbthSZb`%C_0T2!J!JI%<<=nIu^kgeG((U`|z|jBI&=J6s$Auy1EMq(6)8VQ}C@X;4kmvg|geRO3`eg9~i_~aL*4C>g} zw_UD4U5SKyelvn&D3xisJpsZV7Ts!|l{S7Dgt69TGppR;H$6j7bc0UR%Kc7E5-V_$ zRtWQ~i4CASoGLz01Bs$@i)YHwsombu545HmDmwFeC_Ge$d%=%0V^&s*VKhffP}scqYXniLlvihQ;Xkz1n@+ zgEiC*jb8&6EMH35GwZ_AP&4?M^5au5Jg0N2-{&o@a>9lUhpycBe6D8ADhQA|NElg~ zcUk2{ZI(Obk+uZ1AmA(l@68Xdqx6sI8pm7>8ZG(8kvl3|9en8WZE z=o5rtBt((0yt(fYMRR}@BspE7)ppp?^+>Eh_?BV8N{+*$6!N1_4VqJAFd;F+LiE!; z>)ba0^4=1p-fbDdn^r-YCegxCCk(sqOKjH@`b{U)k}FwszA?F!Oi6seNm*Y2K^%57paW zenjs7Id_Nvr47&^q*K|jZu?k~b=?LIyQ0C?3G?D?movhW3v*9l^iVA&%YoXN4E@0J z2{@w{v}1+Q{5lCusb)f{8vSuP4S9q~O}$WwkXX%*tQ(u47&>FoN9o*E>{C)bzxlrSvqT;;FIvMvFGzgQ_!&%Dezk!yN_iz* zCq{c3Z;{H&7R?4TWZEjX-ZPR#F^cTxCz_A%@zMgvyen$hOtS{EHhfNFrY2Q1PFDE2 z+%PW?Zt5mmmzxGYz_`Tt&&U5bP>&G|`p;T@Ns$`?X2xTfS@EeR)mZ80A2S?%4yrd< z*UM_F8Ze1U0_OM{M1Z#X9$9QC+SA5Be}Dd&{GL}L%yws`SWk1-u&aN3m=Ir?oj+=ArH!5>B70I2B5t&adw z!7*Q%7iD}$?cHa>zs?&jwGKmbk|=19m|HBA)k`X`l@i3NGCfft{fz{eyUXf=j+hcF z24aHS_wMr+tKzw^TT9OXrY(G+=U(m@AGSiOYZz=9q@6^Qwzhwtv_bGyvk9tK10C~( zy3quRdy$Vj87;6%7?coJhAVY%Mdo9@cB;J5wl3)~FBWnOg`1Vb%~s>X>{Gdn>K_l< zsk^b}_h5!m%@xjcA8Xjg@OqW2Uo|;_+M|JiuGI^ChN&z(+ze>UW%eH)?p^8TjMx{m z&l$RPFjD*9q3e&J`K0esWa|}vUj2^{DPfP68=8NP6G&+d9G#mGSZe_TvF}XX>C0)b z))3eoN8qE(i*0n?;4RE9pjwgFXF(bRU)5SIGeKK{9}-~5`ndo=Ntcg0J0bdr)h+&Q ztVyWmq7of?;*Q3OG0Gdl|fk&3E4-M zv5%}_=DGd;dj5I-e`a2(_j$ihlrdKK6df-e0N|9qp4LqOknm3= zprwXS+W|lR!Y3+6jq4f!R3y+J-9G{UKWnFV^Ev=Q7XW~s0`RX0v;@E-X#kdO08oAb z0GC&G!wpsV2DPoBt`?yD`{p+nrodNdeD$wu)6CM+F>nj$(Y{>=&bAIb+_~>n010SK1j?T8vaY=&2zTT+gi1&wOhzpsal( zUjSK!_*I~nB&YF9*l9(M7O7NuX``ZMG*aOU_DrLBoy)A?%?Tx8$NC;(L`Kp@GeJki zy@}xd`c?rib^Yvf-*%6t7el`(vB0+dfA_&4gqz9Xdtt<-Q!K;5f`n2Q;(2G@IE@Js z$KsS`|KOL%(X0Z}utD?RuGZkLL6jdIMg!T_Y|SljJ$ajHP!BzrFr(p|Z6J6sJRQ8T zWi-kGl$b#4?);o-^*Cu>m_XNaZvioK({m4$4A7!FRFbv9UbYq>d{cd zmK5@vX{zxE(TF@7ftWFE@gmfwL{5Jw`O@|U%c^iZ8=UT0Ee;;CgZ1N2v-4|38wrst zjhV3_hcjOucpm;%`%-0zkj7PC!Uc#sH;D}1CW#m-lv*j1@3D|PSLvXGo?Yjvs*g(7 zg{=Hz*4-JZ5-5Xov;#-oZsL6XS<{)G?Gqa$A~m-=e3LmG~A+0M(!&$BJ-K}z~}F* zo=WLjN2}j(en%pf1aM3XmhA&;tH8ZCl(|Lq(4d^2Gcyqnluyi@1b^Kg+;k_G>kX+0 z>1W3SWl+PKm@UaAGmwinwJKH z2Y>QHFY)<(LG^BOpM7F`EBg#3frWJ1?*wL{9Ep8TC5#^2H>GTU6lvX$+LH?H=m*p} z+E9(gFEMA4;|_G|#=f>>D2C?j9DzycqhG^~gV&M!k(P)huml3$dn5{zW^r3HUvO@^ zux;ib{C>KhyAiqFXcA3Qz>#N@7T4%8H2FQM)J{F5npZbnkH>U33`;yv5F>^f(Pjtz zuAxcnERFlS-z7w79X$PUNGcF?=9WE^Jl=eT95k1v!9NdWOBRe$33mg4?g4i4XfD zrS3cH^RMKG?!TV#VDrdetuZd*i~Y3_e*fHU-9}!|Imj=3CVh4?f0pn zkw=PA+fpi}%bsfc32Cd6*8wd8fCW1l{ke2>=(j=2P>l70D}=e25%vapHY7~mqd_aR ztPTlS?oQM5fj7Xo^e?_Nf{@$zWuu8g9x@8q{cPA`wghGbskrDqwEddEQe3qr%tyh@ zWekXZ*BV#9?Y?msLsAGK+x6s1+5_n#Z$T9MomSVoH}%(JBWag$ko!SFH@REg2c$~xr=EeC5KZ0s6DWG z!Nia9-9m2r*}HN*M+2?f27zyKngA_`J`dQ-!h#r>|F+4o8m}`#v*f<08fzwf7qO6?jh#D`s-CM@yyxvEwx(a#(}YSCX7RVUkuY9fq+Lol zD=q^(s>*Asay#z*{7G22QXQ~eZ=!k>BKs$NJA)dUHTV&>)u7|XQz9k@Sk)HAzNSX1 zDEzQps}v?55sBAaeI59o$z4x5tf{H>v@jc6N_;Gc!p?<{J$nCVRc*vX;evkh7i-y% zU~}!5*vvxQP--@|_u~B=$Vn7F*vXRAmnnXmK?QjV=$m%GkRXUkG~%j`n6uXEz^(5x^*dOGC5L^u7v7oHdJ38%YWce? zGo>zjP}<5ju)53D+x8B#Nbom50hQlxoP4QuHu?8$1)S4JA>fUxlUoxdgA?L1zfB)h za<~fF-YY|4k~@poxY>F0gWsic_k@C_s@E<@@Jk2qzcRI|$I%~6(sEu808AbVvSq+r zd~10;y&&;rrc~{UE*mCEg9aEovGXzmOcH__7#Q2L^MY;{mV7#TV0rp^%_DgHR1V~$ zKz=s_Kr{mc@&^C}yb4V0H{mmU_TB12WEo0qG%HHz)bF& zZjg_HpWzmeW=6E}AnHmXMj$E!kdUAq7clMw`E3aJ3gA8~smWPB$_0QnwePD0d!K;5gh^9Tl;f419vKw@MC#dgKvcnUBk zzGxU1g;P_(_5doto}qzWaPDXyDpmA-$CpwX8D%2kqR;xdT3FIa*!xSR`6c(e?IiCg!8~1W9-yj zT)caYgs$i&;0oL$3SJLK)sb$V15{A#yKq5Nj5s-AZP|mA_i?4$SBn-7^`gI}rSaCZ zHpcVCX%D>nGLR4}J4IJklI-J0hj=R`_s^Xav#V_hbZ}uP>6$<^PCTy5?|Mg6vD~Y! zw*iZ@4qCjV*RJ7!8L;y%1(MKHpOYvhYl?%ha)KW0NZ1eA_obsLJvoq2AMH6HQy%Qj z2Z!)KH;=-hEe;-E0G-L~y$@StCr@>k?QB$H5`*L=1lUV_%uZ?TcP4$4qf*qz(6p&N z)lk#8aL@T@=i`ASxttb}%LuhIfYQjK(ej(Lmj4Jk)S@FSsRsg|f90CZ&OMac>4nM=f#(2tA=g_CgeL}jG8@wonpVB}N4 z4G-bO#{?-VOv_3!Blz8MTP3d8&-@o?p3{>R(`Q8oIbWsa{-F68JOWVoz00?w#uZ{a zgj7UqEARA=lWMLGeJ8&0o_nB-81UpDD|{}L@yes;nV9!@XA*Z=YOU%z?4XU+3>m`H z@QF5Gu;rhfKc4pO86@M6T(IKwO~FE0T%mR>XMf94O;~L)fB5_fBWex6>kP@KQ0HnU zWT^=xYc}_9BCk0k#{rO*PvlgdRU&M5r(-Eb<}QX(o-RKzE;> z!>iQJ&v3y}HjydjhyJUh%C!cJDZF`6hGSTe!k$psb|--qqoqTL~-S_&Vk&N z5pcZ17*-6(oVIZkCu>5?&<%@RPDB6$bHm*u0d-vx`VT*8-|a@D%bjNNb2GE7Xu-Nr z`Ad_lEbXSbT4W_!kobhq>Jx^iaO6O0w^%Ic5dLmwq9XjCD^i_t(eV}Zuj!E2l!S;7#d6W~ z$oeCjR}vBO8IwP}IGYt}z`exZhlF5w6P(1vo9*#~Qt5;rXWe%@nRvOK%Y1%44Q2rcakG}On(x#QmaQpn>gT}kB@S=YR%1<>wr;wBuy7xkXbIul2MVUt>Zoop*08@ha`W z&U0R0fcY0T-h|R3c3fCD>Ow?Ynx&#jBQnDk{d~@y9dSjzfkXa8`op_N_ncLm#6|Fw zSk%WEA|%PzYwxEu=~h^=;^eK2So7=1l9J^E^>iRQ_DAAM5^gG*Qlf%z?&#$AM(lW){wlZb9^*2urWEBA!u#(bt z;`S$G*}hA5@9g)sJ5;H#pbOYA|MeJhCN;_@2D4gu{%(~m6r!97hvwr9+<09(_86~m zEsT1gCt_V#y@!60BS5XL!6X8DrDXYrfYUjD@N2zTj}S3JWp8O;W@Z^9!X!_>^C`cO zsjo%ErW6ab0yv~Cx%=2dRqk{UaGi(%;_br4@(R9p=e_5{@u$(MK1Dp!Q!4K4jM_v{ zclV2dr0Jp5z`Xdo(1Yd`)7y53vktSnBeD^h-}Tk_fYpiKHf77-NtE|4te0!5(1;nr z+uLS*KdYuYl}Y;5ZmuY3)y7eHP>^Q9_fX2EfXg>u*()>qtgMKRX*mA~h< z@*h@@!W#|oUoB{h{zA;iwm_$6d-TaM?-i8}i>%FJa2?m^$(uyK_f~_4{)jWG!|^8i z{%b?(XP?55$#^D-6915kq9k=@W&1q1osvSs1~ zu2m0>dcQ$${B8|!zA{yPU)1G%ONyJyM68IxF5=}62V*f{T$4me_s4ct6!*7HDw6$h zvKP#cFWzuXGntD&_4!7L@Y~5&BR;oI1wSKQ-Ip)5sDQ!cWTnY#b1^9SEu1!2erjj! z?shpQjtD1L<6SsRPwP2U-dWc@URbHOE8U+W6I+hS^;qZ%!k9sw=Gsd*BJB?{!r9h; zPra3`O6b8cmsDw|iUI@vb>juY!^oMRpZkh#3r?*PAvax%rese9M8K6DE-36? z>nbKjDwG!MqOFE;#6cH0kJbG+H$!~V7wIdl37Kazt-bOE`HpzpO%hIGT1A?V23s?i z_9(8-t8Py=G~LQLZoG^;UN=tyM_V`6^H@|Afw?ASPofa8c#6eto=cZwZboEW$+Gun z{LbB9OYRxwAK&xVS}L7MfD?o2qaq$>ttK;C4B&3E{hc=*k<>~+d*-}2_^}p#Ro_Cv z#CkK&(rv@0uhQjT^4{Ejnc*)@i(v1=w4NN0t-;HT8O)WlQ*y_Gig<#tRSknD1NK&f zkzbdIS7kR&dL6$;fl2;@T8D+Bgp1@wzOP*GCZhtj$BF|+Qdw5gq}ENmNrNs;!Jmyo z0!MCFDbHU@x#x&Jf0Xv<$@ocT=wJAgit^(njefjU(MX>I#iX0e^`E->cAd&i&7w?! zdO3^^o)ej-W+YacZ%=Kz6ssWsFFXttZquxt^oUA@mK4Uo&OIKZwa@tg|Oxqut*s+cKhQdX!U$ z5_JZN;6?dRUk1Um-5UFOUR4E=psK>*@5UWn-P6E~EOYC)+F0-^Rp&i#S;yBTgG=th zH}cj@u{DD6Mvn;HL~OPT=Z3?_9b@r#Fpl&yv!pe?xgZhagBQfG<2XyDZj$b3f_u7_BWq+;<;znJinx_xAa z5a~MsTDih3p3U$1Q(riLPCog<4l)WCt`@4u=IK_K(EG=L`L{w@r??S zWFi#K`|g7GpI<@n+Kc$KSc#xYPb-{HKOL~Vw98O1my$CYtZDd>BGmKe64fLF z3?WSO^5U25|NQwTlNPr^w|yI<)p1Me%Ih(|MLE$OrJ2Wxnbtk@T`GQt?Vib#RSsrX z{#Nvc9!I-`lwzJF5wRWgBEKqTHEW$JQ@+;%)$UKR&2u^wZHWal_MRO$d0+e_R4r^G zQQYxz2p>rIpcY^{RZp}%ru(E>n=;f%Ici%zf803#-ppL$M~kw|Y?4{@C}N4E7k;EX zX~6gGF-?m{@dcKiXMeeX&a(c?e!O59F%iK8B-~H*4>%k8h8rO)2a7I*HY->di~m&4 zDIVK&(;UwC%~uA`yY$qe7M@dKwBCLbdJ?af{d$VoM?x)wl`jf{A<6q zP^#i;Qo$#`Qw`430gavrn{QEm_t&rQ7<4@7DTzTt&mD|2@lO-^*)j|S2@8g&{is+j z|9O}d)}*_$M8w8&E#8yM&%03o;zKJgw)k8iyhH(dUw9;Sgd3D@0xhC+1o_ zj}TENHKY18SJSV*-l>~SZeX*AF1-n>mf1fp087Qgh7Ou-i?v3b&o^?o2n)}{o9EU7 zj_||)pJ()1h2}6yb`^`3-k(-APpEzGYF{}xen-bh1$dP)Z>r}&|Lsj4_XR8)i>G)@ z`-;R#tz|D0Z-2Iprbw*t((|({hX{hRRMH#YL#F7uMyy^$Z>)Rz?d<)707o@n6urbK zMmfD4I8(&24c*Kog=>}7E*{D@?Za}^T55S{u#X69E2k^$lQvp$ zvjHkCe~)~#Jr*b`L0Mfc(dc=4;4y!xh|Oy!ky&~s7yUDyt4n0=dioDSLxuSdaeDEX z2qS-jij@3Zy&XPaq+_AN+`)&OkAj#nFR#@O?f;x|IGQAzz_BK-$JE4bveH1#YB6J9 zh%F}oewmfx&v;a!ayU=G@B015zYm*UM{h|0#cAeErE_OZ_v*sVL>2q-jwe*v9wwOx z>v!l$L?s2Wa{Wkgsu_CWq@A6KeLZ$@Do|!*H_!BxH%~sQ?QA%-XRXGbH?Dr?1y?P5 z*ucZI$?Sz0<~PnAL2{<64QG(*C2Sv-lFa$lX;hu? z*1p;_kU&H6uZ332H*A>pXi8}``Uy8Mr%OvSdzJ&v0lYxNXLb-yhuCQR`l-#TGMxjr zcthRZ+bRQ@Z)~zcm3Yj7zKEqLEqemPTuXNb!(3Slg*2kN7Ej^%g-lO zr-7LxVZktIzD=`f#uw=wfiI%^>>SP3JQtIEGOi(<0-ZB<-mrPK_tv7Gz3a3pcQg}< z^0)dPdHr?uiM*$FhVL%lto5|6-B0*Qa9?qlUfU2XfI*Sywz1bbN>dquR{f2eyQ}8W zP{m*UC-%TK?GC|i4?n4UO}Xw5(6EQK8rI z0>0pE-Z`7POonTRbFXF%nn=k(M!OpcWyM|ZX1}(rj$bd4*zYOPSoU(*qTCbnN@u&ZUm+9dUlZEW~NzsE=pS3L)BhMyy zVF*|Ma9VxAY72z~zZ`D#hW{r}=OFsb;AjnUHQggSPYDakTiupeQ{TBSK&|26&$!03 zWjnko^f+(Kyg&Ru)3Q~gb1fkcuJB9E+O|p9MdQxtT>dQ!6y<;SP55HQG}|h5SPf6> zPwx`pi4?^enn;X@Zq3T*HMT7P+;z;x1w?56>hZm}yf-Z3&%S3RR&6o46R5TiPc?y-p99HJv z>Z|(J+WKOerX}n>Cwgj;P~KB?IOd52C{JJg^Xp1vzhh#cJ&z7H!- zDxHPF!H@p2KH+w2pH^S@*+rwrP8q}~KlrVU*%XuYWN_ru>yzDLMtX5^q8p+}|A?p20^xzmLLn6w)4J-0qR;(GYm zEEU$sdt%Fckvd|e|4L4iW@?U%XtG~m=l-Y^&XtusdzGe9<>@D=UTdd}#V%5`ZXdlg z;sX*N2V}%=(cZlo#bjj}i*1XU%h~s(_LR?dDI|@#-}0WhO}0Mz7+A&WX?pa9$h{s? zYjOh#p7$-EPpw;7?(98{^5JLS%UkWRR#)SQ!1@>7ZS{S}wx_1VaoDL+PpP#=o5u*W zT9EeS(ROtQo9y6HKAYFbmAHLhn4nfv&gcv^x{g0BRfdmqb-C=zKN$lf;pwmn4je9@ zBM0f5UnWq3FHIk@mV_XHY1fqrT%ij2aQ0k&j!uXpPP_&8fn%h!44=wnV%Jys)oeU0 zCvw#P6VAbNw}3GXElRox?2 zQI*t@9K`y0IP%NSUegm@g@dCCQx_*h!r)PG0~lZ9dCKf%`k!W7HmokF#Mc=5oRPms z=6;^55CdjaX;A<%8+Q{Z{j!`#W2$DopUhC0VjbCI z>Dmi3|2@7=!#=z)Mv!`VYUzYRk&NQ(39zUNuSo)KHp@PoWCEqJJa-Z(+~9iiPX@Q)@*gn6WFD|k3t%PO9;DcjHb z6G7g((6;$ZV~Y*>Y-L_DCK~-5-odjdfPA*BfAPtR176@skHx7Ym}WPl-Pb#*g1FZi zR6Apobc2cohUD4~cfJ&$?TKk`b!;JH9CM5IS$Ks_TuKV%=KmuX;>+v#q#VVJiaDt2*=Z1RE;3>-6Wro+*K z;U>w5hAf3iIth$HiQ`qwR3WM+w!i9F=uQ>}j%S@t1u8jElJJNp!-UMcHTZ>ssIjNe zc{D8|@Gq1|V8RdWXhWrnU7FNP2b!>cpoit8_TVY)T#H7ZkT2ROls*Bp*Qr#8rm<~l zm+`oB+SD*V3WB(i4gxHz-x`k{f04C$G@R8R15CP(Yz^7d$B1S-NV%TK3Mrxw%lP2cp5F(2MM{UtcZCR?Z0suWdLg32>whs^9^ZJXD-~O8cyf5fr zNZVVoKkWhgO(;Bd`3=0^L#;l3DW^XCKPI=F_>`fT=|hF`Vtna}s}5O`(V$>K`SC+P zWLS`oka}Y?%=`HEZ!8!`)g6Bgax=Gl^xuCVpL?#23$N#1z_xjeTH9Y}G0Dzdq<;bv z%`SJYO!=8fNS={jkEontblnwuZh9puVD9|zsGLb$A!D`O$alXcuUBlPBTjVhdG&2S ze|2fPf9Jf8)CbjW2^K!!D9mov%xZK*2{ZHAwNC00K8R{KTWDPDjCWdYd_^HDSJbpI9Z?*URsSZL*5VuUnl0g4-zbI(wR zj=7!$aF^4fbJC7z6?Y?U^y6e{OPm2`Yku_0a%~K{1a+nHPIgA;}B=>ME(<% z0jKJVDtfC0pEg+Yg)10+`EH7w8KGMZ*L1};_cejcVU=Kh-=?po_HG9gP_iLG*6e81KnFL5j*2{C zL{*moZ$)U*6cHnJg`WhJt++2KNu46F_wM!vD3iCRR#G;&3Q^1~spdyIT5dl3V5VvH zg-1u1Y{`(>@r-r7x)SeNo%pLmaV|vu@2iyKRBXtMwWmQmyCl%knh3tNbpK+`_=7Cma;vyA3%Aqxn|KLlv|zn{TzxuOEh4^C!kM*|o#pV1IS9BerNi4Avg9@B2X6?%@OY1Z1QyD@aHyN?ew{ zeOX3XMowAwvbeOgva~cu%r3nD@&9_j-P7LLA@KkGfc;Ob@W1BkYh$&_G;JRL9}SsT AsQ>@~ literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/icons/ic_folder_git_blue.svg b/frontend/src/assets/img/icons/ic_folder_git_blue.svg new file mode 100644 index 0000000..f2c0bc3 --- /dev/null +++ b/frontend/src/assets/img/icons/ic_folder_git_blue.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ic_gears.svg b/frontend/src/assets/img/icons/ic_gears.svg new file mode 100644 index 0000000..3e94482 --- /dev/null +++ b/frontend/src/assets/img/icons/ic_gears.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ic_git.png b/frontend/src/assets/img/icons/ic_git.png new file mode 100644 index 0000000000000000000000000000000000000000..fc4e068579f786c9f3c0c8ff0b3eed2b9dd2f1ef GIT binary patch literal 7022 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 IvGMEw1y%79MgRZ+ literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/icons/ic_hard_drive.png b/frontend/src/assets/img/icons/ic_hard_drive.png new file mode 100644 index 0000000000000000000000000000000000000000..d082d9e0a299c0191886567749f6c4b740319810 GIT binary patch literal 26727 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 Lda6~*HbMUbX%xa} literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/icons/ic_klovercloud_logo.png b/frontend/src/assets/img/icons/ic_klovercloud_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8e712bdbbf3ea11288d2336a76fe91d99281e141 GIT binary patch literal 6063 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 Lj!J`)P1OGZvN{J> literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/icons/ic_launch.svg b/frontend/src/assets/img/icons/ic_launch.svg new file mode 100644 index 0000000..f80282b --- /dev/null +++ b/frontend/src/assets/img/icons/ic_launch.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ic_network_storage.png b/frontend/src/assets/img/icons/ic_network_storage.png new file mode 100644 index 0000000000000000000000000000000000000000..47326d883f5d36641a912ed2ce20699bc148d4aa GIT binary patch literal 129739 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 literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/icons/ic_new_app.png b/frontend/src/assets/img/icons/ic_new_app.png new file mode 100644 index 0000000000000000000000000000000000000000..007d43f7923c08dea52ec53af00f24cc0502d95a GIT binary patch literal 5480 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 literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/icons/ic_ram.png b/frontend/src/assets/img/icons/ic_ram.png new file mode 100644 index 0000000000000000000000000000000000000000..d1a13b4c139bdac6d7bdef335c4aadb48ac7d05f GIT binary patch literal 15323 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 HhmijRx847b literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/icons/ic_spring.svg b/frontend/src/assets/img/icons/ic_spring.svg new file mode 100644 index 0000000..5f55eef --- /dev/null +++ b/frontend/src/assets/img/icons/ic_spring.svg @@ -0,0 +1 @@ +Asset 1 \ No newline at end of file diff --git a/frontend/src/assets/img/icons/ic_success.png b/frontend/src/assets/img/icons/ic_success.png new file mode 100644 index 0000000000000000000000000000000000000000..6d09007170daa2ed13999c0ad18940927fc15dd2 GIT binary patch literal 3514 zcmZ`*c|4SB8-9&2C`(D!Op@hb8Y9I>3}Z_sTiJb>%^2GVGg=tyv6URrLFJI7l%-T= z>>^8&k}OdnvM)v1;(On5zVrLOKfd4ZeV_Nf@8`O&`@XN|`QuHr!JF?Ak`V#`V3(x@ z&JO&tpcl>yu1lZOR>98>3f3A60OhH|8(w^%k04msSp&d%We^t&0BaC_0sul$05IhV z0GK}kU|-M;j_q*(fIYD}cmta)J?` z8XwO(Ps)GdP(NIoR88}&3)-#=?fy;cOX7eHkSSm~w=~xUBT!Lr9C8QL6{(u)%Z7RY zgJ4ApG%N%laePTNAQj|NAON_vjo|{IUC@ARBHIVrg=#@C7K;TLHU3~f{!jfOPHvnA zrPD~Y;L08LF_~B$=*|wIzo0`^>d3@8|7`|HmhBNZzJyAG4=61ApY|va28`E0Y(Cu5 zV1&Y71`R?bv_joNn$sv;w(TsgINJvSszjyMQb}NGNLU)E z05^-92gygk69Xyt$Tetq}&+)|3)0hu#bo4+kKr8-FSn_lUAzr!MT{+4;{*q0cDLD{c~ ztaC_Ncy{UWwvF}#vBZ}x*ca(|(bLx^4f8iw9`o_yO@OsVL>rKl4ho|{~JR6?~;(fR96@y(B!NzpT^cEq!734HPvpd%P$ z;d~ANM4F(NCqrFC77`}J(%MvDR9FxWU~WCvkp}>HuO$xaz#OP?T{YQjDwnIGxL~tj z95=<2&tyGQR8>Xrs+KWmH76&vJ%{1+s7FZhg=vRPt{;BSY<0#G9iXU4E ztDSRIeT1;E_pc8JhK=igdR;vLjfy!DQ0b1!SlE9pjP3-LNd%YeWgCRFjpU^N=f~wP|w)Q`j_heYIwvL z@|{(8RL~=;I<9#=zdg8QzMdjAspGpO^%g^3QY}p*T*@E9<-fT6)ofm;!Ia+7)R&+e z&aUjTOeeVEMorjVr^EZla!*@ZI9$JCm7O_rZQfuA^^0}Q!P3>`{A=kW?laPAn^z7L zygq^pywL3Bo#mXk^lQZ9=Aq>rgO<)tL&mKFa>P^oF^XldRA;oD+4&14L|bgX#;=yU z$wT&ptN`QB#^qc2%?}u;z{DcO+y;|7hf74z>n&C9a=5+=eurW^68 zf2NFj=*o9 z&5It~n8+!M!bglMi+$RVR5+ia>53&a`^XHRDaKYdB`X*j_cw{1b+j8SMeKH{ewD6} z=l>zmyyxP5?T zSNH2=!TyX8TII73=;QY?c1U=HoAh9A{m6Qr+7-c+P3O%Rm^~4cs$08ttB60E_oYO3 zB2R2qOR7y$wsc3FV33Z=mU?PT*`uVi%V~bXo}2na<;a#|07)Mb$}0T%d9FGTX=v1e*+#>Y_0$H-li%Oh*=cfb;an~*->YAfHD5(>IS?A)6-qop|R%)8Iv-(gK^%<-||gcXHTBdvEDo5 z5=|)^TagcMutPl+OAKeLMF5qK3c!Jnj#<7bE92=AW@ZqxuzY-udIG&3uvv62neXiU zlec&LQMDZ-uOj0M)Hv-=8miq6N&D>YFs5Tdx;^zQU3UH9e@dgtUwWjcWo1N_vbign zwY4Ws;DY3_%=BQ?j^rDoWy_07E4J;~%Jm~L707s_%YgyiC*)QrYU3Gx3#>vTwgM7A z)*iSjvGQ8}tfXElpG+Ry)(+OobCG{z-w8)?Hk<*!4m)sibWOxfu}!{bj3lRlUC>;M zu9E!$6OahCb)P~@Hlk~ShOMq__=>dhSv$2>-R_dzr?|3Mj6v*Utrt(Docbb%DKHt4 z*2I$6&-5?{p+kuAYW1Fi< z-GHjx)jf{oGfHSpdV9hfU4+V`@`YY_FpS1t=+;9BxHP!f@@)zh%-j|_De$HKl*Y|O zg!*fOsS@U|z#{zzEhB00!%4@~g`Paz$V4~0ojj^i+bupYGTE9G6f|C{+j>PHq$I%GL>$SQ~A`aquPa^)oEoV111Μ~kDl9x8)q3x)s39J4hmk?z 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 bptGZ!%uZv5S!bZbDB!$-xqb!KCF*|wL~-c_ literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/icons/ic_warning.png b/frontend/src/assets/img/icons/ic_warning.png new file mode 100644 index 0000000000000000000000000000000000000000..ed4418984129b8f06e4546e3541b41036a8b0b86 GIT binary patch literal 7255 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 TO6_@wfD>c8*|y9rtbhIs2~VjA literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/icons/ic_wordpress.png b/frontend/src/assets/img/icons/ic_wordpress.png new file mode 100644 index 0000000000000000000000000000000000000000..83d32b1711df9dac39157982d128e0ce01505cde GIT binary patch literal 14099 zcmZvjcQ~8hAFypPV$ayCMNuPmjU?125^7f|8cM5XOSSfhQoFXqh$KpBjiOeSruN=d zs#TjRTBG%*{r=wfuQyk&E6H=+&wW1UoM(K_$$66CmPSBE5F-Tz1<=IU06{@PMgB@f z0iY&-bmJsR6cp4HaB~|&@=uEMbBf336vT6ijt+{v0Se*-MdO@E$tOX=Xa2ka-qI0n z;sj^mG)LJSJMklH$uMih7z<$nh@E1tm|-T&@s=*|;Ks-dSJ@ONZkhu#` z6*oy%aaBx{ZJcE@92K)1xJiz(DfWsf_R4AY@)`Du8Md-XvYf5rpQ@Zp&Ty7Za#T!m z;HLhO)9kpJf8-<^jx3*IBiqP@md|jKnX)O4@+poAa*d`rDrWwXlYixZ$!Ri4j)b$E zZ2PO?C?_-j$nt+oIXR5!zwf`~%-;b1s-`%|75^XkSN_*l{+IbjPO|^o^1njKw!h@R zz5cWPk0kH%@BKgEU%CIu$ua*6?4RvF`9J@EBsoa3jZFS+fxq&anANil0+?fC3B$xX)46^+1mj6rs zm9zg}`Tr&Vlm83#f8^BP-mD;Z=rsF3`Crw4z4>2_{>sVDf6QO<|Ap}n`;Q@q@n0nW zsmSnuax(mH%U|LD05bXSQ2DpxpvqUzzo$SD!V*bANkvUVOGgi2U}RzjvaqtTb8vET z^YHTVg9HSHghfQf#3dx9E?ktBk-a1*uW(sWNm&J~s-~`?sil2IM^{fD0)-hEUNtf{ zF*P%{u(X0(Bak+>*X-;a9G#q9uDjlFbHC}~>2(X`?Q`4L@6KKSdjWw#!6BjdAB2TJ zjCk}oGAcSIHZDFPF$tagBqjA}T6#uiR(8&_+`RmP!lL3547RkayaHE=ClITiSJ%9# zt$X>ZzM-+{b#qJWo3{3j&aSuJ?|ORQlRotI4-5_skBp9uPfSit&&^{a)L!wDLq|9A#p5%i za)Z>iv+nVSqeBih9%r=cr_edv5AfhD5P9ls$K@7v`J`{CO!rSwj>hYU9+mml045vT z-I7L~A|A7OwT8_K0F$CpO0na^!bgEY%PYV#b{;;{#t2WC>~DpyRn~r{qH=c)um9W+ zwOr-@mb089&X!{&dtiS*=fTcF0&5N|x5H3f~KDch<#t+sqiCq>|$>j_kV zA2GjLc_mdur3U?Y6BNyQ8qO7yD7VfEwcXjh(r2`FUw1}^?zE|m0#sbv2)FnpEjz9Y zxZz~yzG>5C%eOH}49Hn{NvW(k-#>MX&BJ`*)Kf9uUUQ{#>jfVxra#wzsM>$EJ2^K%wV+{F=d3NbLp!hX8jq1N;c?^xNx%6*-f-{>K_E6)Rz9r#tc!Jh zK;qO#BKE-CQ&^+k{qNzYDA{uD+vugow}g$GMX=&W@+b4l4}KT$#CV&61!|Y1e{ZLt zVq?c#$4dm~uXi+w%lUgx6SNBtDuWpSl#@rJcLiNpJDLGe}n-tyQ9Hs@fKM znrc-@sxyquv)PMl7cYV&NWm7BdLA_*h+(>pI`#W^GGqRv&9OuL_y{cu3s$sd(V+xzLBUHjp!+= zpR%Ghm7vH9_u;K>XrqdTA9mLx_6K?aT#cKzD#uJaY#}3rB4ehAPnFVCrr(W1N1#SN zq9pJYi+)L~RuCnAd0wV|AgKi)J2*5h`#%1HsD3sm$GED{FIF_bj8XpOt8iv2d*@x3 zdSgT&O-hJ&eJ^jdAHe^p(RCC=@MDu~@fc$qY7S=O0?GN0G4czsbA@SpQ+|sE0YG;0 z72JZX;(&uv?wrZ1a6(50kH2nWf&8o{Y=bba>jC8WA|$3Yq27)dr#0%Kr;WgatDNfn7)m+ z#VbMIc(&=!ih}{Aj8xF|2ylNw58FNm&$wJGCmV%(JI-Y2)6<7oI}VGN3XBi#YFWH2 zlig3+=opdAO#2o#CK}{o@ani+cRCOY+0qq`oE;uL0lXJh%gj3_L zp)et&_=2$yHIvPD>lZGI%#)s1K#3detq4@~_%m@UuCu%g8jh@9$*mE6y7@a339MPs zvo#jw42`_{*Y77>_*Ex9VEg$`k4b&v&2EgW;&eqTDq1~_UTcJ=gf}h^ePz$&LUls~ z$~Kqq&JNt=x7WH~iCP$t&b_!=V@Nni7<`%?^}u~~8EAdL`{PXFm$@^^nT-4X&M z&T}nd1Vg)PNsApSH$2Qc_~L^@#xPAwyw#|*AC!Eao3+W5Qo-&fe3QvnRbxcB&Qj2haov;>kLKQ$er zRE9F|wXL(w@SrII-ws?q){`> z<&EPYy5!(&?27<#U^8!y%)=*FB`0Ir`mj{4S?sLtVD%={;e8f}_ENB0~+YL(ge#eDs-3g@=`*taP zSVHY8EHlFRLdj?ra2(Dt zod2CNJ!E{41>~=1ZU;`MV~)h7nlRr9{EWE;0BSh1c?pqZLC8`HJPf5rAR#?rl^ z$+R`8Y!~`I!l7Oww)9hL1mVGZSaB`3d9kuR&=y-Upw7&|dnYCb^kL$snt5 zF-?zajcP%db>pokR2kfDIrz77x~c9WrW=G=`NyL9W@iq9A?DS$J)`OCG>ElN%<0GeP zhu}V8taGL~>){;~V9*WlnvHt%-S4Y9GCi101|J`4>~&_^ez%HN0^xGdZv&m%qCvKd zur7UjAI?MH1l)y*2|nfTt$ZB$-3WDSWW-vYp-z=3I0cK9dwwW&XdaVO`e6boqU^^H zLfojsO$4@!1|49FJ=0_gNF%kp*PJYLK4MqGeeO-g4=BecR@XYhHfCvnhxl8R9$Lu0 zuFiVO94Cm5s+fAVqoArNVuL24)!+Ygu1Dp11kUc%i<}M3n|(Ue)amzEyz3kJbptU> zlh{*Sk<*-(XJof-ax3+BJ{%4AaS;kFyTu!EST1!mWhW>>M zN3KfNA^7mb9ZA=x&f;j>=ac2ZmDjD91x{B_&GhDf{jQ;YKaA7(#cH(C{0`RI^tjFI zc%kXS6TV;m&*lpzo55lrP44?8x@U}=E@nE_qN)jw?U5xj?O1`2*a2Z7Cyc&xy%2Hh z(z*-B*$wK3fk^lQt&cbG@%rFG$gCR{&3{lM`FuLn(b5Qp(`neM?{eKxZhGcM$Udl1 zdVcE@Ouh-a3iDZK>1Zx&{zz>GEDMcTqL09P@)&&1#IK;3&sM!wLj>dwCEE%Z^rZbW zw1#^1Ki~1;XFPw9(j1&nalI_`beUBG|24!|4wL$YW3Rx}WWevjbB}oo5n?B+X(i&l zFM!J&m+HM&psc-ibwnIM%idZ1Y{-P5NtChLV*~$RjS~FC@IEj z=eCfQ&XD;RY5=IWcVj+?J8^%->2&|W4)1Wre-eB1R$^o);82vAYuSAuA4R4Y@z zl-BmrZJ21C{g?_aQE;83LkvDsIRDar_t8wKa*T4g@5qmdYWTCXt3oMQALihJSVQ3o zr2^65^vrxmh*j$#TdtXq1jdIx7#wfdr->TKPII)fDABiyXpC-Iov5Ql%fjDV+Iz{T zJOCn|BJBK7&AFSHp`%Nx8fFj+)(t+2{sXL1<%+1ykcq_)j8y6ymW^U;ssj8~BuLq; zTe(8T+uY7L!q8#}G?LNx6>isM0(^y)+?P{*NXHa$_2v|WcsW=;Hpk#4-9&X|yn(ij zvyo8S4Qw$OuNB*;h2I3NY3R2DgP$UdBJlTX)xlJ~#|K7bC?FBH;knE}JzkyrJNjn1(2S)&VP;t)Ng0JiW#Jq0Hk z^jHG4jfGRAU+PXQNi%+$L%_n6q+4f3c@c)=r~#01HMY?$ZGK2^f!4D^g@BcM7#;_@ zrvDLeCw@j5WWx<*MLPL-Ci<<2=q9ub6WlZ&&g%nzLL9!hy#$qOjbrRYZL~7yu0giK z{}5!e4ol;QmyzbOUzL*~4gwjMVMI7%il#6SJ51OWHun2gauw#_eer9C__CRVk3DO! znXzy!%!eJ=A^>e8?AqT0{3huMB}c!ko`AEqUoiy2u+Pou&iy6IwZ<@$Y_fSK5xe>* z_45GjtTtod)3?uh$XuWBw-PU?tZq`T#^tz?Ti_)xlHeCt9;m}jpIj!_ROC)Bu&@1F z$L~%K9Pq}H z$AQi?gjq03DmH8+vF$tDF8cj7yP9K`X6sc+8pqMz*NvG)Vm}oJVfaHkUJ{{>ugH%ra1$2C;lb% znU#z2U^%42NFS#Sd_dPX_ro=H3_h6yQbtBYIMgg3@0 z+=-b80%bW+DzlEIjT>UtT>f0Fps*RlEV$nfObqx5wUuhgrzaGkCVr&Jq3w$WKtq1+mRW{{@#0pQrqL&NE$K@vnu-P4U6qF}bFjT|kDa=-UL4E!Fw%V9h*Dk~gV>{sfH#E0c+zM&u_ zfqeiTJ7r4Rn9tti*lp#do9K#*DxH<^C-ItF4G_Fi%G|9O<8&}6kdy0;ncaIVk@+jf zvb9N{P&BcWWi?1B)|cLUVld6&>dhSeuBHK;mW@!Qv)Fw^Nx&rxQ8h4+g-{3fq4a1O z$sJ(alTpr|J%}a_ONUBbS=Vn)hpT2Z7pBC)sX^J-LE>>p?}5NQ0^O@{UScn@26*KG zn%t<9TB}p+h*Q*rC`k^hbn3fTq4MgKn#GmcI!HFqiIQLq_IU~vFY+D< z-t)W?D9vDaD6P&?{Ls9vURs)HrLJrS!?OTe*~Q}!sDaHrPn|#%(C{7$T0Z)sp0%%l zjSe)FPTxm8C7&s;2fS)e^CsEUjb#`zd70}}xL6YD%VINFs{IM(Lz7}^7HNDDG(ofI zGFX@corI!`qUb%Pe~Q~|mpj=(@fU#MRN}Nq)Bx)KPw7A{3fmWm8tH}B_y8S@v_j^c zl&A?y&>@ot&seU=(#I>S2to7-qDF0D)3~_+v*yzhszC)E9Z9jIpIn#4FieyyJBo{EwNS+OoAkVgRI zv_hN-H6XBu;|&ZKLVuP~=hzu6oq^yT4OugoU?@dkIJ0=@c<%1lXFG02P8uCJmf4UtXW9*dcnGI7 z(-lu*wZFr`&)i+#w&`$%Q=)6ijfT){Vd(h5Sdt4EM}I}YAk+skDvjQb4ZkHl#e|+4 zdxd2q8h2+TLrXhpLCP$}5s=WG*wRN_+H_6gGSk9n;j&w;q76y$I#lV+;4c#QZ8VC= z6N9DUGC6KB+7;5FI$SB0yg)HE#Nlk z0l+0or#?g2C?ss01sdT!6Zbalb!NOX9V=+OjT&x~7|_&Nw8N!MZ`c?V_KF7TDFlA5 zF6llzo_Kq?>r&8VZsM5q6!*>*NL>UxOaH|fr|1DK@RUbEOs4-WzMgB)(T0ONDzT(h) z;mGjrbrWjolW2F?(vUHFFrn0G9i|G1AP?8MW8e9LMwoVfn_D?TMwQWR6rsHcUp1~^ zEbC<$ULa+YC28Kfv)jLlN2f&qy^8deT*x!8oRWjWXx+O1H)?cBRH^mB*N0a;(B)&8EGS!&F3hibX~-Zn>{G3Kv8#mfzKbt|@@VDBYXj z<6*By(-+O-OCelNz);HqawlDi59 zubzDnZ%%F}EnX)1^ow{mu7LTgyTY-hKmT_8lZu&B_(YPan*N#}c{r7ivxaGZLB!}T z&>H@bQRCQoQaJztfCmoIZ;mQ3t(zrPutyN64E5k! zCa-^J^c=ygO=MeGl-1#8w^6O>?rrJ)n+FvDE+MSF-s|xc_itEI4n%cajPqU=$kIs6 ztP7o%s9{OiAjv4F>y|@pwR&1QiyE_%qe{DN0@ZkwGYM{V&Ou?q;z;QruI2@(D+|=x zt?wgMCVlZnf=)H&icG9^G2i=ySOj(qYv z6kYTLnp5iSOOupXmbIQ*`1$h4GsC}Em}hT`5LvhB43T*0SIi#0NM9}IE5?>lq|Gcs zVxiV(B?EjSBfxOUGB(qF8@nb$3=>oa%1luy=!#kO=zk7FZ$T79Ml0WA*RG>IJKM&& zHi3qr){|RbUjgkoQI2JiqqT*=$MA%3K zYC4uo5cx^olHB!?rSsC$JUglw zXDex0v*6oefwZ(WG0A>sc1UAzDUpTLbtJ%@6uHksC3nqX{nH(WK9++7fk9^FXdQ~Vuik9fo^&1=5ib8`Cf?mqFDL$eJ+ zdkN#C)MMG5S;TcpNi42xaY-YXdZsLWzU9>{z%h*&)c?X39L;z=n)s3Hl&4s((mo8# z)qvB7kscZu()*DR1qwN^w;_?HKH>>Zgi?8~9&PDHwqkRfv%IvdMU=XzN+PwbZZ3bw%-UqO4JYi_fDQf_83LEx^;~r5l5XSO83Uwq4QM-{ zwxNB8aTi0a?|^Lv%k{NMzPOA}zNE3VS>HI)U7Ha)%^)25C&q{B>z$a3htf?PL_CA-MQJ-W;i3v>2E3MeRD0U2KJDpJDSw~_D&gIulLP61H5m7MU${+b z!29J{x<1ty;!l}cTIHvRF6q~~eT8>o-(5N&Fb2%%a|dFHQeSlwZXspVDTq5|2EmD0 zfg?>VB#sBsnr+lcRqOqCzQB`A!yuF6Sp^isC-6IzHre+OHzYl##wvCEN6C5SWs0P> z12^%2`|+kk{Yj&&O_t%BvIT4D(^M+@ZMFxwx^2w7yNXTWVoGS;dMJw?qDL72vWR@j z-@ldxQivlylNl8huTWk$^Ycj3>|VGADOG4QLmP%P;612pY%2>@gs%&hJKN!Xph*sC z$4_*(qLUkgBwoo$KB}-YOYcU>dQ;l!$TZO}%2h7d;L*nAopJXQ56W33mOfLr{GgG% zI#wl28VZS&9WsJVn)k`as!PZ;QTHvD8rUV0hex4y;${yyKF-o5X&v-B@XV@KWW>Q6 z69T%IEH3tGCPQs+n?8>pFbzB8bPg&HZxF33xbAzE1xYAZvB}28AMN2TkS}P&+(0h> ztOOGEfe)Xv94`E(=y#5``#iITCFSUexA5SLsy1=z*6Uf}?0u_ncQykwZnWT1T7|Lf zM{PmMsH!zXA&=>J(;UdGeV^3)@}ydyU;N8?neP%FIitxU%by>G1*k}djF!PjZVK5! zaW93k=9zbKh#?0?VyP9PRMa+?va44^tARvH=Qlsj07dzQJR!5yV4GXO4xp zZEZFp?N^?#WRG}jw#^t_9}faX`^*1Hz{M@N=e${x8abJM8sFK&d$6Tq%v?!tmhM6@ zCz5Zzw$`^~LMhti%H!$aM{-iDFiG8{VjIJpmn>nc(yUSW2N?R7n`Tm+*yl2;15uZ) z;N5}n5bF!HLj(w4WTgd6fKNN0#ZS~SY~;X8)eYuG zV=9;3CEAYJIl9-TygYvD$sU6?+AHI=_N27p{tlF<@;L-VIYNtfT+njd>n<(;XGl}A zVF(QW1tNXP4ERlAY20pNPc&=xahU;k;sDOcY1v)0O@K8?WZhE8<0q$Wp$vs5E3(_? zml_&$4f0XnlsUmzphcBUp}j2hy|~!km5&;+TRzASx8Y4Wp!lvPwTZNJ3eTPl>Dpns zq&1bGN{*M#S6v-p7_E=F(ObRnxL2}S*}-ra)30l9O@KPsonTXN97#K9Md0=Q)b@e6 zcPy(@pxGH#>mFtNrV%hN4ts-%JiQZaTf}vrNxXWkm(#y4v%Q=vs`J%=lnl=-xGcj9 z-c$^lg7g4YCX%+|G#5Lw%YJ8c3jX@zUUX{(>Eb6IP0B7JjD{uIE z!4D1qvnR{YOA=1r_6)=jT!3HB1)8o}$CQz$fH3-A{Kf`?w^)YuNr)2Jc>N{i)mr}9 z!7_9)+%8>fF^)WZUy%Vkghjm<+oub(XXU*~_{?kUdoyHMtNhin^9oD^$*8#P8t^v1JnVmvJGVBn2-B7!{i0^3==_=>j7mJ$-lG$-yX+ zeTzLc?_H#=qY~g@znodRg{SO{S3>9IiSNP_!I+%eqI(@SvStd*NpwNq*HfL+itA-Pw&jrRm&o~wT(a*Y++7jK zXO|5PPULrtQf z9WClBWhbZsGp~& zN6HCF*U?jPAHUG@_dGAs6_RI+imoKA1c41!;bwP@owH4BTg8;4&wtS<@F2?BY1)@R zv4|B2tUK`Ury<+Q!=ZZobcckHjuS_U?n$1j(aydxESb_5cNb}> zk2c@Z^l292pk+l&awTqkaaBf3nDO=%qN7^Oel<<`a|gz^m)j-0`#2Gx%n04J?zdxW zjv-o-^E}Nzo>I!>I2Xw+$>Kd4yS*kjTzRWh4 zkCuxdEGy$L?Mjx!RFN;B&#nuITi|c$1Rdatv(uWpAgYsM-?^H(6sC~f0D!OPW~c4r zlRdD<6k?cq#QGQ2Avk(Kn#j+Pg!Z`Q(L7@UJoSVBBOQ4$o4JD9429 zCYVp~$ZC=^2wWDFv@h8Jj%!ISL@p6!+q8ojJk$`wTx-oa`S}oBpM$J7OVXd@W%o-B zZ)l@}tCu$(goSE*+`-~nMh+wnpC`bzW%Fp0_CqDixHmKf=z~AHFZ=Mef#~_?c{YxD zT27EiZ9tnTH}7XLH=`WvM3DN#?DB?B*r5fO{3i}lWKA~RREK;I`K9?@hVbeE77V;@dx$RI6jMB4i?3L0Y{dk?A9&#l_q5v|^{% zd`>>l!A=mC58jAv4^-8OOgAmuirJ#lCz_b$J3thL@f&BroE3q~xA5q=VF zfA(l2pK8SiF>jW3I}@@i98I2Vt!G3$9gkU06EJcaA}V&7ZuH@4n=M(w8rY%Ml_5W-;BYEJ^(jdtg5JT`|AGoL5P~l7o{HeLtqboq3$r*j^$TkZLhrYAUKS%9ZX9@0yF zt+u+ny~z#NuS|HsTc0&=%BtM2Z(9e>UwMQ_YrhxFnAh*WIq~c|11{er!ekOF^+-nN zz96w>RI&tOOTX&>#Ro+wGL1mG)tC|{eww+V>Z~x~^Oy}}{yS?*G>=NFA2+7rm+pp{ z0&8YUDP^+n$hdaVoyq8YL>{#HjZkUx6r-T6b&30nqU@<#at#qK9;g0Nuk1%I%A%_%|lBJEbbNUS6J80o$6g{{ly!=Q>l& zwTz^R)tYv7gT*Vv4y5F6s12F!d20_&3hDmt>o|L)a-eEa#(sL!Ew2VF`5nPGatLn9#jMh7`>_@ajlroD- z=-KcX%e7YQo!ZtopAuf2IU0YMxoi>T@T@cUJNQByo!n1GAc!#r-Jaj8Cm*LiJw|o0 zbSX}VE(HVWc59>R7{mNgB#xb0W~@ss_ZT>0<>kPMbicW%^-z{&VV$)tC7E0F!&?d7 zakRBV669qvG>^Ws00S17R`Mf0$nQPpmruXOeCp@p9f{L+XoN;a=!WjREwx?ch@44PaSO+_wT!Erh0hbO zjP;V&UD3bgP_jsP6p(tg$mQ641!ceDkl!^*^}vh9LP>&$r*3-ds8?NPBD2NQvW=6pTZrV$>iU&^Z4 zKJ|6wFN04z^zu!fX8e4ldh4LOns~J`|;QCC9rEMAra_ESEKj7tioe_OIZVeQ<4kd%+UeXT|4XtlO=PSNxc_Aa;DM*zsGJ@*OdlT*?WH-#A+~d5 zkpI_RoP$qoEwa5>=;lyh+j2{P^J=-@$m-@ zs!&jRf-LGA)S&R++u%`2njDf9s`QEVJ%G~p6(R8GO8`yo+j(!?$3ZrP<4$E>W3R-L zjfOt5&6ZhAVp%8O=dJ?{M%D;LEGzN@FdW@U0#9O10miD9W6lL2Q5x{9X`oOmGbM4+ zA;154#}E+kY@p(Up(1?3jbCg1NdJQq7los^|^t+%f6;n_ObrTzvjgARFqpYB`5ItHWKup+_&S<((w+0CVG0@((&?- zAJ;3ELp?>VZ(@{UWIG^k;m&o_UpgF+8H zPUe#;sGYK+y!#p+o|GXEn(n0oxLq>y=u;o7{pkw3rzqL}=x35^;SJ%}BkW>dh;0KB zsjfWjb3dm*-`QmCUs-hAOAgh}H6kCq#xj4Deq8&k9%yvf`g1jmo2e`LZT3dPo2E}| z4+^Xl@5;+Wv)vR~^|)cIeb&v}zdBs3SWY2Z0IZ&Q9liCE++d&`UG+clD^(sc;!uj*z&jHI>5Nw z-PTmd-N9iiF$SM!HpmYI*i?mDsw@>1E{b!w@g%hePdU)lj;lBtiVYx?nuc}XM+SvV zRgaP%F__W*R_GO}d3?QqFZS5NV};$RkeMy@MS|)R{oIc14Q1{02Rk#*Eg1m)5=SS) zcY+j$J!%A;r{ini*w%mD8_rw{{bt8{+nUcUO6=ugnTT-dC&Anw#@m2c+FUa&i^Y6s zveey2)i-HlX^DybyP)>_FEV-jcN{dHN7!n=rE=}M9rmX2LOM?K&vER|;R-vCGo$M) z?$c|-PbJvK@lOg58+QFv8O7ytxvL|L&eO+vBN~3#({XzUo__C-8^8YOxnH$7`B{&~ z(rkf+v4&5Xu + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-application-c-sharp.svg b/frontend/src/assets/img/icons/ico-application-c-sharp.svg new file mode 100644 index 0000000..72e58ec --- /dev/null +++ b/frontend/src/assets/img/icons/ico-application-c-sharp.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-application-csharp.svg b/frontend/src/assets/img/icons/ico-application-csharp.svg new file mode 100644 index 0000000..7615f4f --- /dev/null +++ b/frontend/src/assets/img/icons/ico-application-csharp.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-application-golang.svg b/frontend/src/assets/img/icons/ico-application-golang.svg new file mode 100644 index 0000000..0b88103 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-application-golang.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-application-instances.svg b/frontend/src/assets/img/icons/ico-application-instances.svg new file mode 100644 index 0000000..a13cc00 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-application-instances.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-application-java.svg b/frontend/src/assets/img/icons/ico-application-java.svg new file mode 100644 index 0000000..3ceb808 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-application-java.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-application-javascript.svg b/frontend/src/assets/img/icons/ico-application-javascript.svg new file mode 100644 index 0000000..3e8d287 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-application-javascript.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/img/icons/ico-application-list.svg b/frontend/src/assets/img/icons/ico-application-list.svg new file mode 100644 index 0000000..909e87a --- /dev/null +++ b/frontend/src/assets/img/icons/ico-application-list.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/img/icons/ico-application-others.svg b/frontend/src/assets/img/icons/ico-application-others.svg new file mode 100644 index 0000000..78fd2e2 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-application-others.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-application-php.svg b/frontend/src/assets/img/icons/ico-application-php.svg new file mode 100644 index 0000000..4e931d7 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-application-php.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/ico-application-python.svg b/frontend/src/assets/img/icons/ico-application-python.svg new file mode 100644 index 0000000..78523e1 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-application-python.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-application-status.svg b/frontend/src/assets/img/icons/ico-application-status.svg new file mode 100644 index 0000000..b27cc4f --- /dev/null +++ b/frontend/src/assets/img/icons/ico-application-status.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/img/icons/ico-application-team.svg b/frontend/src/assets/img/icons/ico-application-team.svg new file mode 100644 index 0000000..cf33665 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-application-team.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/ico-application.svg b/frontend/src/assets/img/icons/ico-application.svg new file mode 100644 index 0000000..d385b1d --- /dev/null +++ b/frontend/src/assets/img/icons/ico-application.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-auto-scaling.svg b/frontend/src/assets/img/icons/ico-auto-scaling.svg new file mode 100644 index 0000000..7612174 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-auto-scaling.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-bin.svg b/frontend/src/assets/img/icons/ico-bin.svg new file mode 100644 index 0000000..f99ee4a --- /dev/null +++ b/frontend/src/assets/img/icons/ico-bin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/ico-build.svg b/frontend/src/assets/img/icons/ico-build.svg new file mode 100644 index 0000000..70444c2 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-build.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-canary-deplyment.svg b/frontend/src/assets/img/icons/ico-canary-deplyment.svg new file mode 100644 index 0000000..c1f3600 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-canary-deplyment.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-chalander-dark.svg b/frontend/src/assets/img/icons/ico-chalander-dark.svg new file mode 100644 index 0000000..412f72e --- /dev/null +++ b/frontend/src/assets/img/icons/ico-chalander-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/img/icons/ico-chalander.svg b/frontend/src/assets/img/icons/ico-chalander.svg new file mode 100644 index 0000000..eb16604 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-chalander.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/img/icons/ico-cicd-redeploy.svg b/frontend/src/assets/img/icons/ico-cicd-redeploy.svg new file mode 100644 index 0000000..8304989 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-cicd-redeploy.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-cicd-restart.svg b/frontend/src/assets/img/icons/ico-cicd-restart.svg new file mode 100644 index 0000000..6b58df1 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-cicd-restart.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/img/icons/ico-cicd-sucessfully.svg b/frontend/src/assets/img/icons/ico-cicd-sucessfully.svg new file mode 100644 index 0000000..deb3c26 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-cicd-sucessfully.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-cicd-unSucessfull.svg b/frontend/src/assets/img/icons/ico-cicd-unSucessfull.svg new file mode 100644 index 0000000..9515746 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-cicd-unSucessfull.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-clock-custom.svg b/frontend/src/assets/img/icons/ico-clock-custom.svg new file mode 100644 index 0000000..ce6826a --- /dev/null +++ b/frontend/src/assets/img/icons/ico-clock-custom.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/img/icons/ico-cpu-custom.svg b/frontend/src/assets/img/icons/ico-cpu-custom.svg new file mode 100644 index 0000000..040e65a --- /dev/null +++ b/frontend/src/assets/img/icons/ico-cpu-custom.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/img/icons/ico-cpu-threshold.svg b/frontend/src/assets/img/icons/ico-cpu-threshold.svg new file mode 100644 index 0000000..7ef5101 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-cpu-threshold.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-cr.svg b/frontend/src/assets/img/icons/ico-cr.svg new file mode 100644 index 0000000..97aaeff --- /dev/null +++ b/frontend/src/assets/img/icons/ico-cr.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/ico-custom-basic-auth.svg b/frontend/src/assets/img/icons/ico-custom-basic-auth.svg new file mode 100644 index 0000000..6e8a146 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-custom-basic-auth.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-custom-external-url.svg b/frontend/src/assets/img/icons/ico-custom-external-url.svg new file mode 100644 index 0000000..0d563fb --- /dev/null +++ b/frontend/src/assets/img/icons/ico-custom-external-url.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/img/icons/ico-database-type.svg b/frontend/src/assets/img/icons/ico-database-type.svg new file mode 100644 index 0000000..d9e91ac --- /dev/null +++ b/frontend/src/assets/img/icons/ico-database-type.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-docker.svg b/frontend/src/assets/img/icons/ico-docker.svg new file mode 100644 index 0000000..f2b752d --- /dev/null +++ b/frontend/src/assets/img/icons/ico-docker.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-easy-to-use.svg b/frontend/src/assets/img/icons/ico-easy-to-use.svg new file mode 100644 index 0000000..f22a73a --- /dev/null +++ b/frontend/src/assets/img/icons/ico-easy-to-use.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-enable-external-url.svg b/frontend/src/assets/img/icons/ico-enable-external-url.svg new file mode 100644 index 0000000..5b7c1c0 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-enable-external-url.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/img/icons/ico-env-dev.svg b/frontend/src/assets/img/icons/ico-env-dev.svg new file mode 100644 index 0000000..f6e9399 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-env-dev.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-env-pre-prod.svg b/frontend/src/assets/img/icons/ico-env-pre-prod.svg new file mode 100644 index 0000000..ecaa2a7 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-env-pre-prod.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/ico-env-prod.svg b/frontend/src/assets/img/icons/ico-env-prod.svg new file mode 100644 index 0000000..cb7c4f6 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-env-prod.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-env-qa.svg b/frontend/src/assets/img/icons/ico-env-qa.svg new file mode 100644 index 0000000..f8287b7 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-env-qa.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-env-staging.svg b/frontend/src/assets/img/icons/ico-env-staging.svg new file mode 100644 index 0000000..97f8b61 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-env-staging.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/img/icons/ico-env-test.svg b/frontend/src/assets/img/icons/ico-env-test.svg new file mode 100644 index 0000000..74e3653 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-env-test.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-excution.svg b/frontend/src/assets/img/icons/ico-excution.svg new file mode 100644 index 0000000..2628180 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-excution.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-filebrowser.svg b/frontend/src/assets/img/icons/ico-filebrowser.svg new file mode 100644 index 0000000..d3d2710 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-filebrowser.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/ico-git-commit-id.svg b/frontend/src/assets/img/icons/ico-git-commit-id.svg new file mode 100644 index 0000000..bad936b --- /dev/null +++ b/frontend/src/assets/img/icons/ico-git-commit-id.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/ico-git.svg b/frontend/src/assets/img/icons/ico-git.svg new file mode 100644 index 0000000..5814577 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-git.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/ico-instances.svg b/frontend/src/assets/img/icons/ico-instances.svg new file mode 100644 index 0000000..350083c --- /dev/null +++ b/frontend/src/assets/img/icons/ico-instances.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/ico-intro-app-on-boarding.svg b/frontend/src/assets/img/icons/ico-intro-app-on-boarding.svg new file mode 100644 index 0000000..11f6cc0 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-intro-app-on-boarding.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-intro-cicd.svg b/frontend/src/assets/img/icons/ico-intro-cicd.svg new file mode 100644 index 0000000..0a50855 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-intro-cicd.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/ico-intro-easy-monitoring.svg b/frontend/src/assets/img/icons/ico-intro-easy-monitoring.svg new file mode 100644 index 0000000..0ba6223 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-intro-easy-monitoring.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/ico-intro-log-aggregation.svg b/frontend/src/assets/img/icons/ico-intro-log-aggregation.svg new file mode 100644 index 0000000..5ad2edd --- /dev/null +++ b/frontend/src/assets/img/icons/ico-intro-log-aggregation.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/ico-intro-multiple-env.svg b/frontend/src/assets/img/icons/ico-intro-multiple-env.svg new file mode 100644 index 0000000..fafd0e3 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-intro-multiple-env.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/ico-language-custom.svg b/frontend/src/assets/img/icons/ico-language-custom.svg new file mode 100644 index 0000000..55bfa55 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-language-custom.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-lock-custom.svg b/frontend/src/assets/img/icons/ico-lock-custom.svg new file mode 100644 index 0000000..2970609 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-lock-custom.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/ico-logo-icon.svg b/frontend/src/assets/img/icons/ico-logo-icon.svg new file mode 100644 index 0000000..d21d411 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-logo-icon.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/src/assets/img/icons/ico-max-utilization.svg b/frontend/src/assets/img/icons/ico-max-utilization.svg new file mode 100644 index 0000000..cafaf3a --- /dev/null +++ b/frontend/src/assets/img/icons/ico-max-utilization.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-memory-custom.svg b/frontend/src/assets/img/icons/ico-memory-custom.svg new file mode 100644 index 0000000..17a9f76 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-memory-custom.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-micro-service-platform.svg b/frontend/src/assets/img/icons/ico-micro-service-platform.svg new file mode 100644 index 0000000..7827f76 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-micro-service-platform.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/img/icons/ico-name-custom.svg b/frontend/src/assets/img/icons/ico-name-custom.svg new file mode 100644 index 0000000..0845875 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-name-custom.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-phpmyadmin-m.svg b/frontend/src/assets/img/icons/ico-phpmyadmin-m.svg new file mode 100644 index 0000000..da3ae35 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-phpmyadmin-m.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-port.svg b/frontend/src/assets/img/icons/ico-port.svg new file mode 100644 index 0000000..98eb03f --- /dev/null +++ b/frontend/src/assets/img/icons/ico-port.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-presistent-volume.svg b/frontend/src/assets/img/icons/ico-presistent-volume.svg new file mode 100644 index 0000000..9d66592 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-presistent-volume.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/img/icons/ico-s3-compatiable.svg b/frontend/src/assets/img/icons/ico-s3-compatiable.svg new file mode 100644 index 0000000..5a5e9ce --- /dev/null +++ b/frontend/src/assets/img/icons/ico-s3-compatiable.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/ico-search-custom.svg b/frontend/src/assets/img/icons/ico-search-custom.svg new file mode 100644 index 0000000..1a2e8dd --- /dev/null +++ b/frontend/src/assets/img/icons/ico-search-custom.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/img/icons/ico-spend-less.svg b/frontend/src/assets/img/icons/ico-spend-less.svg new file mode 100644 index 0000000..4da583e --- /dev/null +++ b/frontend/src/assets/img/icons/ico-spend-less.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-spring-boot.svg b/frontend/src/assets/img/icons/ico-spring-boot.svg new file mode 100644 index 0000000..9a58213 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-spring-boot.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/img/icons/ico-sso.svg b/frontend/src/assets/img/icons/ico-sso.svg new file mode 100644 index 0000000..1daaedb --- /dev/null +++ b/frontend/src/assets/img/icons/ico-sso.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/img/icons/ico-storage-custom.svg b/frontend/src/assets/img/icons/ico-storage-custom.svg new file mode 100644 index 0000000..2536077 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-storage-custom.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-theme-preference.svg b/frontend/src/assets/img/icons/ico-theme-preference.svg new file mode 100644 index 0000000..6f878be --- /dev/null +++ b/frontend/src/assets/img/icons/ico-theme-preference.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-tps-threshold.svg b/frontend/src/assets/img/icons/ico-tps-threshold.svg new file mode 100644 index 0000000..73f78eb --- /dev/null +++ b/frontend/src/assets/img/icons/ico-tps-threshold.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/ico-user-custom.svg b/frontend/src/assets/img/icons/ico-user-custom.svg new file mode 100644 index 0000000..0cc3927 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-user-custom.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/ico-version-custom.svg b/frontend/src/assets/img/icons/ico-version-custom.svg new file mode 100644 index 0000000..357fd04 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-version-custom.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/ico-volume-mount-path.svg b/frontend/src/assets/img/icons/ico-volume-mount-path.svg new file mode 100644 index 0000000..304ca64 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-volume-mount-path.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/ico-vpc-custom.svg b/frontend/src/assets/img/icons/ico-vpc-custom.svg new file mode 100644 index 0000000..e70bf54 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-vpc-custom.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-vpc-list.svg b/frontend/src/assets/img/icons/ico-vpc-list.svg new file mode 100644 index 0000000..48363ee --- /dev/null +++ b/frontend/src/assets/img/icons/ico-vpc-list.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-vpc-outline.svg b/frontend/src/assets/img/icons/ico-vpc-outline.svg new file mode 100644 index 0000000..a15df90 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-vpc-outline.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/img/icons/ico-wp-application.svg b/frontend/src/assets/img/icons/ico-wp-application.svg new file mode 100644 index 0000000..e5bd78f --- /dev/null +++ b/frontend/src/assets/img/icons/ico-wp-application.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/img/icons/ico-zero-trust.svg b/frontend/src/assets/img/icons/ico-zero-trust.svg new file mode 100644 index 0000000..fdf4772 --- /dev/null +++ b/frontend/src/assets/img/icons/ico-zero-trust.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/img/icons/live-icon.svg b/frontend/src/assets/img/icons/live-icon.svg new file mode 100644 index 0000000..8b95b86 --- /dev/null +++ b/frontend/src/assets/img/icons/live-icon.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/manage-backups-icon.svg b/frontend/src/assets/img/icons/manage-backups-icon.svg new file mode 100644 index 0000000..d6da49f --- /dev/null +++ b/frontend/src/assets/img/icons/manage-backups-icon.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/multi-cluster.svg b/frontend/src/assets/img/icons/multi-cluster.svg new file mode 100644 index 0000000..591feee --- /dev/null +++ b/frontend/src/assets/img/icons/multi-cluster.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/img/icons/on-demand-icon.svg b/frontend/src/assets/img/icons/on-demand-icon.svg new file mode 100644 index 0000000..b1e0fc5 --- /dev/null +++ b/frontend/src/assets/img/icons/on-demand-icon.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/org-cog.svg b/frontend/src/assets/img/icons/org-cog.svg new file mode 100644 index 0000000..5431b7c --- /dev/null +++ b/frontend/src/assets/img/icons/org-cog.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/img/icons/pending.svg b/frontend/src/assets/img/icons/pending.svg new file mode 100644 index 0000000..6c4d0b7 --- /dev/null +++ b/frontend/src/assets/img/icons/pending.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/play-button.svg b/frontend/src/assets/img/icons/play-button.svg new file mode 100644 index 0000000..7f4d58e --- /dev/null +++ b/frontend/src/assets/img/icons/play-button.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/img/icons/records.svg b/frontend/src/assets/img/icons/records.svg new file mode 100644 index 0000000..666aa32 --- /dev/null +++ b/frontend/src/assets/img/icons/records.svg @@ -0,0 +1,2 @@ + + diff --git a/frontend/src/assets/img/icons/region-custom.svg b/frontend/src/assets/img/icons/region-custom.svg new file mode 100644 index 0000000..66ca0e8 --- /dev/null +++ b/frontend/src/assets/img/icons/region-custom.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/img/icons/resources-icon.svg b/frontend/src/assets/img/icons/resources-icon.svg new file mode 100644 index 0000000..875f718 --- /dev/null +++ b/frontend/src/assets/img/icons/resources-icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/rotate-arrow.svg b/frontend/src/assets/img/icons/rotate-arrow.svg new file mode 100644 index 0000000..41b3d31 --- /dev/null +++ b/frontend/src/assets/img/icons/rotate-arrow.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/running.svg b/frontend/src/assets/img/icons/running.svg new file mode 100644 index 0000000..5d94828 --- /dev/null +++ b/frontend/src/assets/img/icons/running.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/search-icon.svg b/frontend/src/assets/img/icons/search-icon.svg new file mode 100644 index 0000000..e9c7b6d --- /dev/null +++ b/frontend/src/assets/img/icons/search-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/img/icons/snapshot-custom.svg b/frontend/src/assets/img/icons/snapshot-custom.svg new file mode 100644 index 0000000..1ff2564 --- /dev/null +++ b/frontend/src/assets/img/icons/snapshot-custom.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/snapshot-setting-custom.svg b/frontend/src/assets/img/icons/snapshot-setting-custom.svg new file mode 100644 index 0000000..70e5263 --- /dev/null +++ b/frontend/src/assets/img/icons/snapshot-setting-custom.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/snapshot-setting-dark-custom.svg b/frontend/src/assets/img/icons/snapshot-setting-dark-custom.svg new file mode 100644 index 0000000..3a90af2 --- /dev/null +++ b/frontend/src/assets/img/icons/snapshot-setting-dark-custom.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/succeeded.svg b/frontend/src/assets/img/icons/succeeded.svg new file mode 100644 index 0000000..5706b0e --- /dev/null +++ b/frontend/src/assets/img/icons/succeeded.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/img/icons/team-custom.svg b/frontend/src/assets/img/icons/team-custom.svg new file mode 100644 index 0000000..e55a3b0 --- /dev/null +++ b/frontend/src/assets/img/icons/team-custom.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/img/icons/team-name-custom.svg b/frontend/src/assets/img/icons/team-name-custom.svg new file mode 100644 index 0000000..8795aca --- /dev/null +++ b/frontend/src/assets/img/icons/team-name-custom.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/type-pdf.svg b/frontend/src/assets/img/icons/type-pdf.svg new file mode 100644 index 0000000..aec7ee9 --- /dev/null +++ b/frontend/src/assets/img/icons/type-pdf.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/img/icons/update-successor.svg b/frontend/src/assets/img/icons/update-successor.svg new file mode 100644 index 0000000..753180a --- /dev/null +++ b/frontend/src/assets/img/icons/update-successor.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/img/icons/upgrade-vpc-custom.svg b/frontend/src/assets/img/icons/upgrade-vpc-custom.svg new file mode 100644 index 0000000..cc8198f --- /dev/null +++ b/frontend/src/assets/img/icons/upgrade-vpc-custom.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/img/icons/v2_1.svg b/frontend/src/assets/img/icons/v2_1.svg new file mode 100644 index 0000000..268b0df --- /dev/null +++ b/frontend/src/assets/img/icons/v2_1.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/webclint-setting-custom.svg b/frontend/src/assets/img/icons/webclint-setting-custom.svg new file mode 100644 index 0000000..bcfd772 --- /dev/null +++ b/frontend/src/assets/img/icons/webclint-setting-custom.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/icons/webhooks.svg b/frontend/src/assets/img/icons/webhooks.svg new file mode 100644 index 0000000..8a08ae9 --- /dev/null +++ b/frontend/src/assets/img/icons/webhooks.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/img/icons/world-wide-web.svg b/frontend/src/assets/img/icons/world-wide-web.svg new file mode 100644 index 0000000..8bad690 --- /dev/null +++ b/frontend/src/assets/img/icons/world-wide-web.svg @@ -0,0 +1,2 @@ + + diff --git a/frontend/src/assets/img/illustrations/checklist.svg b/frontend/src/assets/img/illustrations/checklist.svg new file mode 100644 index 0000000..5b7e4b6 --- /dev/null +++ b/frontend/src/assets/img/illustrations/checklist.svg @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + 26. Checklist + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/cms-header.svg b/frontend/src/assets/img/illustrations/cms-header.svg new file mode 100644 index 0000000..a60e8b2 --- /dev/null +++ b/frontend/src/assets/img/illustrations/cms-header.svg @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/dashbord-intro-hello-bg.svg b/frontend/src/assets/img/illustrations/dashbord-intro-hello-bg.svg new file mode 100644 index 0000000..e2c08f5 --- /dev/null +++ b/frontend/src/assets/img/illustrations/dashbord-intro-hello-bg.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/data_center.svg b/frontend/src/assets/img/illustrations/data_center.svg new file mode 100644 index 0000000..373d37a --- /dev/null +++ b/frontend/src/assets/img/illustrations/data_center.svg @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/email-verification-steps.svg b/frontend/src/assets/img/illustrations/email-verification-steps.svg new file mode 100644 index 0000000..4698bb7 --- /dev/null +++ b/frontend/src/assets/img/illustrations/email-verification-steps.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/forgot-password-bg.svg b/frontend/src/assets/img/illustrations/forgot-password-bg.svg new file mode 100644 index 0000000..cbb602e --- /dev/null +++ b/frontend/src/assets/img/illustrations/forgot-password-bg.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/hello-box-illustration.svg b/frontend/src/assets/img/illustrations/hello-box-illustration.svg new file mode 100644 index 0000000..2cc753e --- /dev/null +++ b/frontend/src/assets/img/illustrations/hello-box-illustration.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/idea.svg b/frontend/src/assets/img/illustrations/idea.svg new file mode 100644 index 0000000..976ad57 --- /dev/null +++ b/frontend/src/assets/img/illustrations/idea.svg @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/ifg-email-verification.svg b/frontend/src/assets/img/illustrations/ifg-email-verification.svg new file mode 100644 index 0000000..c7fe375 --- /dev/null +++ b/frontend/src/assets/img/illustrations/ifg-email-verification.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/ifg-email.svg b/frontend/src/assets/img/illustrations/ifg-email.svg new file mode 100644 index 0000000..f081d30 --- /dev/null +++ b/frontend/src/assets/img/illustrations/ifg-email.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/it_support.svg b/frontend/src/assets/img/illustrations/it_support.svg new file mode 100644 index 0000000..900df2b --- /dev/null +++ b/frontend/src/assets/img/illustrations/it_support.svg @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/know-klovercloud.svg b/frontend/src/assets/img/illustrations/know-klovercloud.svg new file mode 100644 index 0000000..628f681 --- /dev/null +++ b/frontend/src/assets/img/illustrations/know-klovercloud.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/lets-start-left.svg b/frontend/src/assets/img/illustrations/lets-start-left.svg new file mode 100644 index 0000000..23435cf --- /dev/null +++ b/frontend/src/assets/img/illustrations/lets-start-left.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/lets-start-right.svg b/frontend/src/assets/img/illustrations/lets-start-right.svg new file mode 100644 index 0000000..4e12f1d --- /dev/null +++ b/frontend/src/assets/img/illustrations/lets-start-right.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/login-left-bg-dark.svg b/frontend/src/assets/img/illustrations/login-left-bg-dark.svg new file mode 100644 index 0000000..69dc123 --- /dev/null +++ b/frontend/src/assets/img/illustrations/login-left-bg-dark.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/login-ls-dark-illustration.svg b/frontend/src/assets/img/illustrations/login-ls-dark-illustration.svg new file mode 100644 index 0000000..7765993 --- /dev/null +++ b/frontend/src/assets/img/illustrations/login-ls-dark-illustration.svg @@ -0,0 +1,371 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/login-ls-light-illustration.svg b/frontend/src/assets/img/illustrations/login-ls-light-illustration.svg new file mode 100644 index 0000000..effe003 --- /dev/null +++ b/frontend/src/assets/img/illustrations/login-ls-light-illustration.svg @@ -0,0 +1,349 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/login-right-bg-dark.svg b/frontend/src/assets/img/illustrations/login-right-bg-dark.svg new file mode 100644 index 0000000..a4d1016 --- /dev/null +++ b/frontend/src/assets/img/illustrations/login-right-bg-dark.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/login-right-bg-dark1.svg b/frontend/src/assets/img/illustrations/login-right-bg-dark1.svg new file mode 100644 index 0000000..b75a9fc --- /dev/null +++ b/frontend/src/assets/img/illustrations/login-right-bg-dark1.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/object-storage-intro-bg-dark.svg b/frontend/src/assets/img/illustrations/object-storage-intro-bg-dark.svg new file mode 100644 index 0000000..9c16e27 --- /dev/null +++ b/frontend/src/assets/img/illustrations/object-storage-intro-bg-dark.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/object-storage-intro-illustration.svg b/frontend/src/assets/img/illustrations/object-storage-intro-illustration.svg new file mode 100644 index 0000000..1045857 --- /dev/null +++ b/frontend/src/assets/img/illustrations/object-storage-intro-illustration.svg @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/object-storage-intro-illustration1.svg b/frontend/src/assets/img/illustrations/object-storage-intro-illustration1.svg new file mode 100644 index 0000000..e1be176 --- /dev/null +++ b/frontend/src/assets/img/illustrations/object-storage-intro-illustration1.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/onboarding-dark-btn-illustration.svg b/frontend/src/assets/img/illustrations/onboarding-dark-btn-illustration.svg new file mode 100644 index 0000000..61b04f3 --- /dev/null +++ b/frontend/src/assets/img/illustrations/onboarding-dark-btn-illustration.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/onboarding-light-btn-illustration.svg b/frontend/src/assets/img/illustrations/onboarding-light-btn-illustration.svg new file mode 100644 index 0000000..fc9eb22 --- /dev/null +++ b/frontend/src/assets/img/illustrations/onboarding-light-btn-illustration.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/peak_mountain_3.svg b/frontend/src/assets/img/illustrations/peak_mountain_3.svg new file mode 100644 index 0000000..6683a54 --- /dev/null +++ b/frontend/src/assets/img/illustrations/peak_mountain_3.svg @@ -0,0 +1,262 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Peak Mountain 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/queue-intro.svg b/frontend/src/assets/img/illustrations/queue-intro.svg new file mode 100644 index 0000000..aaa8e25 --- /dev/null +++ b/frontend/src/assets/img/illustrations/queue-intro.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/registration-ls-dark-illustration.svg b/frontend/src/assets/img/illustrations/registration-ls-dark-illustration.svg new file mode 100644 index 0000000..06707fd --- /dev/null +++ b/frontend/src/assets/img/illustrations/registration-ls-dark-illustration.svg @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/registration-ls-light-illustration.svg b/frontend/src/assets/img/illustrations/registration-ls-light-illustration.svg new file mode 100644 index 0000000..1207893 --- /dev/null +++ b/frontend/src/assets/img/illustrations/registration-ls-light-illustration.svg @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/illustrations/under_constructions_1.svg b/frontend/src/assets/img/illustrations/under_constructions_1.svg new file mode 100644 index 0000000..b7b5b8f --- /dev/null +++ b/frontend/src/assets/img/illustrations/under_constructions_1.svg @@ -0,0 +1,282 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/instance.svg b/frontend/src/assets/img/instance.svg new file mode 100644 index 0000000..64c93bb --- /dev/null +++ b/frontend/src/assets/img/instance.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/list-style-custom.svg b/frontend/src/assets/img/list-style-custom.svg new file mode 100644 index 0000000..65dc059 --- /dev/null +++ b/frontend/src/assets/img/list-style-custom.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/img/local-gateway-bd.svg b/frontend/src/assets/img/local-gateway-bd.svg new file mode 100644 index 0000000..5428f58 --- /dev/null +++ b/frontend/src/assets/img/local-gateway-bd.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/location.svg b/frontend/src/assets/img/location.svg new file mode 100644 index 0000000..76c8f49 --- /dev/null +++ b/frontend/src/assets/img/location.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/marketplace.svg b/frontend/src/assets/img/marketplace.svg new file mode 100644 index 0000000..cda0234 --- /dev/null +++ b/frontend/src/assets/img/marketplace.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/img/max_alloc.svg b/frontend/src/assets/img/max_alloc.svg new file mode 100644 index 0000000..c429ba1 --- /dev/null +++ b/frontend/src/assets/img/max_alloc.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/img/memory.svg b/frontend/src/assets/img/memory.svg new file mode 100644 index 0000000..ad5610e --- /dev/null +++ b/frontend/src/assets/img/memory.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/img/migrate.svg b/frontend/src/assets/img/migrate.svg new file mode 100644 index 0000000..1bc7de6 --- /dev/null +++ b/frontend/src/assets/img/migrate.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/img/mobile_banking.svg b/frontend/src/assets/img/mobile_banking.svg new file mode 100644 index 0000000..6cdd353 --- /dev/null +++ b/frontend/src/assets/img/mobile_banking.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/nosql.png b/frontend/src/assets/img/nosql.png new file mode 100644 index 0000000000000000000000000000000000000000..2a2361371391b20ca218b02292946972c4ecdd24 GIT binary patch literal 22246 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 Bep~ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/organization-custom.svg b/frontend/src/assets/img/organization-custom.svg new file mode 100644 index 0000000..fe941a7 --- /dev/null +++ b/frontend/src/assets/img/organization-custom.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/package.svg b/frontend/src/assets/img/package.svg new file mode 100644 index 0000000..477e7ed --- /dev/null +++ b/frontend/src/assets/img/package.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/pay-offline.svg b/frontend/src/assets/img/pay-offline.svg new file mode 100644 index 0000000..40f0ce2 --- /dev/null +++ b/frontend/src/assets/img/pay-offline.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/pay.svg b/frontend/src/assets/img/pay.svg new file mode 100644 index 0000000..9ca470b --- /dev/null +++ b/frontend/src/assets/img/pay.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/payAsYouGo-custom.svg b/frontend/src/assets/img/payAsYouGo-custom.svg new file mode 100644 index 0000000..514424f --- /dev/null +++ b/frontend/src/assets/img/payAsYouGo-custom.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/payment.svg b/frontend/src/assets/img/payment.svg new file mode 100644 index 0000000..40cb971 --- /dev/null +++ b/frontend/src/assets/img/payment.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/img/paypal.svg b/frontend/src/assets/img/paypal.svg new file mode 100644 index 0000000..11b082d --- /dev/null +++ b/frontend/src/assets/img/paypal.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/img/pipeline.png b/frontend/src/assets/img/pipeline.png new file mode 100644 index 0000000000000000000000000000000000000000..50cdc7c261201157acaf4301588e54b50e7f9a09 GIT binary patch literal 34660 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 literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/plus.svg b/frontend/src/assets/img/plus.svg new file mode 100644 index 0000000..5db625c --- /dev/null +++ b/frontend/src/assets/img/plus.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/pod.svg b/frontend/src/assets/img/pod.svg new file mode 100644 index 0000000..a31a219 --- /dev/null +++ b/frontend/src/assets/img/pod.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/img/postgresql-custom.svg b/frontend/src/assets/img/postgresql-custom.svg new file mode 100644 index 0000000..ca97c14 --- /dev/null +++ b/frontend/src/assets/img/postgresql-custom.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/img/prepaid-card-custom.svg b/frontend/src/assets/img/prepaid-card-custom.svg new file mode 100644 index 0000000..1832b76 --- /dev/null +++ b/frontend/src/assets/img/prepaid-card-custom.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/processing-shadow.svg b/frontend/src/assets/img/processing-shadow.svg new file mode 100644 index 0000000..2c97140 --- /dev/null +++ b/frontend/src/assets/img/processing-shadow.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/img/providers/aws_logo.svg b/frontend/src/assets/img/providers/aws_logo.svg new file mode 100644 index 0000000..ad15864 --- /dev/null +++ b/frontend/src/assets/img/providers/aws_logo.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/img/providers/azure_logo.svg b/frontend/src/assets/img/providers/azure_logo.svg new file mode 100644 index 0000000..c1ffac4 --- /dev/null +++ b/frontend/src/assets/img/providers/azure_logo.svg @@ -0,0 +1,2 @@ + + diff --git a/frontend/src/assets/img/providers/bare_metal_logo.svg b/frontend/src/assets/img/providers/bare_metal_logo.svg new file mode 100644 index 0000000..3e83333 --- /dev/null +++ b/frontend/src/assets/img/providers/bare_metal_logo.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/assets/img/providers/digital_ocean_logo.svg b/frontend/src/assets/img/providers/digital_ocean_logo.svg new file mode 100644 index 0000000..5a81f24 --- /dev/null +++ b/frontend/src/assets/img/providers/digital_ocean_logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/providers/gcp_logo.svg b/frontend/src/assets/img/providers/gcp_logo.svg new file mode 100644 index 0000000..8538f23 --- /dev/null +++ b/frontend/src/assets/img/providers/gcp_logo.svg @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/img/providers/onboard.svg b/frontend/src/assets/img/providers/onboard.svg new file mode 100644 index 0000000..c67ef53 --- /dev/null +++ b/frontend/src/assets/img/providers/onboard.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/img/providers/robi_logo.svg b/frontend/src/assets/img/providers/robi_logo.svg new file mode 100644 index 0000000..fa736c5 --- /dev/null +++ b/frontend/src/assets/img/providers/robi_logo.svg @@ -0,0 +1,74 @@ + + diff --git a/frontend/src/assets/img/queue.svg b/frontend/src/assets/img/queue.svg new file mode 100644 index 0000000..6e71c8d --- /dev/null +++ b/frontend/src/assets/img/queue.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/img/ram-memory-custom.svg b/frontend/src/assets/img/ram-memory-custom.svg new file mode 100644 index 0000000..38c1b04 --- /dev/null +++ b/frontend/src/assets/img/ram-memory-custom.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/img/ram-memory.svg b/frontend/src/assets/img/ram-memory.svg new file mode 100644 index 0000000..0a1a98c --- /dev/null +++ b/frontend/src/assets/img/ram-memory.svg @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/region-Asia.svg b/frontend/src/assets/img/region-Asia.svg new file mode 100644 index 0000000..69cc264 --- /dev/null +++ b/frontend/src/assets/img/region-Asia.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/img/region-Australia.svg b/frontend/src/assets/img/region-Australia.svg new file mode 100644 index 0000000..dcf6ff9 --- /dev/null +++ b/frontend/src/assets/img/region-Australia.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/img/region-Europe.svg b/frontend/src/assets/img/region-Europe.svg new file mode 100644 index 0000000..109e530 --- /dev/null +++ b/frontend/src/assets/img/region-Europe.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/img/region-SouthAmerica.svg b/frontend/src/assets/img/region-SouthAmerica.svg new file mode 100644 index 0000000..4cac292 --- /dev/null +++ b/frontend/src/assets/img/region-SouthAmerica.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/img/region-USA.svg b/frontend/src/assets/img/region-USA.svg new file mode 100644 index 0000000..774b32c --- /dev/null +++ b/frontend/src/assets/img/region-USA.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/img/region.svg b/frontend/src/assets/img/region.svg new file mode 100644 index 0000000..a29db96 --- /dev/null +++ b/frontend/src/assets/img/region.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/img/registration-ls-illustration.png b/frontend/src/assets/img/registration-ls-illustration.png new file mode 100644 index 0000000000000000000000000000000000000000..e00d167369e24c68878bbd66759a749318bd36b8 GIT binary patch literal 597198 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®~%;ah5_9WZ5pCwxjL={a`13;>b95v8ENGJk?$Z=HV{Ev zdI45V$@#vI|7XBfW;{O%8Cw|V=mB0^1*OnTgZWt_(k@#$0`(Lykv8RyI{&>VTpmrL zDnaf831awC5~ZUIMjOW`ae2U|pjB29#yd+!?+BVayeqwjc;D?-xAFGm&M#!s3g>w| zc}4FD0=F(BQuvzWa8-s=dY6XBTlXd59vY#DQd?0pppL#`=5Ibz5i=TZ(Dt#=u?{H< zesQ=+kVPNF+q3e>(nn+)JD)t`8bwx|TR--&;c z2TXSG(5c*K`TjgJCJx25sZo#ee4Zr-pP|f;hCfm2ZyC&)vMYq+ky^ z;U^m#8{swI?4W@U;Y7Wg4!i&H8>%7n-*W*}+L`!+dpx1@#6D{WZEPFwo`3m2~NApJT)6Jpwvf>DDp zLKMP(=m5h$SIjZ)`uSam%(s*llC2_nZncr3S6XYCt*c{}u2-C=W%$kN`w$riOThx+ zXYDO?;f?@qsyy7zmJ1F2h?`5j?}6}!HX>_+aOQDMv3oYoB!7v2JgG%H(i@WT)YOODn0lezkOJ<hS%>=;c9TyLRTDaPy%6G{#mr|LO?OUZ zU=lpPA_dZBe&(ldBqzHo9)ERrRO;lf2=U#r=FzI?_@w*sKC*iW zM!cC;$}2g>j1r@yr+0;>lz3iy=SL5F2YmJ4BYi1&Vo5w>_TXQpXJ%t+FUesUrYMth zUDrhyTmlar9*%1)>?CYoLw$zKuBe!`fj6($7}+bTA0C?{V!Fw+Og0PM`>z^Ut0NL- zWQrSC)>854sXOP?Z6icRpSGs3xgdw*;b`Q|4iO#|+4J9^qG!%gd|bxBkjwuvhz>IU z?8@J6uMsoWrH3LOL&0AOFb{_rdX<%s7PL?!G>uQNtnO2Am!h_PcFoRrO$~VM%TQ%wb~X)+vmFLvQfrcM+!)cuTo;{@==8 zxuT)%mQld7pPvT@o5~Do+!NriLSa{lgEzu)*4?yMc3g3X!)gOoz;U(CUR!cor`OaZ z7Zv>5pvMLjbi`?#!x0v6qW@G2u|NM@sBw81SsCe?Mr=tvN%-7zHrjDrt!*d2^r+ebtrQ#(bt1x;yduq#l7#==?f^(3^cUUJBw@&OnB_6w? zhW2Vv8Xoc^H5WQK>0vdxPjEjm#_(Q{e0|MT3ENa5&lDARSAM@FN`xtkiZP|MaEy3_ z*CbC&69x;$ANm*ek%u}-o&nBHpWP906#$<5BqC)+%m$ELbUm<1D)@=-@)+}3L_TsuOgZ= zg1&fLJ@*qbTLPFb+{^i)kD73kzhJ9S*QpM$772nQ4gkduzQDeva@0smUt!!BEU! zjhwnTULWXvHv*kY8c{FUhgo7unO{|6vY{gTSAn%0abH}Ea6xlUykfShWeL+uC#~FF z109%A=)aY3<@k0nI<*Ta%YC1|VKa-JU3!iBbA*PN?nFhX3vWE4lp2R+HlB^~%&K=# zcZNIZ&@PUP6te2fF0LjLhEBku=$=YRxD5o?8uuNnF+c+>)j{ z*837TmU?f5tIKQjC132A5Xt>G9wTPB3H>u-wTih!0rwGP4 zbX3e|v_)P4tawP8-tQbszc=VrBa$G?B&Al9Z%}B;)ko%6v2T>>cLqalphQH9>pLRq z?mf`#7cLZ|Fr-2%1yQmfPINZ9e=B$0sEiH&Mx<)AM``g-^_*O0%&)9}7G8J*XH%}i zhE7gS-ofDEDN(W~81Ed3)Wuy9^+WXu;JaZ9-4`O=_2{Kd$M^BEv9(|A?}1!)#8>x+ zB%5K%bm8uP z67b-d*ceyiUY?&&1u7og#)KFBYawU7Mf!g-j}n6Zy)&N1j&H9>yIuN9vB!*L(~7v` zYtaL56PA(a?7pbUFzFUcs-`n82!GWoS>VtFO@~2{b!N&OFxf$Y7jHWr*@{~ zeM}ZR2z|J?grwotN|BBdb;j+ zF`8r)uYfdc;|fqVG&6+f@OKSGGxly?&@H%kuvm!FC-C2ByXX3ow>D8W&7*ou zAp;}rlb1CxzKKumJ!6qJ=W|yrH)zHqlBfeD;E$Up*V>V_AwRE!VN%ss`eQM_0xY_>Avsu<>?NKWUK<0zKjx}W}YZ=%L>eI8Z^hg=+8YAieRhtIwr ztoj)|_2B~k1*eT+CR03zUoUtgz6CUX7sJU%rLSvSWje2ytw?zXE-q!g3D1#`*noZ* zw^biAep?#0G(Ut5xnI)Oo+9Rdc$-nLRh$W1S@t=9gPu6@$@`xBpz1}G1_(AJBgO)z z$k5`Y$!D7IE_tax7hS07(XY_!?YZ(jKcI``6Dg51!o~5#osKlA8W7e8{~<@&hsC>o z+p_II11GQ(@dzTqxFLkzb|fF}2nMEO?SBk#x2>bHYdfTGewym`+LF#wfkzn$Z}@9- z*JA+~1iw_LQp3x>pcYR|^mY|W*Nh(?K6F1UV>+^R57|nPB}@N=KCmQHmesO`W_OP% z-WL=7$S`5@kkQV;HT2{V`JUO>b+vBce=XTE&~jcQusY#JvnbGekXhgui;cyM##31o zD0k`g)tfzjuE=`9p0;7i+j>c7KSp7Eq1OhpUvlaf-|#K~zHA<|BRP`{7SS0qMZ7vX zl3%()j$daNd!dm?d0!n|Fm zezRM)Au9b?7ERh`wqK+|lYgAry|IL!YSewjF}!TQT!#EUlWg-3`WCzB(0o#Mg`}z< ziopIM*h(z%F!bj|3_@i~Dnj6tv7#`Jd8WC20t61g)Vw*MD=6vwD?0si%EEpyFPGC+ z`4^$G+13{l@WO99=-mil2h!fQfe?ZV$8X?Mfn3}<>P%A$y4>(A`fx{2SgrkH{9$|? zXI8Drgmx`U_3s=ne@2W&TJS>FO~unI$GM>P{H@9LQZh~&`8`+4=OKz>#vaf2p`${x z!+oFcrT#};p65BFvj6_rSeYy>VTchSN~n}qHth@J^RzkC!-^(9@RGJ>yY3D)U9SxI zJ3=Cl^*X$O}u}ee070{mfxUa`89G&}Cc^M3Py%bnW znxTJJ^Der(w_;?}`*IX+bZTTNPUEF!WpW@&&XlIPDiha=mdO{snl7iD-oGe`(8hGkx9=ZGjJ?UEyejEFr5>^R4QF~o}-EjsoWk>fprpmYYgjIg-E zPf5)cYlaYF##Z5fE#HtjLyeKEM?-BKR|8$(FZyUTFvjj)FfqIZNS?25%FqlhgIQQMJwF z$!M`4byPA{h>F=hi*ViOl3hTNHWOec#=fK#bU}*Lz&^3ksdZ219uYFa(A`|6q(eBb zF}U|$`0pUJt;z8EH9(r86r2oqg;$%51P8NtIxm1jx0C-k8gNIUyDcO`mu!z*kH3er zro;{Dc8M=vYY28TOT6mZe^g0df^eUFAx#65wXJKz-P!@;6X#(b;HYi3b+y2jsdv|R z$Vu}TA#*>R(k(_0`m2J=|yc6G(vc_Z@3V8jZ zG7S|Hf{OTs`-r92jo-{>xOrjx307`Qx)4Hnnitl$qPDH*nfGqph^($n0hMxj`mcge z{x?kBDx(A*$T9>bzZyrr+S1AsU-vf&+(9k3$bkY_YV_dargxDwBmsQ-)#1wUrmkhM z{!Q}dO*Jk%L7ntI#S}GXr|(Dts|=WMJ@yZ`8}^TI{Z9|;I(#4_=bZ0kY+tgC#|0~- z$MDagVPOb%F~G2^cU_a}L4~yCYCgRH`->0K_KdCQ<@dh%-_o&wyST^qbOWon_$DKv zU#HUC(J2=lIj57ER(1F$K3IIIT16?btWLxQQ|rsHBWtnjZY5*!lClB64G`OWAHPpc zn!FbD7VB(E{zZM(otlU*7hc_?xrK_!1@XSiEj7J8@nM_po2IIK5!P{g8&U=PS-^X4 zx3<3-IN;2F*wMHZPBC4T@6A$B9hXZMHZF_GX^G?Q4GUel6Xdf{odjuYK7RC|Ud;r< zA4LKU#+h(Ta1cg49*I5PLZPRGUVT`=AhAEZWhPNK`&@eT1AbLz`>s6-KdjU-f$+=U zh^g_#2{ZF0J33SqmmtBM=T(2Kz&J-p$9)`iTVg`6hRRQ~sH*^hAP@^Q8)!;h`IWYH zOz|XV39YPAXVv~kYxg+1sIZx@K7y_*piD@0hg>%dX;(Xew|?A*Jp4wmK%SU?N#6<( zO-%U;^(&4X?R-H@rL5pT{iq8wnv4$?u{#0 z+Yf_*|4tVg>Bm)gE_jmJKhY`MJuUbpCSk)s$aQ}tv7adt6)s)}{o}6hW!+X>$fM5u z{#OE2Z`v|wuh%?>XSquF9M7}tHqC!4;MrGRj=OSxW>NhmE8xx{z7GM$0r&zim+VwL zCOrKyi~i{#ETJAfZlv&3cA zdb6=VCO~2EFG|KxHG`sAc{j0qw9Rn09Y-NZxPCZra%Kl&ANO+Jn7uLKSfH5ja9WW| zDVGjZ$$Tf(K?hlciyCn!H+pszP1=eL+G|$sY5qT+{(&*>ws{|iH{3K%n#Q)>*k&8G zNgCU>t%i+lx3L=A*s!s&v8{dfy1&2Y{}%Q$J9Er|IrVj5N7zJK5em{a?8!4hvfE?i zEigpwO9OH&>42xf9|lZznL{xZe4;(325JRL74Li)v{Mm0fYwP>>)x*mZW&wOj?!^x zqgAT;eom5j)qHzj_EB7@#WOUN_VN89d#!PXvi$=VNb{*g;Qf=Y;=Q2~kCi)L7 zJJU({mI++D$Dozymojzmns!l(4HDT2PKqObJ~@D`I_i!Fi{j0QRL!z=KRTz z9sL5?PRy36Y`w{X_JwpB2lBh^F=sfzuN&3&#?CCEUl0E5J*&z3Ul!oky8F#$lvJiu zn^QT>$M>k8zyJy^tdVnTh`RvAzl^>f>uCrIG~QSr*p?HmprGwcu-SPG@Jf&?lgJ~z zY5iL_Oej^4b@40iO`@laL4eth;T&zu2lS$c5ZdxL9d?Gs-`~ zjR&r?JG!iZT!(5>Jsq95u{yA5fKq7o>jd3}J&*F(Dggxxo`Q{v^_mgXpO2d+zrbI5 zu4O-}UjaQTqWiRT?i^#shbAikL23?l5$3JAQy7ggD~pR5>Q{N5=KG0t5|iQW+&t$D z6-b3~-~6Q^gORMi1vxDYXhx(Y_% zzRn)teDqS-6=f~D`+1TCqVUQBqGl100r5Wn!oL^j%}WjN{`y|xvSr{N9;$jH&`PaT z7%{D*#2!qGmoet@)Ac@qtc{ERhde7eTbgm%mmNsf_`-mk7`Q41e}~-VF8@npd%wXc z5}n8BRW|lKpgo-Z!-t=m_ZySU80i{GmW|l*nzkpuD?2$Q78qIQuM$u5Q8rxNh85et zR0O}{Pryv+wbC&2{{e;zz!D(s{GFh7xztA75xHlRkgDl&{g}AaazbfN>!*bUHc;R^ z#T=CBe3zWbdDb7U6s14J_(DUmI)m{YuNLbS4-jf>VF4#?n`o1Sbg`*Wd^%7SE`Uuy zwE$!0>gn7?)Y!|~1zGQ~dWIhB%#=mAroP=+6WWNhquq@R1(+>*IS63$=-uvd?55y+ z^~-`d*8OJ%!RLmieCE4q&)8z>|$F`*O{Te(m4 z=YN1iPmaP(Dmedry580iby@`Zo!me`2JdT8p!YEsw5PS^x1!0-jhKl?zOcs(<&&Ix z9pAWPV&Gm`^`M*m^G!gZE?)Q39USmTQ1r>=v1$-Pnh81&3$_!8Sn7$H`0Fn>s<~h4 zB?CPjD3@F|(4-qM$P<3}D?DXW<4LP2LCdB>&QsHnjUe*-Ih_^946rq-wWwXwpS~Ln4rqra+dUBE^tmlzgB>DEDd!yKpbceszvRMmSX{ zzCMhqvWTwI8<`tR@AEgTj}q?Rz6#q?dAP0$lc>`;dI+{vj?;1=6(uq!rrIv221>zF ziOe_~g0RA57Bu^iD#u-?V(rnil=DFAN|8C4*RroF&ReD%HST znp@~IF*ySC$vmLm;P*Jisk0SNuoju(o8tJHuAZJU#>e3#9%rqqeZ{OD8HN^Z?{^cs zy&$}#RFxo6(iH7(?a}{k~pT`o2*C_5)txAa5RG4HpWhsL#T|aGGuci7@%bKGbKC z-?0{gRy!t23}$j)_$FE68@l)~3KP#zknqk|SrAIIr$U!9*QF>zGJq}$5&@WK1`PBf zcf~gfV%D{-7THmEL;6c@?+$&hH5wIaCCT<}N2Pk}uu1Pbs`o(%^|1vyrq3$Gf?LW; z7w^+m-SFdz4<2cP)JKgX5Ce||ugiD`KaBSi$jwwsfaOc`YFlxR{2K%1$OA)Jk}g4@ z*E9JrmnPdVoa_qY5sp#ax-S3Z>cZR2AXz84$ipL$>pt)X<)W+N!Iu^$+vQHtJ7-o~ zKA=LWghv((Q6fx&LH1Gyr*O3AS3IwCIMQiUx`t{3uiMXKPe!708OtB|ClFi|#lTqc}nAFBPo?iO~J9J5_C#))tBjcA{lx~V`xdd#o;t2X~9vSYq%`aiUkv=G& z=^W$tog`eN-k;G@(fDdss6`tLQJsP)q%eLPo7wJPg~FDC?bBEp1r$y?}sU?X}H2L z9n9)ysiwe@_^zG(NvE?B}DXRT9Uwj%}Yx{GNV?_-n60C24XJsX* zYxfwvm6>J2B)aL~tKCZOY^;mz&Dhn@2Gi553n;t201)GVYm!Bl-RVYf0iC-2n{SH- zAs;r1j_iE;HgE;qdk9y{5A2P*UbAD_JpkE^g3aQop2_G@t=>O8oEs(^laj{M2m~L| z&nxu2eIA~0h;0%LZgfx$xtD-qg*Yhep@8Sa&oDL;Z1~fv%uyzVj9O*n-&D$AgAVGM z#Ap~xE7MEJrTo-9UoyNG33Kt^?IxCIP2>6r0?t9~*<*BpB$d2u04YPKzl5W)f1lg7 z5OF~nsO7PiMHLG@{1xz6p{7{D;OZw|LQHeDEHD>F;(kRTjs~hUF=Gr$Lp-8&6o8zo z_b)m=T?tH0UU4Su{>i!7?qpt753={4O&jX9J6=? z)?G>5ls?vEl8|c#j8*OQ5GS5$|BsPqq?sRX?qoZE4)F-Ls-sMY#$3y90zMvyYE(kI zQaH2&VTe3#m9>|g`^!7GH>{hK9#2(o=<%+*&gos!7LW*Pw%BQlJmlJUo=JWxwQz#1J3px*H@=b#4Uq6bSw1sOmE+=@6`19yJ*_S7huwx7qLN!afpJf%yGXi z#>c09_*yQ-qEFg|w}g5H>52~GNA(lwJcLtI74rlkMlyn}b=k8IGRI2$XeigwNKD@Z zC@TT3G+#?%t?z^3pOm><4wdafQOq`+u39fq$hv-vKlw7wN1)bdkP@~IJs5aV`0kOU z^-+Bl616Y^HEoJER`)si>)5t%bV%`eAIe#sl5;e9mF*ja9JPjgnAqDNwmaR*_?@+@ zE)bJqIbjaIH9LQ_MV5Y4TKzTM!PZRiIpe%a2DR zGSdj^qsd(BK~FlBjha%N6JltR?p>Y-&3j!IGAYhB4zS)U%!*4qAPb|U6$l`}Wy28j z5Xp!Rs`VC)tZ)Z)PEQ4S;=|d}vs>T9cJTgY$ibnQk3=~h|H&L3^Vj$?k*QwbS0UXW zKB(pWCz=!Rli_*QU_mBr(SU)uo_w(Z4x7^v3Ss)#J%G>k5xp+ijad09p9kf>DI}Io zj@cCP)o$VFDbn*_JW_F?X?kqrog>lVX-LMfS2wZ2$$!I zAX1x;No_}TIOnpfUmvHXg!6cYTz<~BwZ4}u3ZEU_-|4N}zbrj-p0(YIzWTHq(SD9x zMX{4C?fmaEv))lHsLMOB_t6PL==P>Yd4@~DF$UGTEADX@%?_u6wQp@GQ@+TI-&V-~ z*MO8w*aSvc%v+^DcYZn9J6A7MS{{Xi=3`$yME&h5l*TM-udZznD8 zciwr?`;k(3l5;^$@k#U8oiUO8+6pFGE3R|iMC(YyJSS?M6|q8#5&R~oVLkzlIX>){ zcM1{s+2vdhjdEl4c~%P%yET{d%fUwNEZ_@5qiW4 z`1FjFtABfixaaWxUTSJ{ft6}e{L);D*L$QUBuEg6vz>!dZ$p*u&7$4SO$~Dhy8BEF zM}R$6L~O)M8C69QHyb=zd1_2ti5)`$2-fJ0<_&f^y=K1hP(}WAbE%P_M2M7M6&Pul zx{ru35%%Nd(*lEGmU{+dANp*`-$pUVWF?%R9AO~>DmYYH^a2h>c1+>_R0QEJm9QrK zv(JL$@qk)MI9f6G9k}>eb2@W5 zRXvSWz8QOYHXy0V$EW8#y#!0Gn&}| z@#J(eb$0n;;OATUr6R{}(V)BS#>Qav^NY@UQ7K=o2{3$iyY~Tx>%l66p%6=?E0()+ z-d^Eon<_=nBCX5*oE?R|y1fF9)pUjV?#c5bKc)G}@vr$GYSGXAJjK#piUqg_2K=4vZD9 zqt(fH^}N3YZWHTy;kHf?XI2$%Bi%@w@!ha`6~%y+*J4t7j3T26h9?tWO{i3+qh!ir z_49C@#h+_Tj*NZF{n?LkfQZ#21%N;&&)y-}Pb*Zsq;;Fdf;hb%^O%_DuoF2;GV#Mc zh7n?w0Yv0@ZcrX@H`JciYITDLuDu*XERy5r0`kDsze_UykMTNA4Rk z#&4AxR-xX2CnkfZv9k8CTh%mO0nqc!Rvh}@u7;OaH$JqeUEy855UL&yKF9;<2wD3x z?CTX1XxPKRou^~JgM|Xor4P=)ZRaO>F2iZNDw=HG%(68xqV*S+Q+RLM1IE#M-HbC=6E_1kCkBZpYHM!NG z3AZ1(DD}*#+kDdo!3rrna-RbIKYqkY;qhmJjYgU3lQAgQ98>g)Zz2*Ayu^d>2JHUi z#z^E*h`!TUNw<~BTWbw@H+)c6*PmvTT?zQ1k8Z>lM+RWomN0TsA15JoCOVuq*PPv5 z+P1Pb2_tyY?*=?6Cv&iR?(;F}3e!Fg zB4ExB@`hU@+2?nzQS<;1fbdZeawAPaKt=Cmu;8YdQ$Egx46`LJn&Dm`khSzTK)>JM zUkG7)pB$<2>7YGTvW0)+*vB5-xHH~+eS`Ow2V^C*&`)RO4_1I>zRSS)ed6vTlRE%@ zB|XXhA>nbp)f>f(Y~Z-W`r#+Wm4`Q?o-`bNs$q5=s*S9wxS-k(1*p@LL@+qZ!-B!7 zn07{nbkuM}Zjr|@Rj=?)(ospMTYj#CMN7tV>EGvdbjW2jLZmQ+3u9+t4YvF};|&@1 zUh=O>ORRnhM;lgz?vgiq;7Lm$kp8J#gP7MEwB?foQ#1_MEiuAK?IMVE2mXTD%ipGI z%dDat`BT)p6FxKKS-o_rnghuafiOXfkU^1m!*lmMg3SLhuG!9o?RYGw`}12Ikj(e8 zOC%YXO*=pAqp!{XFs=vwp7cjq5aI#gdY|}=H+Q^%Cw>uy$~6TMre|@=kbK?;=U|z& z9zSM7xbB>tB`LdW1Q%qY6nN5;I2P@zH%L*+X8iP@173ZGZ(CagEo>v4vIrE%XJ+Q_ z1TqOD>Ym~=gd8xAJd;<7iqB=vs;S$*>Vzqz#04?}^cY%t_eAEx+^j?3hg*_Usk(c& zOTanu-H+QIrO?w~YYE#IbHliL^!qvMBx=}fhjnOH1^#nAz^wsQd#)_P@iNDu=#MWd zWO_|$_>NW|{Vabx^S3DN4sqb1I$p)Ll3 znDt}JG1d~i_|3$b#xx=9ja%|GGD||379eaG_He#Dj35C>h>DjaIcLat6xjOMy74iU zKiE)_oHcPa+ya28>3nOzZm956y74DUVUnEADVA>6SAF4 zK}7)wJVVSDsetcz=wMI>a&@qGr}y|7E73x09pR&4F=9sl?%Cj|tHbsL?8RI(V5rBin#hOYc)AMt zKBR5Ixme&zaQCct6x$IK!3ntmB8SJ8hD(vq%$v9G+`l*-0RB4v`{OSTfFlCn5fe=y z5UjVrsRkZq#D#=wTN4cnKo%T5G2;y1CI5p{llesUf48GCgl|v<&PjRNBJr!02cHmYh~2=-xGQH8q;okdin#8zTTe=sy!D`*61EeujXT-Aoa} zNJ3NzxXsGC@7Wm=ZMKYE2jg;&6z}u6jU-1vomjxUwl25;P2X1AWz<-fXLY|Z`@SeV zS9>GURogfR;=@5q;$^k47vV=f`GU={w6HKIQdvwQu zdl#=(BhSfT!XlTQQ}HR*_I>(FOp<_^!0w3;a{e12Lq<$b3@7GEuHkZ6p!I#VcZkB#-rNQjWASMJPlTA!uQdq|l2`HUS%F*%m81x@rIxO9gM9 zN2Sw>#y-Tqm0Hz{LxvUxuauIqHC3liir}5P1qZyY+#*U&Y!IuN+J*EG*cyyPpYcWVwCeEeZJwv3#c{ z3GZ%g4+fRd{0fdom2T~6Gu)WTjIop}g(pA^GAOiQ9tq-ywcpYQm3>Jf&u!Z4)wvtT zQTq8?(3d$l8%|~F>-JI=Qt%H{U6|GZuNh6XTKRqr%+|cihKFj2keO|D|Aoy6Cdamq z%K0ZOQV$m95(ihymJR6ah({$gbeT>$ZXU&zC8<)!GSBpUmaQRl&l2wi)W z0E%p~%G+P){hbo_5UjTGyrrvuIp^;rR9Fx$+{j92Blh_F4xZMtLl%akIjij zmpCUs#s~u~c*n5#XP>v9Yw|WRHa(v|A?0lbAiQWTk(?dA3ka63>-|cr?t1^&-ah-) z?K7Eh$NjO1k2@LILRTcLAEV#mQ!O4A)jkQ9&wS3g_!vckAyJ%t4Bz)TLZvl@kfc@=hefLsINQ5u93kak!tweq1UZ?0Y!7 zVv0JbLO&L(nDRYMsM;(;Zdhd(BR`7iC7SrCiV>nN1=DASijbLnHDN@f{Yq);i&B!u z_Ot9*1@%d5FI51NayRpTRkH%1Dd3y^+)%dG+Oetmeh1yaAaUvpII>(53T-e zLN&JqpZ(w4TBZYTchf>bm*q}O3PemF$h!C;tx&?C`t6lTA2_xF%N2aX0*{l%#JcFug^Ethn zZ@{+RQDgppr2|#$IBq%D9_Ug2#bcYvjW`K?wmzUKWU#+Cq7A_1xd_#<-jQ z9z4g(>s!hiix&+9=dNr4qaoLvYpBC0fwT%ar_Mx$i}FbAs=Z)d1gw{G>rhx3SC!rt zOU7U>hRcx)`1n7|$-0$Tt}Sln77JPl;;@LQqK|siDkEx& zwfW#uiJF>&%-P{3d&6+aqxSMI`ry!F0CliH_U0wD*zkhLnIL6@N^UWfT5(*n?*dB6 zURq*9|L|ECehzrgc(#>4ea|Ww8Zr*ll1_rb-?vdIkdK;COzf|%PKxsSg~%u4_DL1lud^!=>dWta%*dp{noVW`8CBQA4Dv?2) z;z_mVRSHGHad!kV*76*}@Zb{;cbK zo*L^;lK*(Cbn|8i;+jbt8J(16IWA1vkE}_2~(S1uB+d`O}c1WWCaP zoCk_7+38PPWpGcf*k*pbX4zh%kiKAgd_ACW`h)g2T7dfJ@NYPjPlued=>vNJzLIoQ zWNGOd85sUBgIhjn$FqVbuEag*fsZ&@sF>v4f8u(D-HmK@4Gkpw_BwqAR2Y!X=QADZ zeSCCbgDd0zJTTkc0^f15dk*5R?dFFyr~m#lrjpeQg{`_p2zj7`AHZP#D@{y``-{+C zF?vKYaFh1BoWxulUJ>zEx!RO;8}~yx_H+*7 zzmItGllB9189nhqNkko--_*r8x<0fVwOiK~2JI=s|6Ld-{H2{xv0B-JTqs z0K#kXe{50sf1Kl12*$<&iy`61Wl^8KTyfXD_dQ7rVb@_<(dU`=ZE70yR;P`eb;=ih zkJ)K|uQB1GlDG39i$meufcIgx2$!8`gbEch*=uLJ*wJJWF4fWrna46vE}t6RnZ=jX zHNPJL#Ty-&KigaC#5{|&j( z3ZL3zyr(sDFhfg$MD^*{_t=&`64ASN@nuCp^5-{Aef-DQ4bAS~8~t#(X}KPV0+;+P zaxeF4UI$}nA0PZx+3XK39Q0_x2suey`vtBYFoznYYk$98J}FD#w!2-z3cXZyhGQY! z#~cco2p>xIZ?#OKs8I1YOB|Y?y!0RRPxRBv z-+z-MZ+W1PiLPC3G~f<$Xp`o~dYrN@#@`oA%pa)eQ2n-)w792Up=_~FI_?kGvLz^r zZSehacE~S9!|;9dqCyh=N=k=gu=HMR_0y59jx))XZpQP`7dJk(nh|m zx)?<6;eOZUyBo_Zfh(Fp=F@m+WpZ>um{#M^`1&Lb-3qdf7(YldYCKbl00z6 zLNm|{B(ANU*jUl*>_@uGFT+pZ_cG`VC67>rM_$*#5B&z6wRzO;H^gr-cPMnG<52A* zz_SxcNgYsH19>!Azf)Wn^2%TJ_TW`+2MZd!^!Ktw`qZp8xi_z|J6*VCHMAt=vd{4b z9^KE?WoJUz`RxoaS}d~ZQ54bq0njzy3hw{)uAunI%Lx*lL&U6eHs8nN8R;uL zQC~NpngL9}g@GU1AdvvGIpk@$rUc!0iY1{n43t(B%xtyJkhvo~GVUqlM_$sT0Gjv#VA5T&EZSr;iqZ#e}NLeW3kx_ zW5$t@X>+SPFW5q)swkCKVj9TcZ#zFQ6VnNHTtpP=@#G)&ia0wrPKF6UiLPp2wX)2 z{24-jZ2;8qCSu~f5>(S$`{8QLdbXp`$FzikL9qM0TW})j+bc)~;T{S3D}*ju5+Mn( zu^N<3I@~o^e57lLL1FM%b#l6H(n0iZ(M}A3%$MwF?%Ek`#gTsiJqNO6;s(h9101@q z`zNoW&rb%>T}?q&271NzSkmbaY{ZUAUzGJ~+viKgbufz~wknykNzP&QxpS5xX}~@G zG)Uj&gYQ8&)6w_GdHyI8+a+q);-#EnR)n%PDj*smbv(J7RkR5P!#P}4N*%cR=4@T$P z&dn^8``g2tX(eKz31Cp|b5SXcM_7kD%6Lw`e6Y(4=tm215hTX=;rpbQ2K&ZGl+htF)Y{uC!Zas(05iR-O&1SwovdxzS zDae!f1yP+iyRIXphM{V(^T|c`T{6c)W327xs1L!$&M=8G4<)tH@!$S^kK`a zpT*8)J_Gu|$j`xFK&PT#1k5>@Bm6$}^Yn3$OcN+fi^^!E&W)yjFgTMX8df^Kwnbvr zAy5Q=Lglf~Per%(5WANSM6C=wFP34dt%y?@XWN&AMd>a0i3#^lev0+M?Hz?=;s2~9 zRK@R56Vs~y3Qepq#&U!Ws&fk+HEa+(SA0y!`0xsk5Dj4$?W zLXLj-27y}JkfK56>3eDPlUa$AXGzOENJIO#Uaif31ev`bSIjf?g?A|*x1TOTh0|Vv zmuZ@7Vw+y$5nClpB7nzcvVIpKJ&bi7 zEm}M_|DE+4JdQ*5+0Nxx@&wFp!cMw2zJivcC-k0(5w=8S8eI8gxuhtWooK82I79%s>a?;TEwXdBR{#X4M#X276 zJrX{xgB^{vAZC7*!-=~do#*N5_ zjOAg32V(vB?2ioTSa_OiA9rzLYKA}RhtGUQjN?#5cwA~vClM!db1=J%eIj2xi_YR@ zravv)M#?_dS`iPJ8I-fnc}HkOM3J-E$Y%T&=&|yim@F#E{CrFh0TLrK( zD5}yJ0dsdN8jituo(2unRjF5dZ40}`jV}=Y9D!(!oE-TF5#gq3bM3=qfh94lHA?OH zq3dB~|E~}Wca21=<%GfSJ35#cwY^z}6bgGe5#(wW_HMVMJ#Kkp2h=9aRh;FORPeQr zs0sq%)a0$fkeO=29OOP+mizGh-)n-2UaDZo!Q}tw1p&_IrC||ww%TFCa{@%etJCTy zkBtDxo8T6_8nlm@?XSrS{=z|hAky-#YP|Gaf&)P|A(xq#9#2mesMm(7Z0bT_A-K4G zs=eVJ(Yf9jZ|)iUXQ6O*;uDo_VAg|!Fqys(7}@i_??DX6y=%~QhxqzFxY)DdQWLn? zVqb)tHWvb?fA>$(g;V7kNI;<0ny+I2$KieMp-O{yk=FdtZ1^d0oONoFB$I-SHh{mc z*mu<2`B_}+6c{(ZIr19O*IAQvom=!WOB{|x;2Qvf40XY+7C^Z)sN<<))XEOcosDJL z&fbKqsJE~g65CWa$hsfxr+awL28CW|#((q-SUnsW>}*}=?fT0Q+L(ua=T5fR0Y%jX z-9yvuo1e9N!3set+a%Iv%#Iuk>BX1C&-pFofn~VOd1WCezj}^v3O@g|#2$(6_Femi zI1)_fhylyELzQ15KYD0f6a!e0T+}7$?W2~;$HwG-Mo9FU4i3zp#n|LM=ogRr{PD>z zh_f!-2f1Qwo{=qAkb$b|wv48zR-44-I8 zF^)u?cBI%TSBz9e6#rgz(Q7=t5osAdlw;mFBT$m_JuLJ4E_(ta^8nKME`iMw_%L>= zEs}I$t<=4FTZM=jrF$7fDdp%PrmAi2I8feG)Nfco z4yMF=1{1K$NX>qViyUVRe4Nt5gU^tZIxhUXRH*N6<@)<7d(-DJgr=+?vBr|sMb_#~l-t3Ku(@-DQvFjq~Pw z1Vr<2@j%LMb?WE%osG8zJi4dt+q=3}{N7oivoPd8dALlLbh!yUM5OtGhcyKwqnKqR zcd|?25%8w??5l5uHGXyNR?1V^X#b;ZU@?tEkRG7KyaI*pK^dm?laVc*%Q!E(CL)@! zUKIoeO!sA$aW|X@;n>3DrKE}WGLER43{r%-fIaXvuEXbNSRgrF<02y+kmLgr!Okdh zxG6p(dpXfL{3VVOGJ9}XupdLdJgs2J7xKTl@UO5y&WQ=N5LSG0c!0|-g3JK(-zovO z!oT-2>p$~~4>e7b{Oh||3=pmi87-r)$P7EhZVm7HDVC^L7$YqUki@n$>zhYlhW-T8 zlea|Ht-_WMFJa)Og$zV%0={!19!SN&Vf=8OZVJT{$Ea2?FFGSkMMhMEQ@Ek@kHLbS z+7$4n`0e$f-0r}b$1p1#U*to+m3tV{yA1%QnkYjETR{4Z5PD5pj@UWMFPNAWj{le= zlLSAUDN|zFkV$R^y@$K9Fd?=E&4BDRs}OBOm&)rG^}u`w@?=FUYfb2IfZ;fOHMIB4~!Uko^}^I*14 z8pon|7kY_RpElGhx<#-U_4sRw{Hnq@(VY{t7x9yAE;*xYdQo2kuC-2Z?&?E)roiubiseu{InCxi0I>_@f^*mIGV%Tg%< z{i7x}-l30l*NS$Nzl@CF$dgzeQ%U;Aag9H2YUt(5Ht~R~ABAV5al-bRO7)o$zOv(Xq%6>j2?}2AJy=L%#6PG@AGtyzc^~}{|(1u{UG15;5MN}4>va|0Ko4~ zsO6}~{y{*zWM?;~h~`sc?DSs!|9O_|5TR~1<@Po=dsMkEc}$*EwyW*k&kHsFfH*ia z347EjI>0W-3v91fy0QDT0n!DMJfg~qg@Bbj&P4sRL$6(Oz7qMQQftA#`V#)-4iNUV zKMgcH+~w(Z+;D$>mtO3Fj;wHzY#FleA^#0BU%!)PQeT;oaXuOCWwx$MU%r!xs`Qbh zV-{ZXiY_%T1uKA8PR!9_nxa?9V%J(Am?ljRmEg%TPug&-bdA$XDzB+1owh58{qZ;A1cqu@G`ZWoVV)qO;J@#Vh#iG+OY;8c*v=c}eRT!|_` zWlX1(rN7Li)Wseb_p{|_h9Qs4e_hL)Pg#i^cT^VahHB~b>rkDE zJS))q*mT0%&{YM-P(997eOzWD(byK5<+ms4Ly^To?5Cy!w5s!xLL;-Y>i=dp^neJ1592zPN@NN`;vxBh&{(YEYNU?<_J;M9copi=Z; z88&jP5@Qr}wTc3Bx@-Cg<f*+^xp>)kEUX_+@O1ggI)(xZubqka08ygnOydHC5{@%&97&j)%W5^mM!Erb1#T! zokP8a6V`^!H+;@N&BIM>cE0vsYHF?lHoG4Qj{%mRcN5XiOH;M-8f%H(m@6sr<33O7 z{``ci_w?$ZvJ}sq5ioRwHB9lpgo;2Uy-4?vEE)y>na2UehtMr9iRREgjhUTvJidy& zLSEN5!`BVo+ymO*R*2p&{Bxi>qTFYA*^-TjBbXn$&80lQPKPcRhV#n4p09~CV`5wd z4swIIJZdu<4$GqJHeD5oXidjTt=NC1&Pw?3`Rd%(QDK9X{^WvE5ch0xfj4nz-!Azn z!A-x(uo@|PrM$|8f`-vK`9Gkj3EH+yalPZhCM$KMs+rvgDpQ0 zI;ccL|E2eq-Nsb74d?p#X$MN^yhS5*KTOFM*4$oyO?*-D{lFT{(@C3`}f2)Cz$Al)&Q8hS#q>pyRg>yNtxs|u*VsuA7Z!qk_ zi~xtwn((fmUk0QSfwjHwVWK4Yx#x;lbz-Tzbk(_+sM}S7r9|98lK9N z)RnfUsA~;fteC^Lt)%>;Ga{ooQJ^vW#U0BQZDF)99^U=}xz3lI(>^l;s}^YimtqV|4h zB7*=}b~~YDmlDsXJrtYWeXw0vH)KxJo{f|yh7k(&b*Lk&E{9Cyo#D<*PwJV z=^VMd1~aj37F6TV8Hmne#}X@>$#YMfk;Jf{m0Bc0c6wu{*%j7x-Q*z7%0{(G>}4(t z4YKc_A|Sh&i$c23NLG!4o!dZnHgRvUS3^?UhKF3N-_!Q~wP{%TDCsj_L8e-A zi)G24P<;2|yJp}(DEHGOf4>*NPN$fw{8vxadhPmcP}NQZ{kBq(m1WI4N3Y`<59__% zK@<*ZX@f&{b9vzJi)wU*W3ZzyQO1*9kv};aa69^qxR^YtZH7=pUh(RKndS6bQ5yTh#)j5wJC&PvrKba0a7N*Mh@Jo;+ zPN=2hJQfb@dhAj5{V`lneT4{bpr z5b$T)Jt`lXoSy|;NV^^uVJRj_8hm(46ozK>5=7x93@*f+Zk*JjW!CNuN(+)8x zmSe!E?mbF~m@)MD^`T^Yz=!@c>#w75#AVmw`Th$Vn4cB->3d_-0DFcx3cnn zBeAK6tbxlHzw0LN{&Q>lKhag6cIGmqj3L+epul7+F1pnvzY2%ZGUV!Eu$ z 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%0D;s^qhdxmSwaiY-}eg`AQ|*jeljr`!BD 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 Db%@>`%n=mjdl8k$KzdT-jJUe7z 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 pC5q^OgjvXRkpCZV5hDmpfxL}Gt$eKr + + diff --git a/frontend/src/assets/img/robot.svg b/frontend/src/assets/img/robot.svg new file mode 100644 index 0000000..2d23ff2 --- /dev/null +++ b/frontend/src/assets/img/robot.svg @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/running.svg b/frontend/src/assets/img/running.svg new file mode 100644 index 0000000..5d94828 --- /dev/null +++ b/frontend/src/assets/img/running.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/img/server.svg b/frontend/src/assets/img/server.svg new file mode 100644 index 0000000..117cd62 --- /dev/null +++ b/frontend/src/assets/img/server.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/img/signup-ls-infographics.png b/frontend/src/assets/img/signup-ls-infographics.png new file mode 100644 index 0000000000000000000000000000000000000000..4443ae823e14d5ebd7123078753dbaa2be30b909 GIT binary patch literal 526132 zcmd?Rhf`Bgw?2$rL=lJr3WyX5NE4Ob6aht=fKrnnT?q*_^kM-i5l~ua0R;gO2t5fM z5r`0qNC_o`UL^G1{et(t%6)%-!gppEMrO|1XYaGhv!3-FLm%nfKX>Nx89F+;a~cm+ z_37wNyr82y$$$DJ?Jowmb2Mqc=$#&zxYE(FUOV_XqM^^fNc-avSN;1cbeJ~IU$lQ5 zx4Wx-myWJ5l3~~41l{SAO&Y3qAA25|-Gk-Yko+k0`@eTsHPynTkUH(X_E#-B7U|pr zESk78IbPEt!lIaK1T8we3lr!po;?0^A!ks;Myb^|{`yJwvo{J7$LS(s3O`*x_v7CC zmGEg%8%MIS)B}-J`doC=f7UAtoo48P$=#~;S8nNd!ef5H!QETy-LmSB6VU* zBiE%)vxIK|I zgj4fnyNwI}tD;B$9TV;x(~Bc`q%m3{AfAy^?%{JPbK07o?G^LRktH1`YhP`lYdA@i zbSR*a8*+ zL;U~lcj|mecea+RZe|rJoS9e5yWL|sw+exvCcZ4dSzd=f93CXNn+9u~)%g~**4Ac( z6<2T${dae*_7U3ZI0@JKZ!dRJH7b>4n=9^HmyK^Fo(3UtNeyJFeICbDB05axQ$lSy z7j;>CBI38d4S7{~z}(j|>5!pw2iw5$T;Kh<-Lkn}kXj)6J9lUyxN12-?RW~wk!+5- z4Ipm8ekF}@O>>U&{JRs*dGK~xjTP6HZ&m6{sUy~2R$4p0$GOkAV~6p1Wp7X}0X{^V z1WxgqxNnFwp2-Yfi>itpk+efLFvod6MqXog8MhMQk^83x=d{Kk4LCf>@Z60MBir zu>J1`QoCS~bmwz%4fNLK%IdE)*UvspV2 z@s2np$G4y@gC3gWIZjlCk#0&12uSHN+1acoH+uEygW1ygPI?Q2!Q8>8&;I9ry2Z8w zcMxry8AsmVOvzh$j*bZZVT!~ixp<+{uBv3&96YXy4y|-l-~ShMlD#oRMiO;XH23> zsY`Y3Y>%x5QuZpjPxfrj=?c!%|5Qar_e)gi7zMc5@6=@z4~5?Pi358_40QwMG$0F* zf@_-dAn_mAw0U{rMjjFP1^9m8yr!kAIL0y`AL=~-ny=hTN@h&<9Mk0XL;h!Lbab^T z2M4WaySA#CzNyK!Tw&-oR|cIDMgHgqJdvjVI(h+9?CbN28gK{X&5c}TiF2nOxO6npdUGtzm_vjZQ^H!mWy#uWk%0OquguyF2 zl?m?tZk*1CoG0nhX}ZOf#gAF$a(62#rdBHYh6kR2T484Sx|Jo7x$Tyic2Wl1WDuRSWAC&-kE*J`@2h;f0=$n)rJI{b48t=lG9K_chgER{of~}6FExr?2Q-Q zO>B|5Bn4y*?6wN4T=BP_WIW_MILsiVE@wz8i2W2YEJRs4`osh%^+Mo;3_Un+c@pMA zu777Q(LZC$ix(tyDhV8w?qHAn(NopV{Lj3xHSIj5V>Nas@-urH}78ycW=sXD6F{c4ARagpOZM>ZSA-P%RN=-(~j{EwLE*SBG(E-@wi0X z8*bkpb^L+*Jt2HJyZxX$b%Rd&Qnj5YEJix=`%VhfD9)@><*ml|TZLX5m|2u(@oO1p zYHi+3)~L9FA`i%Mrzboa&yv?UJ`QUy&eL??{aFo6Na7;IwE0g*i=(gpd;TAEwBt$o zo}OhcE8qO#{zO%1QQVq5Gq|cg94f7e(QboNq=Q2HP4(kf^SbyQdev1IEwxk~N2TP& zpjapJkRw53pK8Z6^(-WXPIL-ytE4QObLjMsAC!pbcmY3-jAqv=`rhUC8Tf9_85*u39Jq`>9;)+ECNnt;KU_>OCQG)C|n|l z5kKvtb`#AKd6Yb4A89Cptu3f5ArNyhYGCYAnkI_f4fbvSy0xwogOdhIw2q2!2!El`;vN3e`_x$O&*IL9+}&LUY?Lm`KbyTC^FX>`t{e34(|>wFZaSG+ z`ol%b*V7r#Hmy{}37(RLCwu0J8Qcuq;4tV&qSGn%GPq!mI$4jjQotRQ2 zpk_-j_*xp(sD6;0Z6xiI9MN}G4YwZtx=cyj&n#9?b@kh~m-p;W|9$3Ru~W37EFE_2 zR0=1eC0IbBQ{diMR6v2o?pf!P7A&})go@c8vC~0*a<&GJ0kYWN?K4)0!EZs8g0~5t zA@x<>tLwi|tzRvYpHUMu0{@-wiwgFGw|6z31f+(NDs!ZCS_~_UCq#oa$iAwox_2!ud^iv%%^Zz281nj|r3 zB4l@+nWbZdgYVj|tapb@%CW3?*<{0z&#&qx!UNrHW;wVJlCz1sl=#G^3!eZEGikbr0cMP~1-i$1%o3fBF7xGNLHytReW`Tw zDhHVbZJ`4k+c6YuB_j53W6(v21VuX-^+$NeIZYdrsxV+QuYnrm%8n9e|6V9%{3=_>O2in|L;``K6(5p9fmI_TKvkTi!A`` zr*Op^q`Wc{l#Ab(l9!oiS*YE2!WXM6yVUrPL^SX4}7T`rlQ6$MSYn;m$`TbKkZpeaaK#T~SE0S?+-`YvwdZc5U)=|Yn z??Ub1U3lMgQ2b?ePRnUxobQ6S*r3!a9=!`tgZSeZTxzPI*kkChfEf-oHgF~BS(Of& zJSfuN0|$%yHg=S=;%C{wdh_@ z>t@EG!CSSl3)=ajDLj*;#Occ`K6~p*Jy)Yq+G*4Ljg2y=U1ulv@S)G2aeepE*1FFD zghJ6+*p~CFvU<&lMwiJv&(39SL{9#F2#PFaqoOd`-7vIMFa58Y42#h*(q0OinUUdE zP^8%6JowBOR*AuQ*{RBtYQ@R_T3XJ%>X=keDmI{HFmEF#GS*Hj2WSli8b`yRY;X=Q zi>*51XuboEGqxkr>pLR1VF<*QYBXCMHZ>>qR7K|Rp2(sHM_2y-im-AS`g_Y%_jV{b z3Lw1V&&t!$sj2-49Om@SYPIMEtg2gxTQm846Ku@t0-o+l0di>YM>&tY2 z>E8^`wRQY@;xBr5A%FSc=}*16&1vGEt~>M5ohkd?78`>cnsk>`!Y1se;MDeCgN2eWlm0d0PhQjM*k>L|Ku1w2noj&!Sb9o_u@sD|RwdL=-owDYB?l93bZ#|FxHija9pM}l2 z(27!55<^qzEhANfRB3WtlAB-KdE1$ZS?>*4Re{3#467E?C+U(9$x^aNNQ_6&GR(eVJ$3311lleyZRRKRLeQsVw{A>2v2J-i!9qFD@gqUX8UdS0!&?GgluO;*f=lrD< zzP}5-kUvX1zDlV7?6OtW2NPrxDD;Drp2>ylR=KaNXY_;Ep1_hmjY8+#VCEzhXX3Id z6st73WV#O*9oBah#mmB#SzocCo39V+C#i|76?~`X{@QU7shg`)gXcZ8$mxScG-;h@ z@GMw#(OVx_$Ahpu%R-nA-Ur!6Ns!g$KV??-bAcWj8#kgI1}WpNURCYnJlsf7=u*)$ z;U#8?DUWC~PcL3M490-T|60ncI7_~g>JmiU-$m%=uhQaUQB32x$Jd7PmMFSQ=4Nj9 z6h9`l=jR0(0zKX9e`b6>CH^3*0kHU<0W0zxT}j1DZzZwW%#rm!-%CP>SYp^3)7e4t z-h1O-CC*W@HSM!$5Jm6poWt0O@qig2op7bDySSQd*pu@k9GHw?7u0sl1KbRp~4UG~OwN)oQLCDnU?(P{t`=EF}A8 zhiYquFxnXb+qnh)?&yX5pNz=Xl9!_?7yWgDGz%($9S@x7Ph{YX2^U=X*i(YXr~ar0L_MMiD);AJF74{*L0a>ddlw=2ydc;iA5c(}5GlXT*Pa zv%%Z*W`la-2ZTpmT_Qm4@6So~fkfoPhN{I%od)x9`2-gSHIO*rHn6zzeCiQxv0=8z zf6Z+zjFAQ;D5COi*=@b8fMPF#!@dba%`1S9D67e_jPWy4A+cNZ`2_+1c= zZi6Y@6P+%JD9UeSUuVtnM@s8VPZAgG*nOsoPS+&? zyRDQ9K}^m*(Zg%WKdWriD$Th9W+to-p;C_jSt9a0cz%MkUQfZN+f0U;;YD9d0(!~c zd?p6hml%6Z72w5geX=jhLUW!0?Eqg(5#!tJVU%%ait}tFsi)AR+`V;q@-CBYsQZJ# zx8q7nrk@!8pEa7+g9zf0mLn6t5Er~qd}o)jYhU_LI1Gfu_X+0%MTklkzf?-@JxP>{ zud*T`^EGX{0DWpN<>h?RuO?lV=woOw*^J|~hPM^7p+%0l2OM>j#j?AX>WKzVig zSH9)pN{{^mlHUEaN!ZMbcx{|^@d*G|NFOt*Y6nX&pg83=M@=Tn=(uCuu1iRJ7$lS? z;gnKh_z2uD~viYa@(=WP#-ue2g9RFuGm$~ad%COALK;S6Wp zeOm4Fy1vy9l{@4(QWw{z#2Kfn`Ffk7s16G`r=de+6aL(vr2SOe(Tf0WPq4Sdn3cz$ z2Spp-e6i8Ss>Ab;XL36VUqnEOr<$<=Y--kg0gj_R5ricRJhD4}SsYf$2D`ReQv*?gO&; zP^}B^HM2NMH;Ww0GT)~NvdmapK;lnVRsY+3(?*y9NnA5>}CJL!rDD{J+%ct3KFYj)+9XK2KKA%mL-{(z55EG zq%Xig(j|fcSoLkVS5pTw7rLby0tvB|{s>mI0G(Mt|M2s~PwgEd;%Z^FDUq*_(XF@7 zWTW<7VlHr#hkBBICt+1$zjMdV+v_ECX2NDfhP4N9196uxEOq8PuJ};Tj_r+~TzU1q zf5>PCZ{+W|pb$sBf|DprT>rcibFxsWdanV9J>-q7Cl4ABzHf=Y9f?qC$WiB9u`(B^ zbMZxav#&jzjidhIm#VT|meq|M=9a?&J>8f-?Ar`Mq}(mMdv9a%c*u^_S=2U zrdIXNj9WKNz<2eYf;%h342VIeJ9IW`h;+(32IwFZ)P{JHJJ$%f++DgOj5(ezY#=92i3DF&ak@q-WKQCfkRo*iQn9;1d+}l!Im+9^>p=#n!&^CiaA3F6 zZ8s~c-5GnT0v|V}<}F2MH7u9kpNelyLYesWH%)p=oL6$;k&OPfHdtV`VEl2E_?zQrO=&4ZeXEILHXAf;B?N2%{c3ljT zJNlI%p{4960ISj#@9g0$SL*pFew6SmbUJE|J^}JH&Ia-pJLWP&DrU9pv)RQ0swmAvLATz8Wh_`(I)p)Ri6|npL7jloRmuY zm~vW75FkN-z!`=ji5+Pan_BBNl(R27F|>=kk7f^{tg~i3)nn9OsFugGqJ046a|oTeKzD(b z#`u#t>1Z4mVe0J8@=W`E&N>4HRk! ze7-sE!o?1N+)g2*AG3jK$C?~Ls%zj;td&A6T1_v^yXOLtxDzaTCF5PBoKdojw zPKt|c>Bh2_y}!KT*mh-o?V;EQFTj##@#$()^!{~$z+?YO&9$N@0CdA|3gz~e8}u|3 z1YSXvw_kiybyOtGPtNVEl2%5?9rk-6A7aPWnx~Op$OvYFRl)=40@Rsgx8P#*ZY^S* zUGsf8amH_j-zhW>Ya$2P>!0(Ho!gxrnPbQjJH#xB(s9yg!w2z7!o2oxuYV62bEA|r zW7qUfT@l~k_6(7O^Prl#srA)w-Cd*rI(w?mtCjp+N~#5^VF2J+S1R->mffw2+pJBY!T%7d2U zOxurX$R>64aClCurwt=V}3h69h+DOACF*^&X9LcBXGLGVmU!=Ti$USzS4yekU3 zGVwsMn2Ji=-fU0D*im=aB5Yh0ay(NQIlcaCutc#MrV%LWv^eb3dz{R7ga&Aq?Vi8h zG?n-9vQWWGQJ(fYu^6?^CCSM7Q$L@amx%y~+g(I*^pYzL#l?0Sx4oFV8H)B?GL(Ff zHF1L+;2(w&UBc>yo=40uPr$l9?M=yKB_+PnDMAI?VMnDqaMbuYhDdWA>gw#OsQ|}H z#|eQM>}U?mDnDJOFG;Xf_mTP&PLgQK-@LGcOX3Oy7IRgglO5%x+CBV!^;}AiXl}3$8Q;Tl-xO9U)(jYRYicG1_ zNiZ-c!*J;hD=>6DLTa(-`)q?71f)DC&MUFvl=2@hrK6)*9YC();WazpOQ$e}=`y_u zy9m_>GiM`As@89XWsxt2!V=1YtP%u9U2a`68#Q&3;*nIpS|V{;GtJ>`>Sw;o>#X^E z{>v%Rp}5d0fQQKgM>T}F(tSHDmo!8g-n8jttRDOJZ;7mP6I~OGGD?7 z<9^9n4$39b+1<`3ZWbn*_YkM@fN}%v&KbGdfbUK9(6!@Gf8O#v2LsXvHsT}sxD|Je zhMD!<^+YYl1(@`LK_2(COZj$s>R`3g%*}tvyYf`+k+Zeh{9L_?l3{O#q;bEZ*!z%A z;>`;ic;baiQ8febZ`LMdZXwg!0<5#6P6zdH$gL)V8g1UEIDb5NqT5@chw+gQ-9bXVIly+MCfS|z`vJwL z<7Y^8;aX33$NBfuU2CJTw-N=rgOy^x+WWzkkCpqRbRj@$|Cl(k+$+`aUE8<|DorRZ zkdm?8UrN=Ev$N5kX?V2RG#N*=u*5>5OCX06&c@LL2IQ1Oz*Z>0e0l&A&Gv67IA40^&F7OIVm1RKhmbI38-#7VD=AizJ`*^U3b}vk*K#222|b+Sp+v-sF9_8nUgpu`_A$Hl&oTUv>ygr0 zkAQ2^5|U4pp*T^Gw5xG#P25PduuKn692J;})MJLBXUaW0NXroocSR8e-f!4LXjoz) zAmTq~M@I)|IpE&T_f;>}XXpj{`g?N$Ej5vVN|Wl@-C{hn!8tMU*>NxNiHDc`eQ4vo z528y^PaTdzM-6i`FQl_$uH_qJOT8b8xhS8kV<=O?Njnc^b2fmHoeyHC2Zw+pV36y3 z8OAbOD&h+!T0FWFzprta&rCW{GEkuIjMX>7!cg|8eEPbMK4F#giC>w`idy_cE3XUn zy39c7&_a%6!t9Ah0a}t@PrmPMd+y44&mL4uxl5Kyu6i_&TaZo2h>*Y;%@{C@DvtDH z)8V#-F*bya;I_6Auiqs~_y28J`pAKE5**Aucb5ej{iVbtm!2H|k-~trH7Nl1OF3Ui zG;@9;kTDh%+Utu(HRu8$(688wAH4L)FfM{pChwV6!>P*lpY?Ff==QZyp~{LfMas`{ zXNmc=ke@l-o#Kibht^^jpsN-AI)9l(?>E0QDeQFh^QFzb zCMpKTTc%AA_X*ON?f)Dmx6VuQ3A29&v>#A7LM}~dpLG2e==9ere(4}liq;7-rXWXc z-1EbBq{UFA%Ezo55Y)Bow*2t69;pQ!YEXF8kw&`fj-bpYY2(6jq4xOe-heiZ!K&AN z+!buUhN=8|7xT=@&@=@gd*+O3PudF0KDikoqrfTSc4*WFzj~l6Qp0chq;5_M%2xlt zyq7r*Ph+vJD@?g#<_OInJMOA?qtu2ai3weFVcCD|X47yUP>HB@^jUs#3KO+Gi#6Kp zYhQ9j>^H2BsIO9?w!RVJ;rD>&R+ElHTf`^(P904?I?u1{Cmo114pC?4j?&6Gjz#`d zD%bBS2g`Ji_#R8EFUPy%znVE#;51`}vtXmG33UR=>Nwa>@>B6~`1KrCIP_%?!`D1x zn8f+_6Y-(bS~?fNO`#Jt<@=?ZB2@1PD3b7u`mxS6?bKFnkJq6ja`zyKuv#WEiFItB zaIMHxe>zM54svz<{kba(zH_Jvpzy6FciCuZXURg7(nu{{Tnv>1_`ysmCAJe8{tl|T z^NF=7{hPE7yAk$*ABiT7Xyel}b0-5QPiFl$)o|p`QdT=i-DHl5I?YaM|J-%U@zsZ_ zo$g8Xntinf$@g@39kRzRH2=I>lE^N+g+*`%YFSUAwh&6{yy}X^Qib_cms!;sOck|& z{{ap&?AbE?6wcLMYAzXCwpd&YX7t@n9%F^?eeC-G>6$#y${9rz+ zkz2(|$dz?1b14!)Y+#u$K9{&9Q=XVEj79BnU|s=g{J5-t%a~m8$iL^9CM%p|z}5GI zsE$DqHah4Bcivi;xk_?_{|ibZX!08;O_yDo&u4kknemQV3+sDZLd4{!zJz`+5{v7M zgNpS-B4Ei^=h4M(N>vk@#E`UaJq#@-{B3m}cD&egQ-ajB2Rbj{C&p4dTOM;8V9da& z&RY{}-T$w0K<7^=JnZi~C-&6!cP7&jy#-P^yy{M3I+sYgkqgZ12$$f0ZB-qV8zwb|#VqD#>G(b&_kzNGvL{ceqW}ane3>92gbtSCww!-;797 z9d@!6;<~~}_Be!yFnoVP;(u}`kFQb<67W70iV&hoN8wrR5ZcTkW)eozHd|3WA4Q3C zW$$W)siXA>Sc!_urLSvSB}8r2bpl$-Rf1t8dAGWiSw-uFsMZ&PMU?c8LzJsJLGZ2A zdfiOSc@4WOd*dW--oKGgqg4*7xQ#obl6=_f%k)e^P4z@QCQzBKf%Jw^k0^bUgcxs} zxg)f%9L9f7oArUuJj5f=K27>}|I|KKwyu?zeujhmloSInp;1Sp^Jo8iwT}?iBbLTs-kU zv8h$-Mz~4kzMWg07(=~4a%0G8@sz~Z#+E!?>Pb?uzrc8w&L2s+ZAg3-m16FwHK9W) zb=Td%l|l*sk2*o_kFzGviTjNP>0R+PpddYGzy)z5P(YOER8JHV@gbss94W~3vM;$B zo_D55UtRvvpn#=1CZvgzm-ka81XAE}oj||HzyEO|4&Goq&-u+fVjKgMmbggE0I7G| zEh;&Q5)doO;UPBZpeB%6bCsd_vetuPiyS9<>tP@jTNWo2D2F!&%bPPkpLs4i+Y9F; zit*mKk(J@MHx4Z=FqQYT>QYg_Mp}QEDQ|N3%W^{ZRU})HiQ4n@%|$T3w-onDPo4W$ z6!(4}qG&x)H;&N384R;(yq&w)jNDpPM_dPGi~+RJW&DnF3l3_TG4<{I zy7eHSSooJQhUIEjRn%ZrcEYd&J@X^0l!91;`(j7mgn# z^?iGyrRK_56u_16p4<1?t(QA#vp<)1t=*Oqd!k#K)+goQTz&AP%FgHQ^nA4KZt!sa z^;60pVKcf{c5`=gVWMi3C9cR_TQxlGvqzz=ov0Bbg`I(iuw>(N9}c#49L3Mxh*-r^yNYgrxeS?M!-;N!KiSsm;&Z7o# zPnNFo7_9}vapmaxuZ?a_`8X&8(nX7tUFG#E-b(8h#1W|zLzCN1d{Rk2TEINs0c)m- zs$x2ulYAV$etXqx<8DhJt!Egj-~@?OohX8_78r1Du|b#5PYdOE_A5ereV_ZS1#{OQ z#u$bN9lU#BXR-6$WcF|`Wh?nLYnXrC?If~R4|2>S`hnT~`+83yrY8c8I}2EEboO|=bju_PrmC|EyiVsZ9i@+y);+}Dteg} zd;bkhR>1T3WxjwO5QcCA!_?gwS}(02w9w!@!i*>ADzLb@y;DMw z+ipZDZL|J6*;&8=Hv;bS8?qw=NV43y=}N^Pa~(ma^MDk;BLiu-XE|Ajr7$ZV-zt9ZH21AZ1aC|G z#N&y9srQ1&*5|AN;7h^Jdle61QPQ8T%wUp!BqRlQO$cv0fe?04XD&_cgEAV5$86_9 z22j!TRh3ugw~J)8_H9*)JO;O2HP9h%{N3TA-e!ZJAmosdWlG?4OmbV*?y&Lwnig{g zoOT#VQL{qJWIPt!Tq?9NiwAl7U zr)rJ(3d44L4&nGpD#t9%+vLK#Z0FM(4MUgBJpg_y>rLH6Rl5L2Sw3UVwxwif9Jt+j zo}vSHx;Eb?oJW@h0QjH^%^-$LJ%@5$FYut6geQP&pZhh(@x#Fdm$>^1_}ASTnU5QD zr~W8^E{!s>V;m?Fxw<15=Gn5VFA$#8(?s{{ z^wU)Wmr0~sT|o1QtyIpvfeLJBgda`cdKiH3JWUn5OIMrMLX&A!NrZ(GCiW)jN&H#v zH98habgh9uGclgi6xmT|CVV#nU~* zd>*LI9Bs2)#Dh&f69lh2^O(Jw3l2OL5I~Eb^N!{+h=jk6Oeb|9+V!AQSS(%(ggPU; z>Th~V+?LZWqfUeKqg`9WjLo2Fd34kjZy3vMS6uTpq^BSco4> zE*#>+XOA3kjXeKL{MoXoWt~2zY+;7hpe}VVU`sA)Y)rAw%iE&X*9a8dtt76mvw^k` zAwSj#QP55~_s}?WtIs=hS$Ku9VRIffd_quc9DzMXeG^08>f0$?ht$%j1YAV*QbuI8 z+P|GM96&O3U0Y-dSLu)}ORcYu7$<#Y)c>^oj4(?gTzbAoH;eQjdFs8LEr{6~e*nrIH0 z=ehS>!X)IEJSgeAsPX8;ec9wUgNKI61%E0!PmDq@n{`x)Y5gi7I`-P2afk?99f+A@ z<0^s}BksG5=I0*`#-9|=Y%Ub_AvL!vQ`v({Zb*PXxl7;wD5q6zDC-I>ly9`%JbhNa z8lM}DcOOG&m`t_SIZEx=pLEi{OMXJxg91hFw_U1JB^YLzgAQ@nM-M#ybuUfQoy_s% zt0wQKuxY5+kjaPKG%iaDT(m`<`Sz1KC(&~C_aqQ*Ja8-}zWK>nH7e)2*i%5Una83& zYZ2&_`1X1_a8&ktktsOts#POkf{Lz!uv5FckmxyEc?T$0L7XZd}nI+|3rhV!rhJE~agwpn^k;I`IT~5P0G?F*fpQh9XV3sTP>m2~kEk;Xa z$`WG>N&e5x0S%(Xv(1B`$Z6Av4ptYjq!}sLEqV$zAf(|#N@gyjx%ysjsT{UQ_jCY|F3Hef5*PB77hcR_i(gx{8HrZW#PBy`muyFvbJhM zDa&|<JcIYr>8*YkLOM*5aFHX0$4J!oiD(ulbdU z0%KWI+_t9uMS+{gmgO?+{C{Qto)`T01TqJ_aaIv+Ft#*ARD9XRP~#7#lC|NqZyFSy z?0iZQ?nUB?{6vV~vZqubVHr$%I7|Rn>QyRDsiWN+_hs*KrMq}Trly#vY!lX1DA_tn zu_$-g8W_!0t=3g)P^30H6K6gdVvY^tUydduP)#P|In48aT|G2nx%0;j1^*C`EUCl= z)1__!_gjUAfsfG}+8Y*#v+WCCQcHzN&Bewin4PRd0lIw^c{j*$Wsd`di(MAWx7DZe zQ$yep)=$l(QtkAf78`i5dfVN{c*E70P@}fYh5`XZ%luvhB1-!DbH<`qk8Q=M`lT(Z z>n^iJSzQ&=v#zVE57q8WmTWKnGBW(f={=2o(3ZiUo$PqwA-i6Z*aeT>Y7S}xoSpjP4W-rBQIoMml_3$#xfO@@s5CKkiCzdJ1+CNu9GXc3GG zyk{~<>V1o?O(@`7ho$B*i-5J1bu1P}?JZLoh%`&+h)LMTem0hGv7ZK~vyW1mqP->0Y* zFC_fR2`Fo;blZB|`DDw%Zu(^F9evv(>NRc^KEJ6s+poU6&YQJgciR6cvgf@I;)Jch zZzNPR9kQvS=w-%`HN9V2399iGij++G*6Lxwiu z;q{wllmdAy#7g#MWhCH7`(YXKLDCSj_%kK|R+f0>d}`~rX6(AzbQuAvU6I$*>XV1t zpgp+EWQ9(5R4XvM`w&*5>r70R;?+DaCP->gGN;r9dJ~~W6zir~Td=$Pxl=w%BERIE zw|%=8}ox$rJWKS+Q37V=`xYmc8uzOrTl;=Fc%xAta;jriLs7~%4z;B z?)aPoaS@o-;t|BNB+)s8B`T~Cq0kCkg!$sYW1k`<7O^u<0+m@)*~7LGTpS~6`n=9p ziU&yK$_$Y{CsvT3S8+iyt{YF^vm4y^Gik0uW7$o}dfAk#*dU&)ZXgl_`0a>MGW@6x!&mY;CjJtZ~=X5A%_DI;GC5)EG;?xxAzp3qN%Z;FWBcfyPF6+H- z1RKXjoISM=@Q;Y%`k6)TnXjz~i|~L4@K-peh`vnXEBwIV^?Usgi zSDN((LU1;{(ulwT?NLWEP-m94iO{i0Hubw`f$}TM4#{Kv{m#K``C7qTv}$=bUrwiV zYG$Ki!RKimatnJVWd#KX z=M5gxk9lw%U@(RRfj~af-{zU5YmQPOk^V>VQ3O1S*M1J8{CPB7M6Nu=#><|TU@zHru@U!;TR}K#| z*n8qf>OoJ$Q5ggMUU3hGAA=fr!-yuuHb;^1=m3`x!OWO^udTPbzMHGU{{&~X;DgD> zyrDazqH4kYopm>l=nAsCP9<5;*xZ&}#H*sGGAB9M@ zRw<1WSAk3P#VLTDshPYYJ{Iz^nOArt~w+;S!Y+E z!quHF=_a{6$woTbBlr_D3nF2LLu^gzlzZC$jqd{r2i!bb#?Jz@aJiaKtGZK{4;5-n3Zk zKYtsbX~LCXq@ep*{VUo`J}AhaGccAr(xiUqMjt2}{3PY^caq-BJK&v8@8~kP0iP5h zF67cy?u#5_J_#NjlTDJH?h*={y^-9f1=>V)1; zVbu^F7NcB>F-O- znH#=wgVlLsW(Kcn~k_B z2UGNah}+{f4O!5I9FWx4!-k@9eREVRF4M2Y;UPEfQ*YcL*yym&%_}ctIb%&;Yqv=z z-!^?owsy?G@Scf2ojdwn+eEx|Dy^?^d`v*~jt*~@X%ma)SB?517r}G8rSC>W_T$R4 z*{RLE%Tqax&$0Yxm@CVYxlw~*AJCbhlg89*JyuJcNGeG-W^5{YwYIOx?<$wfzweds zW3&oJ7Y__fA6$)Gk=K#H@-Texi5*evYx>1O62K4zU)|6vXec^U^d-Fr?}yxoHQ8vV zUK{-=m}&D-{d!2qLmo=q7i}yotc>1)w}3S-EBmB*c3{|77Ey;bi1?kUvG&9heT~B(~_eNB{*Ql4XM?w3v$9C*LB4#+^B&|PtYP&%! zU-68tjG`y=->!RG;*ZK@uBfGtsyv}AZ+4y4!g;+&#s?{wd@n@Eeki6M55lBh3N5C6 zp%c`({duP>dkz#Db(+WMs-)2~Wcxp*()=?T7NU#M3sA6GXbDP6KPP4L1{jf0e0itf z>SghKVM?FLFVQrZtb5O`vMx2z5?%wXNRCWMVr+zlvu9>*_?LoLCgJu zy4=_mK5w))_PJW^$AM+ zNr=ALOq#M}^IhsMYOJ8ni>&Tz%a@p((J=z49gY3p?QSgW?xB4G78lo74okY`WoS^I zPSyP5=Fy8#efL%N*-<)?UV(?h868!DSz|***|sGe(zbfUDQM>f_B9J{wB(O&0R81?$Zc zM;*lGM@I!&^~&WQ8@{wbKH^5EerIbg%RSG%+p%{@M(V*&D}8h?=NNQB4@>-e#BsY{YT}e)4 zqe1a_VS^j1a|MCsrE@_`?t)fT#EeX^^&p8@v#ces{@1L88m>8R;^F6sr@lv`srg5DlMCUa>k%y&U?w#23(Ub&bcExIfrLc zuKXUneCV?vvNH{8)7?H$1l-K)ERKCmnwVAB>#gvvnx+z4<_AR-+Lq4nzcF{G_GwQV zwv@}=N{shH_=sK3O8VW3EX*^I&S_AS#NNxnm@N?0Ky8-A7x_owF8SA@jMh7PLs=wq zO$a(&v2)qUf$c9(^Oiwg`OfJBjd=T>zoClTS3we98uML!IHEQQ@%z6Rfs3X}q!YQJ zeOh`3nS<}roi#kJhyJd89K<+3oGVe3^gXZlS+uO)6rwl-Rh2GDNso&3VG@S3KFo3< zL0kEyDrm~jqUnNh^C{2>zgL~VzU0NneNh)fcGe09)5NImZgnos$Ef3uP_bsbn(E`V zP-52%(L33zQ6W1}evXmX4Om4Pd+@;*-h#qh+0Hp{`R~(-;kF~RLRfoJfX&G(Ho3F( z`0PoNeS)-DzOZud)XtZ96I+vF{u5}2aO41jlF#?_i$zb=wbcerQN7z{(e~ZhWlo%wNnX3+rN!Ka6T-M*uByR9SCq5g1 ze^z!K4^@K!W9N>}i{+d#ZZ zsyQ&Sl+j$GuSZ2xv+Hglq3z6bXND}^lfY=ZK6$Su?8kbn7)n0&)>(lro$J&`xs{kJ zqj76LuZJ?2G>g6}a8E9esKk?cz7y}!_S%cBj#{36==3UzWHB=rB$^wnWeec#t8 z3MvW`ib_d$OAa9j(u06>j1tl{Fmxl*-7$2>jC7ZDOT*9|1B`Stzv1(J-}!%@=bU@* zIeYK5*IJtoX4op1N6?5}5@kJ&nDkH9TmQ+L5UY6ey6gK^Q~t?q$@$&#_y4+OO^IoO z$B31~o|C0$J_3Rl^>SoO1s%x4j6-CbuFzZa+o|EYRjkoexHwu6!EwJ8AADR)c;&Z; z+-eJRl`=X1c~%CfT^ET0!Zs@jWf_c*8@cOG5HG*8Cg`cFm_k3mnI1X{<#&n{j%t!u zz2k{~(bo_xZ0m1S6Er((KHxU5t%vW&ca2?7({IBpbf^yY_Ppa%_$B>%#Kce_*efYg z+?X3MA|Vq$JebX)Y;i-L$EL|8=-M|Np!i!8@65vrt`X=G(Q$rr!I=Ma1$Ym6+7UAu zqJsIXMS1w8WV*X|w`Z6rqMi6^gG_G5l_Y|Cw?6hBWvF3df5NUfK1nr>7kCyZo zh57kEmXvo1ar281#H&x;B|2FwkKI*TW-p8bTu)R#o0=gnM88h=oI@gU}G0w?#ONJr^6m&jlu@P zaVi?n^ytg_KJ=|TTn)X+F}x%N+#5PGJ->`6p1I5MzA9h4N4oTI#lV}@lOJ&-!e0zp zcr=Dsk|NM!p9hF}^}OSsaH|F@KC&??o?#I2^t3wRXgZr;y7c@n3$IhSzq4mZOO#t2 z4fjNvch`uD9Us2(C{yE)2K>-IsUp``vo)#Q`(_fc^Sm!!f)3hR)Knb|CkY+DcuHv7 z_lHD_Q8g4Y(&GgCMku-QlRaGW4xY`P`tHDwT@UB?L?7F5aN}%i*>cH1pOeC-9dNxO z={7>*UjiQ87=-2Rn?9(2Tn~LZOD43ncyPJ4 zki0`&+>nFC5|Ln4#<3-){fw`LIDaX;lsaU>=*FXt9p<-#+5eP0g_T$8>~2hIIUtB;e?k^L70R}ogSEdHAon0_ z0~054a1KVQdg=_7-n*e;&?Q%rG%MqrSjKKGeDPYdHR$OIWh$n)%Ui>g)XzdbqM zv$e3U@12-ljZcvoc!bTiW*JGl##FGiCG?HTHrMT`;`ORNVQb{XOT}bMLN1@qmYVW} zT=<@78j++m$};GeP_))}ONH~zI5UVshHb{9^WJT!I7MDH(s zPQ}IS&If>x=~?<%u8v~*;Fsmjr;1)Zz_@rZb!vrNlf~E2ZN>0>lWJl%q0ZwgtycMe z;ecq}o=Us7jC`?7zp9mgF{vNM4hXH4YD@^F3@xy3CG&b7TPA-Tf*4K)Tm69tHE+JG z!6WR{BYjNhsZ^sMYputrM#@<r1=W4 z);u%H9+tA<$*F(#+n5GEq6xDdb1NJ0(kqK~cm+ve?STi)(p>!rj8_sfHO)v1QG%ma z#BXQrua0Gy;qYN|gM%NgLHPcZg`VRKg3ugxHhVWm%vWE=p96E)P)#d|FS16H(VYvZ zD>Dp9I}GC6C>*M&d!?55;;p4R^y1=R-d!8?zSZ5vhmrY@&HC=>$?sNiV@G9dTQitH z_jkBO2=6~n`NWua@cmPhpTpzS@72kjW$FI{I=D-McT{&=z#lrMHnq^{teSQOa0QZm zgUay$hrFgtR?_|+DMi%un0+|!YIN|DQ`=u5O2I^tx!4>Ng*QwT=x$Q6 z7A4F&4z%*M0yEZE%FEl67_0%@cOpb7R;x@m6@1B+3W>cq1bNkIJ;8mV?6d*(XG;Vh zg$V`GClR2fy8&l>^p`KkC-^(DA7P&359Tfl$DQAVCIx|cLGn#^d&rDy0Q|q|sm=QN ze_Q2k^g-1hmDL-~1O@yE90D$lF)OtAlj=7}3$f2_N@`Vl@mfU3zld=dOz2w#Gjb+w zWHWlyf2Ale{7bIC^E_X5K|}~j?3RaSy0WoWslYFFxcJOHJ3K_*v7Y_D-<2N-n&nVD z%TEr0T$0mL`pqS!VJF89`6PZdbDrAV7r*+`6Mrh=97Lz~ujq!jTz zdTijVs;wfC2}uLRY6(yVQzv&(pW_Nix5ogPx!b0n38dZ!YRmDO(HImH|M zDz&9lq-H-x<{aF9dCE1&2suzU#=ck3Ec4%2u*($oH${n&;Q~?nV=Afz=3y>OK|y^6 zb?T(nB+jv+Jee0MX|!eri4#O3wh8)@+SX1wKX^3ZNHSIACjI%F5*ym)Z$~iQk}{~Y zg$V*&C1jZtOlF>ty)Pui`<(uRwh?`h&4aS@HJy<$n_{qOO` zWhXCH9*f_}WS~!NF?hbuTteC!K!k@Mo3Z=HH}DnZux00@0!cQ-41-uW2O{^^;u}vX zn03FO&4ic!HRx38>ar!3i?p0LqWYkMty?}i)K4}prrxhitiJcRr#u`!4Ja`1zB~M% z3!7c)1I!`)7x7klIn*f8Hjjrbd3hG{IB=SxwnXGxF-xiQc|wnZ=hk2G2o@7MhptVz z5er{UdQ(EZ0cvZ&0N2;R80|RM4o@{DIYcxY?kbp^7+khTa$;M2l_`PcJa8ly-_ggs zc2!qWbeua%U@^K{VeOJXjr(AZyE5o@NZjY1kYvM}Prg*52@?@}t{WLvdqkY;$5~(F zw-+4M86TR^+ruE+Xvr?VLyBd4&2IA7@ETPclSFInomXZG72xRRCyX8;=0JJAw&Un| zWa+K6yB5DoKWqbXHD>T&XSP1bJH6UHRC(0$zo=46cpp_zNs|R25uQC8PXGts_vsIv z*{g=9nF0*3|PT@S}k-0TNx|mees#srib$2qtvXI!doR4$p881B6I%D1v zbjS>v&Zg}RZapBM7n*w&t7teq%NJO^f!2Wg_om{pz=uv#0oVS|T5@CC1GXSre!o;f zgjLgV5oqoT%p#T(OhO8Xu{kjg_G1s2aSU zB7`@oZk1`OjDgre6&mm0oAtDI*SxXczm$3#g@sJ^9)3h=|3;EY=ULfd#w&)v`)|2z z|DIvl*0?%44i^!y2sTw6Jk5D|{rfd_0`$FHyE+{OUp9i1j^kTJ-?#PIuS2l1wO1C? z@VC10h^X~O*8}cJDRMyIx^Unze;4)oRfXQw%u}DdAX;~=#6oN;xohtTaz!m z0^iEakhDK10u;{L6c<0IP={*#u8~1({pH`8F@)bv|N5Psv0`hlJfOVcQhU_R=zKF8 z!ZA;ovEWnkeEZMSd;b%kIlTKA>MWi9@?f`>qEVUvp-SlHU@On?#o?{*k00!*jd6Z# zQx?kcYHLrx(J$!^TfplQJXoG%z60zN24;I!o7m5XI&H3)ibATU>W3gIhr%iavDyRW z{MyhV=T97C)R)5+#XtAtVd3=w5}z1DeG92d=mm<>6d5$dD-@t>7)hYV?b-F+n*ZEL zh9nLR7FLst$9gTAD)OI(u-IZE6&dQpAp%}hGIlo4Y3^YwYe0i!oRYS6PpgI~i1ubMzQL6D%T`p&Yy11r~`XEbF}KFx`euHq``lGHs_F;q#b!$^W*jDI#qOl`{-x>Os#a)BCu=O@1z~Fh#6aSy&A5?oHnOn<9?yRrfC#j z?0B$|_J9REnnDG~@m39sBL46^1v$YE{pZo?io; z#SzsFdtz75ux;$ei0J-OoRe zWfbi-a-*g~wb3oUeH+u<&sVmk%00_R|7I&p>oQzNe2L#@jVHZIa(^ZXww;NUH1NKS z{gWekXora(Nv%}0DfyhVm$cE0u6nMDBdu2es>}ZoQRcJnK`uQ3v6G1b(w>%4Zkp97 zosUx> zV|SjWRxx}0p&tyebS3FJ4e$Oai<+nCdh`HUv@1t+4Qo1eAJS*L-r=SPX6xlh^}+l@ zQ{F5!|HB1c%-lD3{zV8L?o3DQk&{!BLAr?7njyo7)t|=>W>T_Jmu6zwSe9Y+kO#W% z^pbY059b6+7q+%UXDnXoR39+}wT7?Nnxk*0@CS0?2=Cd&4IIm1?bX=K6$ON3NMDSkD1C(l_y=qMKe zvR?uAXa%N$;0AN9TSmz%EC!aM6n$||ggVO8Um4iJrB10#r{zX~kzjPPR5R1LvQWu>0vVBh_UfWi^;Fh1ksYp)?{|&m@2J_sZ0aS1>GP z({BMQYZEc2V<{??Gg&j(xrI&k^i(Y4v(loW(XcNG3t0^IBEgzdJsKYBRsb%^rRkjnJr8@`(nt;o1lz`eX) z8&DAWn+MTBGmp=}7ZJ^lhZ%R98AMqBvFd%0{ec-?8+$X+!ln&O=8-J*z$BC2bK-h&;eV3d&3hbsp7bgQ_H-Qj8?^%H;RdtH1R z!~}9wjS=!`qW4|gg%sDvo`xLD(%9Y_+k~%8i5?^`1pt4G{$frywCGfZK89I+t%(Ji zi2a@%aO==MEtOUw41&&S7Ohgu)7c8wr*h6gtcXvAV-8gGJV#nIZFfT2M-{?NEx`hC znaOr*BOnXoO+$}W&RRcA&msV|Qeti4#Q=*2A{;UxyggYawO$BU72k3no*OG?rSs|s|N3aDLFrrg z(V@S!RKoFcSJ!%s{lINTP-C`f`@1%-k8=4W4lh-1-{;i0QmZY>ys(Eb34P*>K@@Kc zmsq0Lz_swItO-{T-njL=e-poi(`&onK&!PfBPz!>EgTUjEduY~z|3i1Puko8s>~UN zDOpFvz3wT?^Jn)CW`+o1g=0Md`+s2DQGWbiF%B2Q3NC8bHh=8AZ|9$Rx@WGiBB4;Y z73gCG*UWzv?h9(=Cp|qgPb0=gAcO?FN7P6Moki)WIl`D(=6pe3@j zW2Sv^`I!Ub$c6)RpkpLu;yH{5yd8}SfA~)sgE`OBE0*Ji`<(iuv00|K{0*X}8vCf$xXA{0S|U*T$*E@d$5zN|F8ah;i+q#K+K*Fn z4z+Dop+4A*53fcKuD-K5_VQe4#&c0?v29Fa>K5ldLw+8!nWH^OzEi}$XOq@N<&@;4lVB&?k1-ZX9ZxI`a$=3ynQP)Bm&C_Z>JcVH9;l_PoVB5Y@^XqK8j1)N(|=z+ zGkEeh5~bhBs&G$y?l=v6a>v!71jmZc3Hk_HfMA z-_`I7fv$5ehol+-npEBQsuMf+tUsJ(BT=FDh1_ZIxj#*mYKp^AfAL3s-p`32Dp$kJ zTmN)1hBR`6TT9?6@L(Mb6(#?wMn#wvc@aZVaza#%Ey@WCcmU$eE*zKdBXPu-1<4uv zXZq<;n5*yLrPpb#0oh}a&S4t{ z_NbTXmL~YsF3ED>Slo=1;g$_JF8HyRqhKLY=c+(2$?7jKf{4~rvIkD&uN2F# z!sl%4IrxcpMkZAl3VagL7;QUcmHB}aWQI2C8-Af~9XsDQlf9c(Na(l!JZIS|+`9$e z9z9WmPU*2-lHMbFUi2E{F#)=~+Va{b!DKge?ElRVSbK4^=Ysa)dgEb+E+-HTv^5|e z&}PZeZ#j_~SE)IYFeY4tFA?{>Q@Sn9}Pr{@HhjNa0l9AC9 zjRP8@LjeHz7IJa?NIE z0SEv-r4;6VDbBNa01P|tz?~uJRX?B8nRz}ipj7pC-T~YDyCH9cpRLzU58J}~^!UF{ zIJ2VqYw1CUe%0}ef54s`FRbu>S#$TJww&Y}N+Xerq9lZYH4S^*gwf z{c?O^%o^)TdQJpe_QjrEL{Hq1{xu4yF7<6HQX}t2&EePk?%Xo}x8aM8mHMiD8A^@!o8|Q?QHGVSP z5}=qi-wBKfZeO2ovPtFgv9RpaHd!qR>Y5GD8L}&gWs+o7A6_wTnJ!kG4Oh1t#^K85 ziq=&ZD4q(;iA*|Ad+DtMV%wD$mr(n$d!|>F09skT`*e%O+<3;0*QcwZms=B z$`~Hp^T0NP8WUb>$%PJ9S}NBlMCJ>STEEik^AndENh_>5S^fYbOvDlmX5F6-EHIjF zT8!t}pH|x5EMjI$)LG6>bFyHt0X2+QC_sd~>8kAThl8YnGrT*QxW+Q~@mRxOTFE0j6V=jeaORPJdQ zl=HPT*u(ryM7RKKvWh7vODdHrCoXg5NH%0Qb7NB!h2phze`qK4Jh{ZtE5qHbB}ZF% zy$G;NOlhRH>=0o%x0%+qM`AGPe%qPj0GJwDIaRV+Sa$*taEqDye?kcP>?gU^%QrF- z5*}7_GEZec_xYu=u9tD6GLvhYa!&WhmSg0yc|ah#|0x@GDNrDh_^E%@mHpOZwNIC~ z3k$Q4J^l;iJcF>M4{21k(**3*Xaz!igSN7+Rk7PQfu7Z9yl5f?c%t3valom1r{sLu zeK|O9Cw6i&4SZP!N?rO{h}-21dzbjdPSI7OZclD_({i>dFPe7rdl6zZxW|ixAHz^V z%$~nE=W=di=A-ab);plAfAvDpqFO57+R{jD+WLL*e4~26YGRB|zLIey0n%3y>tF2J z41GKb&{CKsQarO8ZEHvFWyCO(=n^onLFbR_Quy$;rJd%iy()1a-F~_r!R_Ko z+8;fB_QaeNY@bbj*WIjvb3%5OuQQw(-c)y^(_UM&LGqYuQun8fa_dQ&^DT!Av$2Yk zA!jYhAmSV9ZU_ZcF(W9jW#u_HqCMhIo$uNZ9jy&?To$CEJ`lS{m~5U=-A%BPj=QCZ z>hmdV{j9*@>VDTbY;llzY5l3jR&`@cxa#Pl^mQRDv!ZwDQ7m%L659Zhki)f?Cca*Y z-xbdq!ODo^PS|jjovHn%t6SZotC_4ixQ*!cS&=*OBv-ZbKXfmg%9OhKe3WUsI# zZMBqBWgcAIPvpRAs#WAzI)?}LbY~S$x)ca=FP2a~IoG798aP+n4gVvw&ajo>s9!dO z56(c5(4D&qB$zkQ1(XA(?p(0rULhGjMRFj+4C;@D0Lj}>OXuz&d(fwEJ)Xtd1Moj=na}u2T-=g znB|mkp7J;()n-Jn3diwF~wA7*Rx82R_s zU{(i}wPgdY%;AZ#)9+|s0*qRWG>^bIWSz9(=%Rz0q6C+LcTUo?#P6FK zMYCrt&%X!nM~^d|pT;;?`o~R8BoWI!Mu4A(MsJ6UX+(CY?uGM5EG-t*)tJX2$5WC8 z_^7iwQaDSURq`@xklZtki3-Flk`Sxb(<>D-$bKSo4O;pQtcB@oK^nYyJh;G!%JtNt z_3U2j>Y}U#^|)kOiZvj!9g=ZFx<@}Nd(+qyY0vI==oQgSdSE{MCHky@j5F>VQ`(NIvP|jaQh{-ZTslO--gqR9kC}Ob&}-3kIRendTOr z{l#M(261M_8Qna%FKm^THNCDUjdYu;-${488WL)eY=J*M{7~n`XZUgY)Db}J!LB2L z({XjMM9$6Hla$Ei{BvaZ6sf^4SessMDB3bmFb*+j4 zVFp~>`D0AqqBOk&{eb|i<$P|XC$$i}t+}=EExTq8?ZDAsnEC*{B#WG>U3)f(u!&T2 zH|JT2(U!rI=J4WgXeseq3A~cWOU5lMN5s7sj8@fRh|u_bIYwAk)UB52@Ze$R%*LBa z;%s%i;DbUY*#TfpE)zmdjEP5W;lyG2lg!;E>d)*Wth$z)UDLbSPuL(K?nOV1HK-}y z;*Q>2`^sIOa%AuAXrzhBeE46y5H=_6v398=Vs9|X7t!xre|Nv)3zYaurAUKVwtJXO zeyc#bhlv@36NK&e;(!jdSEkapqKnmuKhzUqFtQFhbyaR&cD`!k+4kl^3Gaw?8fps< z9J?ahMU}24uxJVYLJL`(24DP$0$GcP+}zc*EtW*t^!Xt`QjgNPb~;PnhH7l~?h5rD z2UAJe@Rt;T++wC3vnaj{T8F#Og;Y8$w)L%(qzinfj_(g{f^1Zu0GcEgK^b-M&{nX}Ggb z)q8WDp6zr1U41*>Y6W%Q63YR57X{k9{H+=)0fdv)#29U^Qq|fIM#`d9bu)jGyG-(Q}^RLzrs|| zbpK6|LM(_bJ!?%hIA3UU(EH<3X^Z;eh~$rh`w)r+_6Wm94ylw;IJ7@zQB z7$dg9IEhhRO$;ni&SlZoPsfu9plqPMP_|k{Vef?=)&;RKu436J!DpF|cTQB}MDiqF zIBDCb#QR&wEKz9npXjfS87a1OFsJf?SPUZ@{01I5_nG_)nThfc7YSN4(PZa6u~KsT zdwepTze5rlMbsJS5u%HI|HP{?)8@_(@?}0#0QFjA3O2Hgco!USz!V%uQzz9 z0CEBEQlEXd`^>u;cpan>v=16#pJ&Yw_B)F4nR7l!`QA6}Aon#w5>nb4SvF(0XqykE zqL3l)g!Vnaq#>!#j}MBf78`midHIpB;HhH*4bSS6L7kzBxajNAMM?FBWQPHbt2l>1 zewE%G)`#YfN*iL=P1#R+r(Qs@Xsc}5(U)- z>K~$B{qm(t9Ol#&pLQ(gVt+f$uSc*>bM5KC#vRkBhlr$FqNJ~Td)Ps27c%EJ*C-6T zV9%eq$64zbw?}u_sOnQ>*m)nWsb&f4YuOfI0S|vt#$vC)chp#(eBNNTX;VRbyj<1v zVZ>*iQl|4^ouIe=vuKY~KQKoR z*E@rA^}<7!gSbUIkl*|xH@*Bsgmc0G!$bb)XKPonke8F{Rj<8S*%uK^LgjLoO2JIS zVX%h>b>E;Psi)5@^-~X6>y@)7KoM|?EjE5#kC+6_ni9JGA}H$%a-gz@qX!O;-=wd47KZ zN=bvu-d@hjG@H?E51iwLXTCogMqX9+zk=cF72QOHr@|{cD6p{F!j0~Yde_Qsn?SF- zRMG3oOP9I;J2f)}>v~SsHEAtGU`Z0caFn&aP0LU-l0_XcG9hA)2>SC~s`h#RFMj>; zupr8}HH+x^i(?XBz_TZqw)y!_>?Vg@3*mpZ`aR6&RoT(9(weV?28hdt@pT2pSQvU6 zqHMULo+UPL0X(3;Qst}VQOZ}2G&r&&!0@izp4i0(4FOJNbLeWKZ!Qr}bbs5FjY5G= zt6uKBjU`HL$VO_NG9Yi}=?FhlIhD|swkwU(*%_vYuXOxVJ+0UBepX!(3dHmg*R=va zH6n?1KZx)wG6KIeTt%rlH8aU^&=k!7E9H&tTo6`yq{;&+`+&WN1F!mP=MZyU;h6AM zoxviIVwT5Jtq4dM@3})~qt0K;vh!V0ha|^-TdORuQrjlGNMs>8HyY1br(#8EU#6d4 zt~2}%a=+`2$Brjn2$i0@!Sayt5}9qt7F&ahu>nlo*Zr)a(5`xW`BmRm?dw#<%geSfZD`3n1?y(vUA!M2*6$wuW*{zU*DP5Y?Rn;>5K>AD9fQl(EsAKG( zng67^2MYwkv~QYC>jVk-iB&fKmR*Gf=e(B}{%fxC^r|yQbjEz6PV9$O=rO+UVmI^QE!mF?)rh;+`oL`n)@ZtrMv{BNY=a>RpMXRJ2&?!fdb z#IX_Y@sc9kvx5%VNSn1$P;YR%R*_pDD#bFKaGR@AwWl}K3h6O9!e_+C2kk`Ydd~~B zZc46S7_4vnV`I+aCoZ1DOR$Ez4xZ9XLe=A*o+rW5e?P;MT2Xkx9yJmMO;DW^mujh3b8MVF+jNWp|_rHNoj-XieS>oX0V zybWh`H|~cVwdN=9@r7V_Qw(#Kj((({270ymbPCSB0MIw)5_>HB@7@TJ*2n9*zlYxv zvoYLQP^b$yG2_BsWRgU}KO^R0m#p!-%rE?^CLsBLb(G5?+CVtX9n{ygUZRtty~fjFViysUY3frV^WF)vfJ2 zZyPU(y^w$<>KI?m5dS8P&v(sld;F-pP91s&aWRNu`(c5>)oXfJgkQ-I=M{h~HLT>Z zM(Yazt_^D^2Z~g`z1gH$SjMWE)ahJ?%vJ>uU;+T02^wEtppO+=eJ`>BkM4QksJD%p zwZqoUwp*ykp;3PtjTGKu!Gs^V*r*d(WPSzmQ88_u$RBM*ofh938KH%oER)9i(7k}i zG_f3t6sM;z`!Wkj5y{Ry{{})dR@^RAhBC`;-;b=t9m^TGyw0Kvnh8FQR)57(x_PBl z{_F{O)qvtXRFP5owoPg<-*=ZiuVyY3D8X~w0_~PIn?V9z91R?A3Le0F7 zp!Rlsh$Aq!n(3J4SBmf0&u_0;O=o|7u=$u_TuAHw=Y`HYQfJT)D(3HnGrif*8d5># znWf>$r+@WGQIza9b6;r!W_mvK4kc(A;*}b_bCm!;A5Y~AmZ>FN5fU`ecmLc6@~82$ z_$e)fyO1ejMGIuQOe30AqZaFy=m(yeMbyBJSDPsr`#OYyQesyQsDd8!rgwfkdDoKM zqngN8y{dH_YdLRt)#gS{8p7&T|0GVAle&WRbQ)10L-Uh06OqcaD6izq-h52PUBS_M zXDnG!jn>5$7lgUpbEEY%F_vZhvvE_E7rHo9!PO&iwX^VV?~Fpi#wh76HRs#R?|^?_ zso#FHFhdvFM8<-am=%8RHFqtoJw+-@ zq4$w`QQ+w>g&x)G1H=o4SImw8-OZ~!%n&H;K!aDB5F$p+w~eozt`4Nbod4y_U4~-o z(k~nj!yFSi^@cfISt*emM;p``k~&5Y1+fn7Fx0uzskxG}52fAWH^gh%9X5)xly`~l z$qSsS^~7o|TNPp1<%?k{!=X=_+!$$yb>zW@qaz*R6 z#S~&k!42PpH9oXVDO@@5cg<6dv+sANPa>9RhGXm81CNrdRuSyv(9f4zi7m%Yb!;+T zo1Q0(-Wp>SHp1{RaGmCw3K8|loWubq}SYau&iJ$OR zYnZJ0t`F2dS)t1)fQjSq7HEgXdOIDpD#&ySaM^ z{9pP}4|+OMTs)*rIbvu~h41YKOw-2LB&L$ivo@G6GN+=Zjh;wC_>7@6Wqjb#_fggl zJ3jmNOXdqvdkTKYrs8FCvVk#^AzSbU1g-Zuy@+qF)Jps)^5QotI%Hu0#0-oVVTVKJ z47svHRH0*m$}~3XhE`wa*NM)9tf1j}yFkK^-HDct#t-T`lE5CQg<1U<9wX)DpCEo? z@w6Qc^E9E9#SLbp`*36N%_>>rPMZF{g$TK^CuuVM<#5p`Z)Ri(ep4o6SOvswS_ zdPHC2`-xaHSPzCZ>&_YSdX#euT_NZZ{ME+^3U@hANNry5mka39%bccD&^C$Z)7b2< z=9jIWwF@pv(-adw@B-4eYQbMMMt9pS6}TRW+&)ihD^c!u>4~C90O054)?dc1IbWgv z-PW^$*G=*JNU^;B-La=;vds$6O0jr)|o~g`2XkK}4#OQRqqH>>%fDL1B zeK0)BNOfs1yG2RG2Mq~Tp)VDr(>=KG`a7cV?t!Bfj(q8duO$`ka6di1e z8;bEQ) z!MzNP;~~c`?96X6n{t%mK@toJvHNO51Vjs&9yn+80n8q6--+}8!pPGp+BnhE@X}wW zzD8@Hs}SdIw3+3NE=alLPq^{{LGBe( z+aKgLzr3`r6i%LLj80xvVh0#PBn9CS46JHf3ToW0~KX0#zy5OB2ReMox+zYEPs15pVJ{$2AvE^s08lP2*x2BD)kJkR&X zA`&0WtAc)5jwDI_<7gG5TYCN#Yh-nQ+0kb5p>dl)c}*V)pxeLZmmX9SJllO%MHnnQ zVlwDcdP^nn6Z3j7GecI=%PNr&H?ueE0NHNw@UhK#4%+K#*xVSN<<(E^8|WMwEVBQp z-}zU*^-dKk3xA>%6q08Laf%N)*u)Ia!JRA_o3AjQ8?$pdo$x-tIz!!xp4{3P{l}Gb zxR-V;-Tf;tn56{4bR>K{A|VG$p_Z&FY4bh8s63hd^zuHZTsD^buG@%VZ+k`1mNxFrSC=>?rin?M zyBp?N;N?l+I^ymAhP*~&+{y@j>*kmQL^-F<=~rnCcs4h8Lgde`Ta;qUu_aZF-uNdJ z*@dasF6Aq?fE;mWZx{5j_nLt`niH9}`_XvZ$+9$%4^0QPn{uE(Z|vA0{iT(Y9mF=5 z-t?Yw&RYYLEd6b|-0%`m?%@rlaTDwO_wv5a%P}}g5S+da{uBYzy7g1_=FMto9^OwO z1~l4$Ec$D$i_cn#)aUriogN_*peE(yMc!78o@7f2Ytxs26a;`(#P6V64eoJ0A+s&*+d=cV^Rd+ zEU+A_&%^;Uk>xcpGFk_e%22ZDcDL|6(}R{rxq`boDd)xwRz;Il3m=JGt$-%4-hdx4 zCx5Yd#Y?Jlca+IZ#8SAO$dCYZjsc4HZDcHZ85n^pjf`M!NN-uG`AE;ir~uqY@yIhJ~ofUoAb+P`ulX~y{FrzY6nKDg@hx}V1h z|9+K%JK_%qL(l%HVAjj#0?iyxhUQ-y^1>eEdaYU5J86{_>;W>Wx;;^hgn_tn`qtgI zl;~9N@cf`aCB?Vx7#nL=M-;| z`}LiqmyDDSvsaKDLSMOe%iStS91hl84k`2YU|rieVwa63u<)zn9}ir`_gl#$dtrGL z7$HXXb?hAIDjfc@j{QGEBmG4;X?oqsN&(3AyOqbV5=w1HNe(GLb)fn-kFQb5K!M}0 z%0kOA%iBpsRrwG7yD+J)chcbrI*v;;4V#p;g4Ioy)-0CL)dx3h|5RahVRQ(Z(2|x| z{g$90RRxxMGiWt4etlG*=TaZUB;N9PWurlfb2_+bC|Jobp~cM*#EB1M>J-PaE8)Rw z0RUu@2}C|49sQiQdtI={*RkKqrWgp#<*@n=7@fC2Uh9t0!uv~Bxag+1H{O`EO8h`p zY9)IPaduU=SxOGyr_{6wyX0W;vne{5NY-U^6^k{jR=lBawjCHJ0L#~(Gg?blu+&oU zGN@h$74S7f{g!~=63Gg=Rv zrc9g~uNI9<3pi=$yLTMPmQo<+a_SoCu)NpM*P>TbXf*ClkLDEc6R`ZYfF~1)Lwn-) zih2Qo_E^5b>mU~+=s(1ViBoiWS^qG)9#Ox}ki15DE3;DT;do&VZ<8ehHMmKRD%o9V zO&lpi`P(^`k6PA6b7DRBXad zu`~8v{m|)vz1W^{)@tFwBryW&bHbs{*fNoE|s$+v{Z!oq_-{bh` z!mSM2BaRNG%3G76TDFZu=4a;@;(iC;-d)H)LcwILzQaS96w2zSvKT zSQ3)p3z)${!ITyUV|ICvXJxM)knM^&gY^~5o8hQW4hdGtHVakov9qhN6`h;vh6MZ) zj;*7FzDG+^ha%c7yh72ldXpNs3!4&RcH4s&$K<|q|EVQ)f8Ec+!L)o@Z)VGfghnKU zlM3~#q{M2Y^=tu-!~A&{0OVY2R&1%V(>E<`Ji*$mw9xjuV#!2$sze>w)Iw&R% zVCauSP5gfKf-0*%@aa+g%ji%pI!jK|Ll^e9ZHiZ^(R-D0Szrbn-2xue@2lnS!d_L- zIV&Q+0=*@3!&=g%i;N3^w<`p;P4^s~afd>$H4Q}*%%^^Sphdv*v^U3$9C6JfD|biC zf1AFLdh{amCY>=wYD)qzI2KdMcPDr9aJN3~WW=vjIRl+Nzh!8%eB))|J)PFdEH!u2 zwD1vAgDwdx6l{>HbHeQ#h0XU33P3 zt|nNOBg#hPugW)^h@nOu35v&+cxvTs6- z!gmNhV4t?FB8-%yWzY2xP0G{I(nge~t%~eK+uN5!ruzXOVh8PiQjvIFLa9vX2;>pr_ltGh}<8_ITg=+cg;O-55OCQkatM zj1>s{q#cEN&hu`=#)G_z>)H9EdQ&b}YCZ*%(vY0jv=!N61E7OcW4{vKtpxYHu!#8U zbBz0z)zx+FJX-HVWTP|p_4uUwkEZis0kh$iHYZ=>I8OAN{<*BUgp>R-Y*WQ`Qz~UA z&s#Odik6_zVOO?umnnuo>-X@zk%rPFo#U+o@{fuvcRDiFZpz`o>Uxk|z`6=HXDUXxhU3>TBT$Hp@jEAD`0&6cZ zLBnzTTT24wkDe=)V5p6Cr2@R>=G``gZL6AtDvr3sgf9`95_3n{e~zo{@?0apog$0= z*1ZCf-!>8fdi8%iy=7EfUDGs-1$PN9!QI_81P{U8gS!SB2o8bZ1Sd$a-~@-k-Q5QQ zgAHzj&r9y>`M&>WopaXOy=r%NRaZ|}-U3)XpZ`bb>v7j;d?F$BIssxX3iei-pO`C` z;~5ssrSBe+cswRv9X4tjX#at|&gDYy-4$%zg*ZswVZh0gz_7M9E?tQOS4G)7cBy$9J}WaWH# zM~0MUYQ7mq5B0^@RYqCUnGy|TR31vtsz)_Of=gEy`@&=R?Ssqp4@;rO9IwL-M`F{* z8pdq>B|g1P-*vTPj`%jOj!JekpD*7%T93zKQI$mNO#hyo>?b`Vb;n!34fH+Dpa2n> zloVZQfz?lPg;f3HFaR)ChP}sx7~n`;kG#4Zk)zYWZ^HXAV>E|{(eiCKiJaaE=p9_bp#W~7EP5YT(T*oN^&s!5OiYY16KyWJRb@M30NHg zQLXSxo@32U5E}8U)Q#njJ*E)8DS#9VsF;cQUW(jPNI~y@c|BZ?%|1E4ue|}Q06$}u*uFKA&g?LOrjsb(nRW3w}e$iM&gP)6?eO*eUkFQfZ)ndS> zSI5>@@iJvv;n0Bt8DQ2zd0`s&aL4~Q6xlaFF(BERAE|EX+6a0Oh+p2czWoG}5_zWy zdl`G?DMuwmvN|y#A}CqN$z5ivC}p(=o0|3OCtZ1P4ajSyq=UcxIUNCSEUudB+Kjlg zcu|4Oh9tlip(FopN*~{fQyXvR{qO6>QK80q+m;DMgQI+KiAZV zeBW3Sl%Y~chvc8>(eBLCc{F-U9Kz~5|1mFvLCXi+8*!T-=bn4*y9~ps*yKX-V14oH zYKQzYGzszjHuZASZbR^AZ1<1XBL33f8VHI~_FU=)Ir|N*S8SB&@2L5bw{eb3&L+Ws zYPx)@!P;WUTCv3aVzB}Hw2=ya}DKk@}k&Pu`f2x4fcW%-=9PC!S(hd zS@mgY+SIBp({aLHA5`U1#lnH!<7aUMnXyKT#>2FNmF91GWA=HUgE&*p_G5CooWIYG z-KUcO97F_fv(K&w>ikx*an>|sNy?sSi~e$)g()FGdeR^x<%^LqMHd%!Yj3dP1aPl)~jGUtqXb6q=TIMtJocvnWlsaDB$Mm(F6En?NS2U06jzex9q

    {?*fO7?3U!{M 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%0D#uuGMD_q~IwSs9XPy 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 literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/sql.jpg b/frontend/src/assets/img/sql.jpg new file mode 100644 index 0000000000000000000000000000000000000000..48670674502caacbc5e42a8baf6861a6211f93c6 GIT binary patch literal 44803 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

    -TvHS~C7dZ%;O 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 z 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 + + + + + + + + + + diff --git a/frontend/src/assets/img/success-bg.svg b/frontend/src/assets/img/success-bg.svg new file mode 100644 index 0000000..095b566 --- /dev/null +++ b/frontend/src/assets/img/success-bg.svg @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/success-icon.svg b/frontend/src/assets/img/success-icon.svg new file mode 100644 index 0000000..1de58ee --- /dev/null +++ b/frontend/src/assets/img/success-icon.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/img/team-custom.svg b/frontend/src/assets/img/team-custom.svg new file mode 100644 index 0000000..2025ffc --- /dev/null +++ b/frontend/src/assets/img/team-custom.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/unverifiedUser.svg b/frontend/src/assets/img/unverifiedUser.svg new file mode 100644 index 0000000..cc9254a --- /dev/null +++ b/frontend/src/assets/img/unverifiedUser.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/img/verifiedUser.svg b/frontend/src/assets/img/verifiedUser.svg new file mode 100644 index 0000000..e9420f3 --- /dev/null +++ b/frontend/src/assets/img/verifiedUser.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/img/vpc-custom.svg b/frontend/src/assets/img/vpc-custom.svg new file mode 100644 index 0000000..d25e5b8 --- /dev/null +++ b/frontend/src/assets/img/vpc-custom.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/img/vpc-form-basi.svg b/frontend/src/assets/img/vpc-form-basi.svg new file mode 100644 index 0000000..3881ba0 --- /dev/null +++ b/frontend/src/assets/img/vpc-form-basi.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/vpc-form-high.svg b/frontend/src/assets/img/vpc-form-high.svg new file mode 100644 index 0000000..9976e09 --- /dev/null +++ b/frontend/src/assets/img/vpc-form-high.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/vpc-form-price.svg b/frontend/src/assets/img/vpc-form-price.svg new file mode 100644 index 0000000..2fc8ad4 --- /dev/null +++ b/frontend/src/assets/img/vpc-form-price.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/vpc-form-stan.svg b/frontend/src/assets/img/vpc-form-stan.svg new file mode 100644 index 0000000..2ee5ea6 --- /dev/null +++ b/frontend/src/assets/img/vpc-form-stan.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/vpc-icon.svg b/frontend/src/assets/img/vpc-icon.svg new file mode 100644 index 0000000..33d0f0f --- /dev/null +++ b/frontend/src/assets/img/vpc-icon.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/vpc.svg b/frontend/src/assets/img/vpc.svg new file mode 100644 index 0000000..4ac0880 --- /dev/null +++ b/frontend/src/assets/img/vpc.svg @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/img/wordpress.svg b/frontend/src/assets/img/wordpress.svg new file mode 100644 index 0000000..280a7d0 --- /dev/null +++ b/frontend/src/assets/img/wordpress.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/data/navigation.ts b/frontend/src/data/navigation.ts new file mode 100644 index 0000000..839a046 --- /dev/null +++ b/frontend/src/data/navigation.ts @@ -0,0 +1,83 @@ +import icLayers from '@iconify/icons-ic/twotone-layers'; +import icDashboard from '@iconify/icons-ic/twotone-dashboard'; +import icAssigment from '@iconify/icons-ic/twotone-assignment'; +import icBubbleChart from '@iconify/icons-ic/twotone-bubble-chart'; +import icSettings from '@iconify/icons-ic/twotone-settings'; +// import icShoppingBusket from '@iconify/icons-ic/twotone-shopping-basket'; +import icFlare from '@iconify/icons-ic/twotone-flare'; +import icDns from '@iconify/icons-ic/twotone-dns'; +import icControlCamera from '@iconify/icons-ic/twotone-control-camera'; +// import icMarketplace from '@iconify/icons-ic/twotone-store'; +import icQueue from '@iconify/icons-ic/twotone-queue'; +import icSupport from '@iconify/icons-ic/twotone-contact-support'; +import icContacts from '@iconify/icons-ic/twotone-contacts'; +import icCloudQueue from '@iconify/icons-ic/cloud-queue'; +import icGroupWork from '@iconify/icons-ic/twotone-group-work'; +import icPayment from '@iconify/icons-ic/twotone-payment'; +// import accountTree from '@iconify/icons-ic/twotone-account-tree'; +// import icRollBack from '@iconify/icons-ic/twotone-rotate-90-degrees-ccw'; +// import icArrow from '@iconify/icons-ic/twotone-arrow-right'; +// import icOpenInNew from '@iconify/icons-ic/twotone-open-in-new'; +import icApps from '@iconify/icons-ic/twotone-apps'; +import icEndpoint from '@iconify/icons-ic/twotone-explicit'; +import { SidenavLink } from '@sdk-ui/interfaces'; + +export const SIDENAV_LIST: SidenavLink[] = [ + { + type: 'link', + label: 'Clusters', + route: '/clusters', + icon: icGroupWork, + id: 'clusters', + envName: 'cluster', + permissionName: 'VIEW_CLUSTER' + }, + // { + // type: 'link', + // label: 'Helm Apps', + // route: 'helm/apps', + // icon: icApps, + // id: 'helm-apps', + // envName: 'helm-apps', + // permissionName: ['VIEW_APP_CATALOG', 'VIEW_HELM_APPLICATION'], + // }, + { + type: 'dropdown', + label: 'Management', + icon: icContacts, + id: 'management', + children: [ + { + type: 'link', + label: 'Users', + route: '/manage/users', + permissionName: 'ROLE_ADMIN', + id: 'users' + }, + { + type: 'link', + label: 'Roles', + route: '/manage/roles', + permissionName: 'ROLE_ADMIN', + id: 'roles' + } + ] + } + + // { + // type: 'dropdown', + // label: 'Settings', + // icon: icSettings, + // id: 'settings', + // children: [ + // { + // type: 'link', + // label: 'System', + // route: '/settings/system', + // envName: 'system-setting', + // permissionName: 'ROLE_ADMIN', + // id: 'system' + // }, + // ], + // }, +]; diff --git a/frontend/src/data/toolbar.ts b/frontend/src/data/toolbar.ts new file mode 100644 index 0000000..84ef37b --- /dev/null +++ b/frontend/src/data/toolbar.ts @@ -0,0 +1,32 @@ +import icAccountCircle from '@iconify/icons-ic/twotone-account-circle'; +import icLock from '@iconify/icons-ic/twotone-lock'; +import { ToolbarUserMenuItem } from '@sdk-ui/interfaces'; + +export const USER_DROPDOWN_LIST: ToolbarUserMenuItem[] = [ + { + id: '1', + icon: icAccountCircle, + label: 'My Profile', + description: 'Personal Information', + colorClass: 'text-teal-500', + route: '/user-profile' + }, + { + id: '2', + icon: icLock, + label: 'Change Password', + description: 'Change Your Password From Here', + colorClass: 'text-primary-500', + route: '/settings/reset-password' + } + // { + // id: '5', + // icon: icSettings, + // label: 'Settings', + // description: 'Manage other Settings', + // colorClass: 'text-purple-500', + // route: '/settings/general', + // envDisables: 'manage-account-setting', + // permissions: 'MANAGE_ACCOUNT_SETTINGS' + // } +]; diff --git a/frontend/src/environments/environment.prod.ts b/frontend/src/environments/environment.prod.ts new file mode 100644 index 0000000..4522dc4 --- /dev/null +++ b/frontend/src/environments/environment.prod.ts @@ -0,0 +1,8 @@ +const KLOVERCLOUD_API_ENDPOINT = 'KLOVERCLOUD_API_ENDPOINT'; + +export const environment = { + production: true, + // Endpoints + apiEndPoint: KLOVERCLOUD_API_ENDPOINT + '/', + multiClusterWsEndpoint: KLOVERCLOUD_API_ENDPOINT + '/clusterlog' +}; diff --git a/frontend/src/environments/environment.ts b/frontend/src/environments/environment.ts new file mode 100644 index 0000000..63fddd5 --- /dev/null +++ b/frontend/src/environments/environment.ts @@ -0,0 +1,8 @@ +const KLOVERCLOUD_API_ENDPOINT = 'http://localhost:8080'; + +export const environment = { + production: false, + + apiEndPoint: KLOVERCLOUD_API_ENDPOINT + '/api', + multiClusterWsEndpoint: KLOVERCLOUD_API_ENDPOINT + '/clusterlog' +}; diff --git a/frontend/src/favicon.ico b/frontend/src/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..0018102d3d121f982444799946627f6389313f54 GIT binary patch literal 1150 zcmbWzPe>GD7{~Ev(UdYsLh2xxbW%tU(Ir@Q6Rg8Vr~ET12(6*VqMN6Mh>lS~?7=?> z3x%r{1koOJ#oTreVIj7&9+WyIM9`sw`Db6h&up^}(?+23*>~od=l8ttj7Wh0+FIea zQAR37PKihpC{ZcaSwwhtn7^4@AwdAW_<|iI(fq%8^l0`7hOr6bG4`)KJ(^QBh~gK# zS-pN%F8_MC)6Le=^Ay`3Ix&-vV^rX}EhhtDEz#pBMYx vp5ydC#7op`)+~saC + + + + Home + + + + + + + + + + +

    + + + + diff --git a/frontend/src/libs/ace-editor/README.md b/frontend/src/libs/ace-editor/README.md new file mode 100644 index 0000000..3db34ea --- /dev/null +++ b/frontend/src/libs/ace-editor/README.md @@ -0,0 +1,3 @@ +## All possible options can be found at: + +[https://github.com/ajaxorg/ace/wiki/Configuring-Ace](https://github.com/ajaxorg/ace/wiki/Configuring-Ace) diff --git a/frontend/src/libs/ace-editor/acc-editor.enums.ts b/frontend/src/libs/ace-editor/acc-editor.enums.ts new file mode 100644 index 0000000..bcfd4be --- /dev/null +++ b/frontend/src/libs/ace-editor/acc-editor.enums.ts @@ -0,0 +1,4 @@ +export enum EditorMode { + JSON = 'json', + YAML = 'yaml' +} diff --git a/frontend/src/libs/ace-editor/ace-editor.component.html b/frontend/src/libs/ace-editor/ace-editor.component.html new file mode 100644 index 0000000..c73588c --- /dev/null +++ b/frontend/src/libs/ace-editor/ace-editor.component.html @@ -0,0 +1 @@ +
    diff --git a/frontend/src/libs/ace-editor/ace-editor.component.scss b/frontend/src/libs/ace-editor/ace-editor.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/libs/ace-editor/ace-editor.component.ts b/frontend/src/libs/ace-editor/ace-editor.component.ts new file mode 100644 index 0000000..90e50a3 --- /dev/null +++ b/frontend/src/libs/ace-editor/ace-editor.component.ts @@ -0,0 +1,130 @@ +import { Component, ElementRef, EventEmitter, Input, OnChanges, Optional, Output, SimpleChanges, ViewChild } from '@angular/core'; +import { CoreConfigService } from '@core-ui/services/core-config/core-config.service'; +import { Ace, edit } from 'ace-builds'; + +import 'ace-builds'; +import 'ace-builds/src-noconflict/theme-tomorrow_night_blue'; + +@Component({ + selector: 'kc-ace-editor', + templateUrl: './ace-editor.component.html', + styleUrls: ['./ace-editor.component.scss'], + host: { + class: 'kc-ace-editor-host' + } +}) +export class AceEditorComponent implements OnChanges { + @ViewChild('editor') editorRef!: ElementRef; + @Output() textChange = new EventEmitter(); + @Input() text!: string; + @Input() readOnly: boolean = false; + @Input() mode: string = 'json'; + @Input() prettify: boolean = true; + + private theme: string; + + editor!: Ace.Editor; + + // All possible options can be found at: + // https://github.com/ajaxorg/ace/wiki/Configuring-Ace + options = { + //? renderer + highlightActiveLine: true, + vScrollBarAlwaysVisible: true, + displayIndentGuides: true, + fontSize: '14px', + + //? session + tabSize: 2, + wrap: true + }; + + constructor(@Optional() public coreConfigService: CoreConfigService) {} + + ngOnChanges(changes: SimpleChanges): void { + if (!this.editor) { + return; + } + + for (const propName in changes) { + if (changes.hasOwnProperty(propName)) { + switch (propName) { + case 'text': + this.onExternalUpdate_(); + break; + case 'mode': + this.onEditorModeChange_(); + break; + default: + } + } + } + } + + ngAfterViewInit(): void { + this.theme = this.coreConfigService?.generalInfoSnapshot?.webTheme || 'DARK'; + // setTimeout solve editor cursor problem + setTimeout(() => { + this.initEditor_(); + }, 100); + } + + /** + * @Definition Emit editor value + * @Params text: string + */ + onTextChange(text: string): void { + this.textChange.emit(text); + } + + /** + * @Definition Initialize Editor + */ + private initEditor_(): void { + this.editor = edit(this.editorRef.nativeElement); + this.editor.setOptions(this.options); + this.editor.setValue(this.text, -1); + this.editor.setReadOnly(this.readOnly); + + if (this.theme === 'DARK') { + this.editor.setTheme('ace/theme/tomorrow_night_blue'); + } else { + this.editor.setTheme('ace/theme/chrome'); + } + + this.setEditorMode_(); + this.editor.session.setUseWorker(false); + this.editor.on('change', () => this.onEditorTextChange_()); + } + + /** + * @Definition Update when User input new key + */ + private onExternalUpdate_(): void { + const point = this.editor.getCursorPosition(); + this.editor.setValue(this.text, -1); + this.editor.moveCursorToPosition(point); + } + + /** + * @Definition callback for data change + */ + private onEditorTextChange_(): void { + this.text = this.editor.getValue(); + this.onTextChange(this.text); + } + + /** + * @Definition Update editor mode when change + */ + private onEditorModeChange_(): void { + this.setEditorMode_(); + } + + /** + * @Definition Update editor mode + */ + private setEditorMode_(): void { + this.editor.getSession().setMode(`ace/mode/${this.mode}`); + } +} diff --git a/frontend/src/libs/ace-editor/ace-editor.module.ts b/frontend/src/libs/ace-editor/ace-editor.module.ts new file mode 100644 index 0000000..b965109 --- /dev/null +++ b/frontend/src/libs/ace-editor/ace-editor.module.ts @@ -0,0 +1,10 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { AceEditorComponent } from './ace-editor.component'; + +@NgModule({ + declarations: [AceEditorComponent], + imports: [CommonModule], + exports: [AceEditorComponent] +}) +export class AceEditorModule {} diff --git a/frontend/src/libs/ace-editor/styles.scss b/frontend/src/libs/ace-editor/styles.scss new file mode 100644 index 0000000..c9fd911 --- /dev/null +++ b/frontend/src/libs/ace-editor/styles.scss @@ -0,0 +1,25 @@ +.kc-ace-editor { + width: 100%; + height: auto; + + // Ace Editor Host + &-host { + display: flex; + min-height: 200px; + border: 1px solid var(--border); + width: 100%; + overflow-x: auto; + border-radius: 4px; + } +} + +// Ace styles override +.ace_editor { + line-height: 20px !important; +} + +.ace_editor, +.ace_editor * { + font-weight: 400 !important; + letter-spacing: 0 !important; +} diff --git a/frontend/src/main.ts b/frontend/src/main.ts new file mode 100644 index 0000000..fa4e0ae --- /dev/null +++ b/frontend/src/main.ts @@ -0,0 +1,13 @@ +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic() + .bootstrapModule(AppModule) + .catch(err => console.error(err)); diff --git a/frontend/src/note.txt b/frontend/src/note.txt new file mode 100644 index 0000000..a321ed4 --- /dev/null +++ b/frontend/src/note.txt @@ -0,0 +1,11 @@ +# Helm App Catelog Icons +# Helm App Role Base Permission +# Add logs in resource, only kind=Pods contain logs + +# repository new column new chart or column + +# Event message Copy and show full message [x] +# helm template file view [x] +# helm clusterid and cluster display name, clusterName [x] + +# embetted success, error ToastrService \ No newline at end of file diff --git a/frontend/src/polyfills.ts b/frontend/src/polyfills.ts new file mode 100644 index 0000000..b40974e --- /dev/null +++ b/frontend/src/polyfills.ts @@ -0,0 +1,52 @@ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + * because those flags need to be set before `zone.js` being loaded, and webpack + * will put import in the top of bundle, so user need to create a separate file + * in this directory (for example: zone-flags.ts), and put the following flags + * into that file, and then add the following code before importing zone.js. + * import './zone-flags.ts'; + * + * The flags allowed in zone-flags.ts are listed here. + * + * The following flags will work for all browsers. + * + * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + * + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + * + * (window as any).__Zone_enable_cross_context_check = true; + * + */ + +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +import 'zone.js'; // Included with Angular CLI. + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss new file mode 100644 index 0000000..edfafc6 --- /dev/null +++ b/frontend/src/styles.scss @@ -0,0 +1,12 @@ +@use '@angular/material' as mat; + +@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&display=swap'); + +// kc SDK +@import 'projects/sdk-ui/assets/styles/core.scss'; + +// KC CDK library +@import 'projects/cdk-ui/styles/all-components.scss'; + +// Internal Library Scss +@import './libs/ace-editor/styles.scss'; diff --git a/frontend/src/test.ts b/frontend/src/test.ts new file mode 100644 index 0000000..3376345 --- /dev/null +++ b/frontend/src/test.ts @@ -0,0 +1,16 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/testing'; +import { getTestBed } from '@angular/core/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; + +declare const require: any; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { + teardown: { destroyAfterEach: false } +}); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js new file mode 100644 index 0000000..a331c1b --- /dev/null +++ b/frontend/tailwind.config.js @@ -0,0 +1,691 @@ +module.exports = { + purge: ['./src/**/*.{html,ts,css,scss}', './projects/*/src/**/*.{html,ts,css,scss}'], + prefix: '', + important: ':root', + separator: ':', + theme: { + screens: { + sm: '640px', + md: '768px', + lg: '1024px', + xl: '1280px', + xxl: '1600px' + }, + colors: { + transparent: 'transparent', + + black: 'var(--text-color)', + white: 'var(--text-color-light)', + 'contrast-black': 'rgba(0, 0, 0, 0.87)', + 'contrast-white': 'white', + + gray: { + 50: 'var(--color-gray-50)', + 100: 'var(--color-gray-100)', + 200: 'var(--color-gray-200)', + 300: 'var(--color-gray-300)', + 400: 'var(--color-gray-400)', + 500: 'var(--color-gray-500)', + 600: 'var(--color-gray-600)', + 700: 'var(--color-gray-700)', + 800: 'var(--color-gray-800)', + 900: 'var(--color-gray-900)' + }, + red: { + 50: 'var(--color-red-50)', + 100: 'var(--color-red-100)', + 200: 'var(--color-red-200)', + 300: 'var(--color-red-300)', + 400: 'var(--color-red-400)', + 500: 'var(--color-red-500)', + 600: 'var(--color-red-600)', + 700: 'var(--color-red-700)', + 800: 'var(--color-red-800)', + 900: 'var(--color-red-900)' + }, + orange: { + 50: 'var(--color-orange-50)', + 100: 'var(--color-orange-100)', + 200: 'var(--color-orange-200)', + 300: 'var(--color-orange-300)', + 400: 'var(--color-orange-400)', + 500: 'var(--color-orange-500)', + 600: 'var(--color-orange-600)', + 700: 'var(--color-orange-700)', + 800: 'var(--color-orange-800)', + 900: 'var(--color-orange-900)' + }, + 'deep-orange': { + 50: 'var(--color-deep-orange-50)', + 100: 'var(--color-deep-orange-100)', + 200: 'var(--color-deep-orange-200)', + 300: 'var(--color-deep-orange-300)', + 400: 'var(--color-deep-orange-400)', + 500: 'var(--color-deep-orange-500)', + 600: 'var(--color-deep-orange-600)', + 700: 'var(--color-deep-orange-700)', + 800: 'var(--color-deep-orange-800)', + 900: 'var(--color-deep-orange-900)' + }, + amber: { + 50: 'var(--color-amber-50)', + 100: 'var(--color-amber-100)', + 200: 'var(--color-amber-200)', + 300: 'var(--color-amber-300)', + 400: 'var(--color-amber-400)', + 500: 'var(--color-amber-500)', + 600: 'var(--color-amber-600)', + 700: 'var(--color-amber-700)', + 800: 'var(--color-amber-800)', + 900: 'var(--color-amber-900)' + }, + 'light-green': { + 50: 'var(--color-light-green-50)', + 100: 'var(--color-light-green-100)', + 200: 'var(--color-light-green-200)', + 300: 'var(--color-light-green-300)', + 400: 'var(--color-light-green-400)', + 500: 'var(--color-light-green-500)', + 600: 'var(--color-light-green-600)', + 700: 'var(--color-light-green-700)', + 800: 'var(--color-light-green-800)', + 900: 'var(--color-light-green-900)' + }, + green: { + 50: 'var(--color-green-50)', + 100: 'var(--color-green-100)', + 200: 'var(--color-green-200)', + 300: 'var(--color-green-300)', + 400: 'var(--color-green-400)', + 500: 'var(--color-green-500)', + 600: 'var(--color-green-600)', + 700: 'var(--color-green-700)', + 800: 'var(--color-green-800)', + 900: 'var(--color-green-900)' + }, + teal: { + 50: 'var(--color-teal-50)', + 100: 'var(--color-teal-100)', + 200: 'var(--color-teal-200)', + 300: 'var(--color-teal-300)', + 400: 'var(--color-teal-400)', + 500: 'var(--color-teal-500)', + 600: 'var(--color-teal-600)', + 700: 'var(--color-teal-700)', + 800: 'var(--color-teal-800)', + 900: 'var(--color-teal-900)' + }, + cyan: { + 50: 'var(--color-cyan-50)', + 100: 'var(--color-cyan-100)', + 200: 'var(--color-cyan-200)', + 300: 'var(--color-cyan-300)', + 400: 'var(--color-cyan-400)', + 500: 'var(--color-cyan-500)', + 600: 'var(--color-cyan-600)', + 700: 'var(--color-cyan-700)', + 800: 'var(--color-cyan-800)', + 900: 'var(--color-cyan-900)' + }, + purple: { + 50: 'var(--color-purple-50)', + 100: 'var(--color-purple-100)', + 200: 'var(--color-purple-200)', + 300: 'var(--color-purple-300)', + 400: 'var(--color-purple-400)', + 500: 'var(--color-purple-500)', + 600: 'var(--color-purple-600)', + 700: 'var(--color-purple-700)', + 800: 'var(--color-purple-800)', + 900: 'var(--color-purple-900)' + }, + 'deep-purple': { + 50: 'var(--color-deep-purple-50)', + 100: 'var(--color-deep-purple-100)', + 200: 'var(--color-deep-purple-200)', + 300: 'var(--color-deep-purple-300)', + 400: 'var(--color-deep-purple-400)', + 500: 'var(--color-deep-purple-500)', + 600: 'var(--color-deep-purple-600)', + 700: 'var(--color-deep-purple-700)', + 800: 'var(--color-deep-purple-800)', + 900: 'var(--color-deep-purple-900)' + }, + primary: { + 50: 'var(--color-primary-50)', + 100: 'var(--color-primary-100)', + 200: 'var(--color-primary-200)', + 300: 'var(--color-primary-300)', + 400: 'var(--color-primary-400)', + 500: 'var(--color-primary-500)', + 600: 'var(--color-primary-600)', + 700: 'var(--color-primary-700)', + 800: 'var(--color-primary-800)', + 900: 'var(--color-primary-900)' + } + }, + spacing: { + px: '1px', + page: 'var(--padding-page)', + 0: '0', + 1: '0.25rem', + 2: '0.5rem', + 3: '0.75rem', + 4: '1rem', + 5: '1.25rem', + 6: '1.5rem', + 8: '2rem', + 10: '2.5rem', + 12: '3rem', + 14: '3.5rem', + 16: '4rem', + 20: '5rem', + 24: '6rem', + 32: '8rem', + 40: '10rem', + 48: '12rem', + 56: '14rem', + 64: '16rem' + }, + backgroundColor: theme => ({ + base: 'var(--background-base)', + card: 'var(--background-card)', + 'app-bar': 'var(--background-app-bar)', + hover: 'var(--background-hover)', + ...theme('colors') + }), + backgroundPosition: { + bottom: 'bottom', + center: 'center', + left: 'left', + 'left-bottom': 'left bottom', + 'left-top': 'left top', + right: 'right', + 'right-bottom': 'right bottom', + 'right-top': 'right top', + top: 'top' + }, + backgroundSize: { + auto: 'auto', + cover: 'cover', + contain: 'contain' + }, + borderColor: theme => ({ + ...theme('colors'), + DEFAULT: 'var(--foreground-divider)', + color: 'var(--border)' + }), + borderRadius: { + none: '0', + sm: '0.125rem', + DEFAULT: '0.25rem', + lg: '0.5rem', + full: '9999px' + }, + borderWidth: { + DEFAULT: '1px', + 0: '0', + 2: '2px', + 4: '4px', + 8: '8px' + }, + boxShadow: { + b: '0 10px 30px 0 rgba(82, 63, 104, .06)', + DEFAULT: 'var(--elevation-default)', + 1: 'var(--elevation-z1)', + 2: 'var(--elevation-z2)', + 3: 'var(--elevation-z3)', + 4: 'var(--elevation-z4)', + 5: 'var(--elevation-z5)', + 6: 'var(--elevation-z6)', + 7: 'var(--elevation-z7)', + 8: 'var(--elevation-z8)', + 9: 'var(--elevation-z9)', + 10: 'var(--elevation-z10)', + 11: 'var(--elevation-z11)', + 12: 'var(--elevation-z12)', + 13: 'var(--elevation-z13)', + 14: 'var(--elevation-z14)', + 15: 'var(--elevation-z15)', + 16: 'var(--elevation-z16)', + 17: 'var(--elevation-z17)', + 18: 'var(--elevation-z18)', + 19: 'var(--elevation-z19)', + 20: 'var(--elevation-z20)', + none: 'none' + }, + container: { + center: true, + padding: 'var(--padding-page)' + }, + cursor: { + auto: 'auto', + DEFAULT: 'default', + pointer: 'pointer', + wait: 'wait', + text: 'text', + move: 'move', + 'not-allowed': 'not-allowed' + }, + fill: { + current: 'currentColor' + }, + flex: { + 1: '1 1 0%', + auto: '1 1 auto', + initial: '0 1 auto', + none: 'none' + }, + flexGrow: { + 0: '0', + DEFAULT: '1' + }, + flexShrink: { + 0: '0', + DEFAULT: '1' + }, + fontFamily: { + sans: ['Open Sans'], + serif: ['Georgia', 'Cambria', '"Times New Roman"', 'Times', 'serif'], + mono: ['Menlo', 'Monaco', 'Consolas', '"Liberation Mono"', '"Courier New"', 'monospace'] + }, + fontSize: { + xs: '0.75rem', + sm: '0.875rem', + base: '1rem', + lg: '1.125rem', + xl: '1.25rem', + '2xl': '1.5rem', + '3xl': '1.875rem', + '4xl': '2.25rem', + '5xl': '3rem', + '6xl': '4rem' + }, + fontWeight: { + hairline: '100', + thin: '200', + light: '300', + normal: '400', + medium: '500', + semibold: '600', + bold: '700', + extrabold: '800', + black: '900' + }, + gridTemplateColumns: { + none: 'none', + 1: 'repeat(1, minmax(0, 1fr))', + 2: 'repeat(2, minmax(0, 1fr))', + 3: 'repeat(3, minmax(0, 1fr))', + 4: 'repeat(4, minmax(0, 1fr))', + 5: 'repeat(5, minmax(0, 1fr))', + 6: 'repeat(6, minmax(0, 1fr))', + 7: 'repeat(7, minmax(0, 1fr))', + 8: 'repeat(8, minmax(0, 1fr))', + 9: 'repeat(9, minmax(0, 1fr))', + 10: 'repeat(10, minmax(0, 1fr))', + 11: 'repeat(11, minmax(0, 1fr))', + 12: 'repeat(12, minmax(0, 1fr))' + }, + gridColumn: { + auto: 'auto', + 'span-1': 'span 1 / span 1', + 'span-2': 'span 2 / span 2', + 'span-3': 'span 3 / span 3', + 'span-4': 'span 4 / span 4', + 'span-5': 'span 5 / span 5', + 'span-6': 'span 6 / span 6', + 'span-7': 'span 7 / span 7', + 'span-8': 'span 8 / span 8', + 'span-9': 'span 9 / span 9', + 'span-10': 'span 10 / span 10', + 'span-11': 'span 11 / span 11', + 'span-12': 'span 12 / span 12' + }, + gridColumnStart: { + auto: 'auto', + 1: '1', + 2: '2', + 3: '3', + 4: '4', + 5: '5', + 6: '6', + 7: '7', + 8: '8', + 9: '9', + 10: '10', + 11: '11', + 12: '12', + 13: '13' + }, + gridColumnEnd: { + auto: 'auto', + 1: '1', + 2: '2', + 3: '3', + 4: '4', + 5: '5', + 6: '6', + 7: '7', + 8: '8', + 9: '9', + 10: '10', + 11: '11', + 12: '12', + 13: '13' + }, + gridTemplateRows: { + none: 'none', + 1: 'repeat(1, minmax(0, 1fr))', + 2: 'repeat(2, minmax(0, 1fr))', + 3: 'repeat(3, minmax(0, 1fr))', + 4: 'repeat(4, minmax(0, 1fr))', + 5: 'repeat(5, minmax(0, 1fr))', + 6: 'repeat(6, minmax(0, 1fr))' + }, + gridRow: { + auto: 'auto', + 'span-1': 'span 1 / span 1', + 'span-2': 'span 2 / span 2', + 'span-3': 'span 3 / span 3', + 'span-4': 'span 4 / span 4', + 'span-5': 'span 5 / span 5', + 'span-6': 'span 6 / span 6' + }, + gridRowStart: { + auto: 'auto', + 1: '1', + 2: '2', + 3: '3', + 4: '4', + 5: '5', + 6: '6', + 7: '7' + }, + gridRowEnd: { + auto: 'auto', + 1: '1', + 2: '2', + 3: '3', + 4: '4', + 5: '5', + 6: '6', + 7: '7' + }, + height: theme => ({ + auto: 'auto', + ...theme('spacing'), + full: '100%', + screen: '100vh' + }), + inset: { + 0: '0', + 1: '0.25rem', + 2: '0.5rem', + 3: '0.75rem', + 4: '1rem', + 5: '1.25rem', + 6: '1.5rem', + 8: '2rem', + '-1': '-0.25rem', + '-2': '-0.5rem', + '-3': '-0.75rem', + '-4': '-1rem', + '-5': '-1.25rem', + '-6': '-1.5rem', + '-8': '-2rem', + auto: 'auto' + }, + letterSpacing: { + tighter: '-0.05em', + tight: '-0.025em', + normal: '0', + wide: '0.025em', + wider: '0.05em', + widest: '0.1em' + }, + lineHeight: { + none: '1', + tight: '1.25', + snug: '1.375', + normal: '1.5', + relaxed: '1.625', + loose: '2' + }, + listStyleType: { + none: 'none', + disc: 'disc', + decimal: 'decimal' + }, + margin: (theme, { negative }) => ({ + auto: 'auto', + ...theme('spacing'), + ...negative(theme('spacing')), + ...negative({ + page: 'var(--padding-page)' + }) + }), + maxHeight: { + full: '100%', + screen: '100vh' + }, + maxWidth: { + xxs: '18rem', + xs: '20rem', + sm: '24rem', + md: '28rem', + lg: '32rem', + xl: '36rem', + '2xl': '42rem', + '3xl': '48rem', + '4xl': '56rem', + '5xl': '64rem', + '6xl': '72rem', + full: '100%' + }, + minHeight: { + 0: '0', + full: '100%', + screen: '100vh' + }, + minWidth: { + 0: '0', + full: '100%' + }, + objectPosition: { + bottom: 'bottom', + center: 'center', + left: 'left', + 'left-bottom': 'left bottom', + 'left-top': 'left top', + right: 'right', + 'right-bottom': 'right bottom', + 'right-top': 'right top', + top: 'top' + }, + opacity: { + 0: '0', + 25: '0.25', + 50: '0.5', + 75: '0.75', + 100: '1' + }, + order: { + first: '-9999', + last: '9999', + none: '0', + 1: '1', + 2: '2', + 3: '3', + 4: '4', + 5: '5', + 6: '6', + 7: '7', + 8: '8', + 9: '9', + 10: '10', + 11: '11', + 12: '12' + }, + padding: theme => theme('spacing'), + placeholderColor: theme => theme('colors'), + stroke: { + current: 'currentColor' + }, + textColor: theme => ({ + secondary: 'var(--text-secondary)', + hint: 'var(--text-hint)', + ...theme('colors'), + 'primary-contrast': { + 50: 'var(--color-primary-contrast-50)', + 100: 'var(--color-primary-contrast-100)', + 200: 'var(--color-primary-contrast-200)', + 300: 'var(--color-primary-contrast-300)', + 400: 'var(--color-primary-contrast-400)', + 500: 'var(--color-primary-contrast-500)', + 600: 'var(--color-primary-contrast-600)', + 700: 'var(--color-primary-contrast-700)', + 800: 'var(--color-primary-contrast-800)', + 900: 'var(--color-primary-contrast-900)' + } + }), + width: theme => ({ + auto: 'auto', + ...theme('spacing'), + '1/2': '50%', + '1/3': '33.333333%', + '2/3': '66.666667%', + '1/4': '25%', + '2/4': '50%', + '3/4': '75%', + '1/5': '20%', + '2/5': '40%', + '3/5': '60%', + '4/5': '80%', + '1/6': '16.666667%', + '2/6': '33.333333%', + '3/6': '50%', + '4/6': '66.666667%', + '5/6': '83.333333%', + '1/12': '8.333333%', + '2/12': '16.666667%', + '3/12': '25%', + '4/12': '33.333333%', + '5/12': '41.666667%', + '6/12': '50%', + '7/12': '58.333333%', + '8/12': '66.666667%', + '9/12': '75%', + '10/12': '83.333333%', + '11/12': '91.666667%', + full: '100%', + screen: '100vw' + }), + zIndex: { + auto: 'auto', + 0: '0', + 10: '10', + 20: '20', + 30: '30', + 40: '40', + 50: '50' + } + }, + variants: { + accessibility: ['responsive', 'focus'], + alignContent: ['responsive'], + alignItems: ['responsive'], + alignSelf: ['responsive'], + appearance: ['responsive'], + backgroundAttachment: ['responsive'], + backgroundColor: ['responsive', 'hover', 'focus'], + backgroundPosition: ['responsive'], + backgroundRepeat: ['responsive'], + backgroundSize: ['responsive'], + borderCollapse: ['responsive'], + borderColor: ['responsive', 'hover', 'focus'], + borderRadius: ['responsive'], + borderStyle: ['responsive'], + borderWidth: ['responsive', 'ltr', 'rtl'], + boxShadow: ['responsive', 'hover', 'focus'], + cursor: ['responsive'], + display: ['responsive'], + fill: ['responsive'], + // Flex + flex: ['responsive'], + flexDirection: ['responsive'], + flexGrow: ['responsive'], + flexShrink: ['responsive'], + flexWrap: ['responsive'], + float: ['responsive'], + fontFamily: ['responsive'], + fontSize: ['responsive'], + fontSmoothing: ['responsive'], + fontStyle: ['responsive'], + fontWeight: ['responsive', 'hover', 'focus'], + // Grid + gridAutoFlow: ['responsive'], + gridTemplateColumns: ['responsive'], + gridAutoColumns: ['responsive'], + gridColumn: ['responsive'], + gridColumnStart: ['responsive'], + gridColumnEnd: ['responsive'], + gridTemplateRows: ['responsive'], + gridAutoRows: ['responsive'], + gridRow: ['responsive'], + gridRowStart: ['responsive'], + gridRowEnd: ['responsive'], + height: ['responsive'], + inset: ['responsive'], + justifyContent: ['responsive'], + letterSpacing: ['responsive'], + lineHeight: ['responsive'], + listStylePosition: ['responsive'], + listStyleType: ['responsive'], + margin: ['responsive', 'ltr', 'rtl'], + maxHeight: ['responsive'], + maxWidth: ['responsive'], + minHeight: ['responsive'], + minWidth: ['responsive'], + objectFit: ['responsive'], + objectPosition: ['responsive'], + opacity: ['responsive', 'hover', 'focus'], + order: ['responsive'], + outline: ['responsive', 'focus'], + overflow: ['responsive'], + padding: ['responsive', 'ltr', 'rtl'], + placeholderColor: ['responsive', 'focus'], + pointerEvents: ['responsive'], + position: ['responsive'], + resize: ['responsive'], + stroke: ['responsive'], + tableLayout: ['responsive'], + textAlign: ['responsive'], + textColor: ['responsive', 'hover', 'focus'], + textDecoration: ['responsive', 'hover', 'focus'], + textTransform: ['responsive'], + userSelect: ['responsive'], + verticalAlign: ['responsive'], + visibility: ['responsive'], + whitespace: ['responsive'], + width: ['responsive'], + wordBreak: ['responsive'], + zIndex: ['responsive'] + }, + corePlugins: {}, + plugins: [ + function ({ addVariant, e }) { + addVariant('ltr', ({ separator, modifySelectors }) => { + modifySelectors(({ className }) => { + return `[dir=ltr] .ltr${e(separator)}${className}`; + }); + }); + + addVariant('rtl', ({ separator, modifySelectors }) => { + modifySelectors(({ className }) => { + return `[dir=rtl] .rtl${e(separator)}${className}`; + }); + }); + } + ] +}; diff --git a/frontend/tsconfig.app.json b/frontend/tsconfig.app.json new file mode 100644 index 0000000..29f5f58 --- /dev/null +++ b/frontend/tsconfig.app.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": [] + }, + "files": ["src/main.ts", "src/polyfills.ts"], + "include": ["src/**/*.d.ts"] +} diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json new file mode 100644 index 0000000..220264b --- /dev/null +++ b/frontend/tsconfig.json @@ -0,0 +1,36 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist/out-tsc", + "sourceMap": true, + "declaration": false, + "downlevelIteration": true, + "experimentalDecorators": true, + "module": "es2020", + "moduleResolution": "node", + "importHelpers": true, + "target": "es2020", + "allowSyntheticDefaultImports": true, + "typeRoots": ["node_modules/@types"], + "lib": ["es2018", "dom"], + "paths": { + "@cluster/*": ["src/app/cluster/*"], + "@billing/*": ["src/app/billing/*"], + "@management/*": ["src/app/management/*"], + "@settings/*": ["src/app/settings/*"], + "@k8s/*": ["src/app/k8s/*"], + "@helm-apps/*": ["src/app/helm-apps/*"], + "@env/*": ["src/environments/*"], + "@klovercloud/*": ["src/libs/*"], + "@cdk-ui/*": ["projects/cdk-ui/src/*"], + "@core-ui/*": ["projects/core-ui/src/*"], + "@sdk-ui/*": ["projects/sdk-ui/src/*"], + "@shared-ui/*": ["projects/shared-ui/src/*"] + } + }, + "angularCompilerOptions": { + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true + } +} diff --git a/frontend/tsconfig.spec.json b/frontend/tsconfig.spec.json new file mode 100644 index 0000000..430cf75 --- /dev/null +++ b/frontend/tsconfig.spec.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/spec", + "types": ["jasmine", "node"] + }, + "files": ["src/test.ts", "src/polyfills.ts"], + "include": ["src/**/*.spec.ts", "src/**/*.d.ts"] +} diff --git a/frontend/tslint.json b/frontend/tslint.json new file mode 100644 index 0000000..cfc310c --- /dev/null +++ b/frontend/tslint.json @@ -0,0 +1,99 @@ +{ + "extends": "tslint:recommended", + "rules": { + "align": { + "options": ["parameters", "statements"] + }, + "array-type": false, + "arrow-parens": false, + "arrow-return-shorthand": true, + "deprecation": { + "severity": "warning" + }, + "component-class-suffix": true, + "contextual-lifecycle": true, + "curly": true, + "directive-class-suffix": true, + "directive-selector": [true, "attribute", "kc", "camelCase"], + "component-selector": [true, "element", "kc", "kebab-case"], + "eofline": true, + "import-blacklist": [true, "rxjs/Rx"], + "import-spacing": true, + "indent": { + "options": ["spaces"] + }, + "interface-name": false, + "max-classes-per-file": false, + "max-line-length": [true, 200], + "member-access": false, + "member-ordering": [ + true, + { + "order": ["static-field", "instance-field", "static-method", "instance-method"] + } + ], + "no-consecutive-blank-lines": false, + "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], + "no-empty": false, + "no-inferrable-types": [true, "ignore-params"], + "no-non-null-assertion": true, + "no-redundant-jsdoc": true, + "no-switch-case-fall-through": true, + "no-var-requires": false, + "object-literal-key-quotes": [true, "as-needed"], + "object-literal-sort-keys": false, + "ordered-imports": false, + "quotemark": [true, "single"], + "trailing-comma": false, + "no-conflicting-lifecycle": true, + "no-host-metadata-property": true, + "no-input-rename": true, + "no-inputs-metadata-property": true, + "no-output-native": true, + "no-output-on-prefix": true, + "no-output-rename": true, + "no-outputs-metadata-property": true, + "semicolon": { + "options": ["always"] + }, + "space-before-function-paren": { + "options": { + "anonymous": "never", + "asyncArrow": "always", + "constructor": "never", + "method": "never", + "named": "never" + } + }, + "template-banana-in-box": true, + "template-no-negated-async": true, + "use-lifecycle-interface": true, + "typedef-whitespace": { + "options": [ + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + }, + { + "call-signature": "onespace", + "index-signature": "onespace", + "parameter": "onespace", + "property-declaration": "onespace", + "variable-declaration": "onespace" + } + ] + }, + "use-pipe-transform-interface": true, + "no-string-literal": false, + "variable-name": { + "options": ["allow-pascal-case", "allow-leading-underscore"] + }, + "whitespace": { + "options": ["check-branch", "check-decl", "check-operator", "check-separator", "check-type", "check-typecast"] + } + }, + "rulesDirectory": ["codelyzer"] +} diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js new file mode 100644 index 0000000..68a7eee --- /dev/null +++ b/frontend/webpack.config.js @@ -0,0 +1,41 @@ +const path = require('path'); + +let sassImplementation; +try { + // tslint:disable-next-line:no-implicit-dependencies + sassImplementation = require('node-sass'); +} catch { + sassImplementation = require('sass'); +} + +module.exports = { + module: { + rules: [ + { + test: /\.scss$/, + use: [ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + ident: 'postcss', + syntax: 'postcss-scss', + plugins: ['postcss-import', 'tailwindcss'] + } + } + }, + { + loader: 'sass-loader', + options: { + implementation: sassImplementation, + sourceMap: false, + sassOptions: { + precision: 8 + } + } + } + ] + } + ] + } +}; diff --git a/frontend/webpack.prod.config.js b/frontend/webpack.prod.config.js new file mode 100644 index 0000000..9896f24 --- /dev/null +++ b/frontend/webpack.prod.config.js @@ -0,0 +1,78 @@ +const path = require('path'); + +let sassImplementation; +try { + // tslint:disable-next-line:no-implicit-dependencies + sassImplementation = require('node-sass'); +} catch { + sassImplementation = require('sass'); +} + +module.exports = { + module: { + rules: [ + { + test: /\.scss$/, + use: [ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + ident: 'postcss', + syntax: 'postcss-scss', + plugins: ['postcss-import', 'tailwindcss'] + } + } + }, + { + loader: 'sass-loader', + options: { + implementation: sassImplementation, + sourceMap: false, + sassOptions: { + precision: 8 + } + } + } + ] + }, + { + test: /projects[\\\/]sdk-ui[\\\/]assets[\\\/]styles[\\\/]tailwind\.scss$/, + use: [ + { + loader: '@fullhuman/purgecss-loader', + options: { + content: [ + path.join(__dirname, 'src/**/*.html'), + path.join(__dirname, 'src/**/*.ts'), + path.join(__dirname, 'projects/**/*.html'), + path.join(__dirname, 'projects/**/*.ts') + ], + defaultExtractor: content => content.match(/[\w-/:]+(? Date: Wed, 5 Feb 2025 11:16:04 +0600 Subject: [PATCH 45/64] Remove k8s terminal --- frontend/package-lock.json | 46 ------- frontend/package.json | 1 - frontend/src/app/app.routes.ts | 4 - frontend/src/app/k8s/k8s-routing.module.ts | 4 - .../k8s-terminal-routing.module.ts | 22 ---- .../k8s/k8s-terminal/k8s-terminal.module.ts | 11 -- .../pod-terminal/pod-terminal.component.html | 4 - .../pod-terminal/pod-terminal.component.scss | 0 .../pod-terminal/pod-terminal.component.ts | 120 ------------------ 9 files changed, 212 deletions(-) delete mode 100644 frontend/src/app/k8s/k8s-terminal/k8s-terminal-routing.module.ts delete mode 100644 frontend/src/app/k8s/k8s-terminal/k8s-terminal.module.ts delete mode 100644 frontend/src/app/k8s/k8s-terminal/pod-terminal/pod-terminal.component.html delete mode 100644 frontend/src/app/k8s/k8s-terminal/pod-terminal/pod-terminal.component.scss delete mode 100644 frontend/src/app/k8s/k8s-terminal/pod-terminal/pod-terminal.component.ts diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 0528ddb..61bb65c 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -37,7 +37,6 @@ "moment": "^2.30.1", "net": "1.0.2", "ng-pick-datetime-ex": "^14.0.0", - "ng-terminal": "^6.1.0", "ng2-search-filter": "0.5.1", "ngx-webstorage": "^10.0.1", "normalize.css": "8.0.1", @@ -3765,11 +3764,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@juggle/resize-observer": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz", - "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==" - }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", @@ -4544,19 +4538,6 @@ "@xtuc/long": "4.2.2" } }, - "node_modules/@xterm/addon-fit": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.9.0.tgz", - "integrity": "sha512-hDlPPbTVPYyvwXu/asW8HbJkI/2RMi0cMaJnBZYVeJB0SWP2NeESMCNr+I7CvBlyI0sAxpxOg8Wk4OMkxBz9WA==", - "peerDependencies": { - "@xterm/xterm": "^5.0.0" - } - }, - "node_modules/@xterm/xterm": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz", - "integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==" - }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -4811,17 +4792,6 @@ "ajv": "^6.9.1" } }, - "node_modules/angular-resizable-element": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/angular-resizable-element/-/angular-resizable-element-5.0.0.tgz", - "integrity": "sha512-GbV8myA2x8aUU8CK7siTi1QMjtilzQzIgClqUVpE/YM1WAp0/OnioBV12oLcOT24eEwP3zDqPTHL+D1Kv2rNAw==", - "dependencies": { - "tslib": "^2.2.0" - }, - "peerDependencies": { - "@angular/core": ">=10.0.0" - } - }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -10996,22 +10966,6 @@ "@angular/core": "^14.0.6" } }, - "node_modules/ng-terminal": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/ng-terminal/-/ng-terminal-6.2.0.tgz", - "integrity": "sha512-0re4RPz4CJMAwliuvhOd2X5vqgTXllqdHcyVrWhTabGg4E9vscU8J/oWz8FsXD3D5WCdNvAU/XYF2SgGZon49g==", - "dependencies": { - "@juggle/resize-observer": "^3.4.0", - "@xterm/addon-fit": "^0.9.0", - "@xterm/xterm": "^5.5.0", - "angular-resizable-element": "^5.0.0", - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/common": "^18.0.0 || ^17.0.0 || ^16.0.0", - "@angular/core": "^18.0.0 || ^17.0.0 || ^16.0.0" - } - }, "node_modules/ng2-search-filter": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/ng2-search-filter/-/ng2-search-filter-0.5.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index 9242319..e0a8d6c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -45,7 +45,6 @@ "moment": "^2.30.1", "net": "1.0.2", "ng-pick-datetime-ex": "^14.0.0", - "ng-terminal": "^6.1.0", "ng2-search-filter": "0.5.1", "ngx-webstorage": "^10.0.1", "normalize.css": "8.0.1", diff --git a/frontend/src/app/app.routes.ts b/frontend/src/app/app.routes.ts index 8832e34..bd6fc0f 100644 --- a/frontend/src/app/app.routes.ts +++ b/frontend/src/app/app.routes.ts @@ -82,10 +82,6 @@ export const appRoutes: Routes = [ path: 'auth', loadChildren: () => import('./auth/auth.module').then(m => m.AuthModule) }, - { - path: 'k8s/terminal', - loadChildren: () => import('./k8s/k8s-terminal/k8s-terminal.module').then(m => m.K8sTerminalModule) - }, { path: '', component: LayoutComponent, diff --git a/frontend/src/app/k8s/k8s-routing.module.ts b/frontend/src/app/k8s/k8s-routing.module.ts index a4e9ece..c3c2e36 100644 --- a/frontend/src/app/k8s/k8s-routing.module.ts +++ b/frontend/src/app/k8s/k8s-routing.module.ts @@ -58,10 +58,6 @@ const k8sRoutes: Routes = [ data: { permissions: ['VIEW_K8S_CUSTOM_RESOURCE_DEFINATION'] } - }, - { - path: 'terminal', - loadChildren: () => import('./k8s-terminal/k8s-terminal.module').then(m => m.K8sTerminalModule) } ]; diff --git a/frontend/src/app/k8s/k8s-terminal/k8s-terminal-routing.module.ts b/frontend/src/app/k8s/k8s-terminal/k8s-terminal-routing.module.ts deleted file mode 100644 index 23c1f68..0000000 --- a/frontend/src/app/k8s/k8s-terminal/k8s-terminal-routing.module.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; -import { RoleGuardService } from '@core-ui/guards'; -import { PodTerminalComponent } from './pod-terminal/pod-terminal.component'; - -const routes: Routes = [ - { - path: '', - component: PodTerminalComponent, - data: { - title: 'Terminal', - permissions: ['*'] - }, - canActivate: [RoleGuardService] - } -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule] -}) -export class K8sTerminalRoutingModule {} diff --git a/frontend/src/app/k8s/k8s-terminal/k8s-terminal.module.ts b/frontend/src/app/k8s/k8s-terminal/k8s-terminal.module.ts deleted file mode 100644 index 32eb40d..0000000 --- a/frontend/src/app/k8s/k8s-terminal/k8s-terminal.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { NgTerminalModule } from 'ng-terminal'; -import { K8sTerminalRoutingModule } from './k8s-terminal-routing.module'; -import { PodTerminalComponent } from './pod-terminal/pod-terminal.component'; - -@NgModule({ - declarations: [PodTerminalComponent], - imports: [CommonModule, K8sTerminalRoutingModule, NgTerminalModule] -}) -export class K8sTerminalModule {} diff --git a/frontend/src/app/k8s/k8s-terminal/pod-terminal/pod-terminal.component.html b/frontend/src/app/k8s/k8s-terminal/pod-terminal/pod-terminal.component.html deleted file mode 100644 index 79479e3..0000000 --- a/frontend/src/app/k8s/k8s-terminal/pod-terminal/pod-terminal.component.html +++ /dev/null @@ -1,4 +0,0 @@ -
    - -
    - diff --git a/frontend/src/app/k8s/k8s-terminal/pod-terminal/pod-terminal.component.scss b/frontend/src/app/k8s/k8s-terminal/pod-terminal/pod-terminal.component.scss deleted file mode 100644 index e69de29..0000000 diff --git a/frontend/src/app/k8s/k8s-terminal/pod-terminal/pod-terminal.component.ts b/frontend/src/app/k8s/k8s-terminal/pod-terminal/pod-terminal.component.ts deleted file mode 100644 index 020f6da..0000000 --- a/frontend/src/app/k8s/k8s-terminal/pod-terminal/pod-terminal.component.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { Component, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; -import { Terminal } from 'xterm'; -import * as SockJS from 'sockjs-client'; -import { NgTerminal } from 'ng-terminal'; -import { ActivatedRoute } from '@angular/router'; -import { RequesterService } from '@core-ui/services/requester.service'; - -@Component({ - selector: 'kc-pod-terminal', - templateUrl: './pod-terminal.component.html', - styleUrls: ['./pod-terminal.component.scss'] -}) -export class PodTerminalComponent implements OnInit, OnDestroy { - @ViewChild('term', { static: true }) child: NgTerminal; - cols = parseInt(String(document.body.clientWidth / 9)); - rows = parseInt(String(document.body.clientHeight / 15.9)); - underlying: Terminal; - connectContainer = false; - appVpcId: string; - pod: string; - requester: any; - domain: string; - containerName; - clusterId; - namespace; - socket: any; - - constructor( - private route: ActivatedRoute, - private requesterService: RequesterService - ) { - this.requester = this.requesterService.get(); - this.route.paramMap.subscribe(params => { - // @ts-ignore - //this.appVpcId = params.params.appVpcId; - // @ts-ignore - //this.pod = params.params.pod; - }); - } - - ngOnInit() { - this.route.queryParams.subscribe(res => { - console.log(res.containerName, 'CONTAINER_NAME'); - this.containerName = res.containerName; - this.domain = atob(res.domain); - this.clusterId = res.clusterId; - this.namespace = res.namespace; - this.pod = res.pod; - this.wsConnect(); - }); - } - - ngOnDestroy(): void { - this.socket?.close(); - } - - wsConnect() { - const that = this; - const term = new Terminal({ - cursorBlink: true, - rows: this.rows, - cols: this.cols - }); - term.onData(data => { - if (this.socket.readyState === 1) { - this.socket.send(data); - term.focus(); - } - }); - const url = - this.domain + - '/terminal/ws?' + - 'token=' + - this.requester.token + - '&pod=' + - this.pod + - '&containerName=' + - this.containerName + - '&namespace=' + - this.namespace + - '&clusterId=' + - this.clusterId + - '&rows=' + - this.rows + - '&cols=' + - this.cols; - console.log(this.domain, url); - // Generate socket object - this.socket = new SockJS(url); - const termDiv = document.getElementById('terminal-container'); - termDiv.innerHTML = ''; - term.write('\x1B[7;1;34m [Hello From KloverCloud!] \x1B[0m \n'); - term.open(document.getElementById('terminal-container')); - this.socket.onmessage = e => { - this.connectContainer = false; - this.resize(this.socket, term); - term.write(e.data); - }; - this.socket.onclose = e => { - term.write('\x1B[3;1;31m Session Is Closed! \x1B[0m'); - this.connectContainer = true; - }; - this.socket.onopen = () => { - that.resize(this.socket, term); - }; - window.onresize = () => { - // @ts-ignore - that.resize(this.socket, term); - }; - } - - resize(socket, term) { - this.cols = parseInt(String(document.body.clientWidth / 9)); - this.rows = parseInt(String(document.body.clientHeight / 15.9)); - term.resize(this.cols, this.rows); - if (socket.readyState === 1) { - socket.send('{"cols":' + this.cols + ',"rows":' + this.rows + '}'); - } - } -} From 18b38565ab74c55b46019cb44f0447087b47f981 Mon Sep 17 00:00:00 2001 From: Toha Date: Wed, 5 Feb 2025 13:30:34 +0600 Subject: [PATCH 46/64] deployment pod list bug --- pkg/.env | 2 +- pkg/controller/api/deployment.go | 3 --- pkg/k8s/deployment.go | 41 ++++++++++---------------------- 3 files changed, 13 insertions(+), 33 deletions(-) diff --git a/pkg/.env b/pkg/.env index e7824ae..ddaea2c 100644 --- a/pkg/.env +++ b/pkg/.env @@ -13,5 +13,5 @@ JWT_REFRESH_SECRET=your_refresh_jwt_secret_key ACCESS_TOKEN_EXPIRY=15m REFRESH_TOKEN_EXPIRY=24h #TRUE/FALSE -AUTH_ENABLED="TRUE" +AUTH_ENABLED="FALSE" KUBE_CONFIG_FILE="dev-config.yaml" \ No newline at end of file diff --git a/pkg/controller/api/deployment.go b/pkg/controller/api/deployment.go index 5a879a0..09df247 100644 --- a/pkg/controller/api/deployment.go +++ b/pkg/controller/api/deployment.go @@ -240,9 +240,6 @@ func (ctrl *deploymentController) GetDeploymentPodList(ctx *gin.Context) { return } input.Replicaset = queryReplicaSet - input.Continue = ctx.Query("continue") - input.Search = ctx.Query("q") - input.Limit = ctx.Query("limit") queryLabel := ctx.Query("labels") if queryLabel != "" { diff --git a/pkg/k8s/deployment.go b/pkg/k8s/deployment.go index 8ec5b7a..15c23a8 100644 --- a/pkg/k8s/deployment.go +++ b/pkg/k8s/deployment.go @@ -382,19 +382,14 @@ func (svc *deploymentService) GetDeploymentStats(c context.Context, p GetDeploym } type DeploymentPodOutput struct { - PodList []corev1.Pod - Resource string - Remaining int64 + PodList []corev1.Pod } type GetDeploymentPodListInputParams struct { NamespaceName string DeploymentName string Replicaset string - Limit string Labels map[string]string - Search string - Continue string output DeploymentPodOutput } @@ -414,14 +409,8 @@ func (p *GetDeploymentPodListInputParams) Process(c context.Context) error { if replicaSet.Labels[PodTemplateHash] != "" { podClient := cfg.GetKubeClientSet().CoreV1().Pods(p.NamespaceName) - limit := cfg.PageLimit - if p.Limit != "" { - limit, _ = strconv.ParseInt(p.Limit, 10, 64) - } - listOptions := metav1.ListOptions{Limit: limit, Continue: p.Continue} - if p.Labels == nil { - p.Labels = make(map[string]string) - } + listOptions := metav1.ListOptions{} + p.Labels = make(map[string]string) p.Labels["pod-template-hash"] = replicaSet.Labels["pod-template-hash"] labelSelector := metav1.LabelSelector{MatchLabels: p.Labels} if p.Labels != nil { @@ -429,27 +418,21 @@ func (p *GetDeploymentPodListInputParams) Process(c context.Context) error { LabelSelector: labels.Set(labelSelector.MatchLabels).String(), } } - if p.Search != "" { - listOptions.FieldSelector = fields.OneTermEqualSelector("metadata.name", p.Search).String() - } podList, err := podClient.List(context.Background(), listOptions) if err != nil { log.Logger.Errorw("Failed to get pod list", "err", err.Error()) return err } - p.output.PodList = podList.Items - for idx, _ := range p.output.PodList { - p.output.PodList[idx].ManagedFields = nil - } - remaining := podList.RemainingItemCount - - if remaining != nil { - p.output.Remaining = *remaining - } else { - p.output.Remaining = 0 + p.output.PodList = []corev1.Pod{} + for idx, _ := range podList.Items { + podList.Items[idx].ManagedFields = nil + for _, owner := range podList.Items[idx].OwnerReferences { + if owner.UID == replicaSet.UID { + p.output.PodList = append(p.output.PodList, podList.Items[idx]) + break // Pod can only have one controller + } + } } - - p.output.Resource = podList.Continue } else { return errors.New("unable to fetch pod list") } From 74ca4429c46e98ac843779180b60aa38e81ace9d Mon Sep 17 00:00:00 2001 From: Nahid Date: Wed, 5 Feb 2025 14:09:00 +0600 Subject: [PATCH 47/64] feat: register permissions, implement reset password API. --- pkg/.env | 4 + pkg/auth/config/db.go | 4 +- pkg/auth/config/permission_initializer.go | 81 +++- pkg/auth/controllers/user_controller.go | 61 ++- pkg/auth/dto/permission_response_dto.go | 7 +- pkg/auth/dto/user_dto.go | 11 + pkg/auth/enum/permision_constants.go | 253 ++++++++---- pkg/auth/enum/permission_mapping.go | 308 +++++++++++++- pkg/auth/services/rbac_service.go | 15 +- pkg/auth/services/user_service.go | 94 +++++ pkg/auth/utils/endpoints.go | 470 ++++++++++++++++++---- pkg/auth/utils/utils.go | 10 + pkg/server/router/routes.go | 3 +- 13 files changed, 1115 insertions(+), 206 deletions(-) diff --git a/pkg/.env b/pkg/.env index ddaea2c..140e8ae 100644 --- a/pkg/.env +++ b/pkg/.env @@ -5,6 +5,10 @@ PORT=8080 MONGO_URI=mongodb://localhost:27017 DB_NAME=lighthouse +# Default User Configuration +USER_EMAIL=admin@default.com +PASSWORD=admin123 + # JWT Secrets JWT_SECRET=your_jwt_secret_key JWT_REFRESH_SECRET=your_refresh_jwt_secret_key diff --git a/pkg/auth/config/db.go b/pkg/auth/config/db.go index 57df95a..f7dc586 100644 --- a/pkg/auth/config/db.go +++ b/pkg/auth/config/db.go @@ -75,10 +75,10 @@ func InitializeDefaultUser() { if count == 0 { defaultUser := models.User{ - Username: "admin@default.com", + Username: os.Getenv("USER_EMAIL"), FirstName: "Admin", LastName: "User", - Password: utils.HashPassword("admin123"), // Use a hashed password here + Password: utils.HashPassword(os.Getenv("PASSWORD")), // Use a hashed password here UserType: "ADMIN", Roles: []models.Role{}, UserIsActive: true, diff --git a/pkg/auth/config/permission_initializer.go b/pkg/auth/config/permission_initializer.go index 6acb23a..f2d1a38 100644 --- a/pkg/auth/config/permission_initializer.go +++ b/pkg/auth/config/permission_initializer.go @@ -30,12 +30,85 @@ func NewPermissionInitializer(collection *mongo.Collection) *PermissionInitializ return pi } -// registerEndpoints maps permission names to their endpoint functions. register addational +// registerEndpoints maps permission names to their endpoint functions. register additional func (pi *PermissionInitializer) registerEndpoints() { pi.endpointRegistry = map[enum.PermissionName]func() []models.Endpoint{ - enum.DEFAULT_PERMISSION: utils.GetDefaultEndpoints, - enum.VIEW_NAMESPACE: utils.GetViewNamespaceEndpoints, - enum.MANAGE_NAMESPACE: utils.GetManageEndpointsEndpoints, + enum.DEFAULT_PERMISSION: utils.GetDefaultEndpoints, + enum.VIEW_USER: utils.GetUserEndpoints, + enum.MANAGE_USER: utils.GetManageUserEndpoints, + enum.VIEW_ROLE: utils.GetRolesEndpoints, + enum.MANAGE_ROLE: utils.GetManageRolesEndpoints, + enum.MANAGE_NAMESPACE: utils.GetManageEndpointsEndpoints, + enum.CREATE_NAMESPACE: utils.GetCreateNamespaceEndpoints, + enum.VIEW_NAMESPACE: utils.GetViewNamespaceEndpoints, + enum.UPDATE_NAMESPACE: utils.GetUpdateNamespaceEndpoints, + enum.DELETE_NAMESPACE: utils.GetDeleteNamespaceEndpoints, + enum.VIEW_DEPLOYMENT: utils.GetViewDeploymentEndpoints, + enum.VIEW_REPLICA_SET: utils.GetViewReplicaSetEndpoints, + enum.MANAGE_POD: utils.GetManagePodEndpoints, + enum.VIEW_POD: utils.GetViewPodEndpoints, + enum.MANAGE_DEPLOYMENT: utils.GetManageDeploymentEndpoints, + enum.MANAGE_REPLICA_SET: utils.GetManageReplicaSetEndpoints, + enum.VIEW_STATEFUL_SET: utils.GetViewStatefulSetEndpoints, + enum.MANAGE_STATEFUL_SET: utils.GetManageStatefulSetEndpoints, + enum.VIEW_DAEMON_SET: utils.GetViewDaemonSetEndpoints, + enum.MANAGE_DAEMON_SET: utils.GetManageDaemonSetEndpoints, + enum.VIEW_SECRET: utils.GetViewSecretEndpoints, + enum.MANAGE_SECRET: utils.GetManageSecretEndpoints, + enum.VIEW_CONFIG_MAP: utils.GetViewConfigMapEndpoints, + enum.MANAGE_CONFIG_MAP: utils.GetManageConfigMapEndpoints, + enum.VIEW_SERVICE_ACCOUNT: utils.GetViewServiceAccountEndpoints, + enum.MANAGE_SERVICE_ACCOUNT: utils.GetManageServiceAccountEndpoints, + enum.VIEW_SERVICE: utils.GetViewServiceEndpoints, + enum.MANAGE_SERVICE: utils.GetManageServiceEndpoints, + enum.VIEW_INGRESS: utils.GetViewIngressEndpoints, + enum.MANAGE_INGRESS: utils.GetManageIngressEndpoints, + enum.VIEW_CERTIFICATE: utils.GetViewCertificateEndpoints, + enum.MANAGE_CERTIFICATE: utils.GetManageCertificateEndpoints, + enum.VIEW_NAMESPACE_ROLE: utils.GetViewNamespaceRoleEndpoints, + enum.MANAGE_NAMESPACE_ROLE: utils.GetManageNamespaceRoleEndpoints, + enum.VIEW_NAMESPACE_ROLE_BINDING: utils.GetViewNamespaceRoleBindingEndpoints, + enum.MANAGE_NAMESPACE_ROLE_BINDING: utils.GetManageNamespaceRoleBindingEndpoints, + enum.VIEW_JOB: utils.GetViewJobEndpoints, + enum.MANAGE_JOB: utils.GetManageJobEndpoints, + enum.VIEW_CRON_JOB: utils.GetViewCronJobEndpoints, + enum.MANAGE_CRON_JOB: utils.GetManageCronJobEndpoints, + enum.VIEW_NAMESPACE_NETWORK_POLICY: utils.GetViewNetworkPolicyEndpoints, + enum.MANAGE_NAMESPACE_NETWORK_POLICY: utils.GetManageNetworkPolicyEndpoints, + enum.VIEW_NAMESPACE_RESOURCE_QUOTA: utils.GetViewResourceQuotaEndpoints, + enum.MANAGE_RESOURCE_QUOTA: utils.GetManageResourceQuotaEndpoints, + enum.VIEW_PERSISTENT_VOLUME: utils.GetViewPersistentVolumeEndpoints, + enum.MANAGE_PERSISTENT_VOLUME: utils.GetManagePersistentVolumeEndpoints, + enum.VIEW_PERSISTENT_VOLUME_CLAIM: utils.GetViewPersistentVolumeClaimEndpoints, + enum.MANAGE_PERSISTENT_VOLUME_CLAIM: utils.GetManagePersistentVolumeClaimEndpoints, + enum.VIEW_GATEWAY: utils.GetViewGatewayEndpoints, + enum.MANAGE_GATEWAY: utils.GetManageGatewayEndpoints, + enum.VIEW_VIRTUAL_SERVICE: utils.GetViewVirtualServiceEndpoints, + enum.MANAGE_VIRTUAL_SERVICE: utils.GetManageVirtualServiceEndpoints, + enum.VIEW_NODES: utils.GetViewNodeEndpoints, + enum.MANAGE_NODE_TAINT: utils.GetManageNodeTaintEndpoints, + enum.DRAIN_NODE: utils.GetDrainNodeEndpoints, + enum.VIEW_CLUSTER_ROLE: utils.GetViewClusterRoleEndpoints, + enum.MANAGE_CLUSTER_ROLE: utils.GetManageClusterRoleEndpoints, + enum.VIEW_CLUSTER_ROLE_BINDING: utils.GetViewClusterRoleBindingEndpoints, + enum.MANAGE_CLUSTER_ROLE_BINDING: utils.GetManageClusterRoleBindingEndpoints, + enum.VIEW_STORAGE_CLASS: utils.GetViewStorageClassEndpoints, + enum.MANAGE_STORAGE_CLASS: utils.GetManageStorageClassEndpoints, + enum.VIEW_CUSTOM_RESOURCES: utils.GetViewCustomResourceEndpoints, + enum.MANAGE_CUSTOM_RESOURCES: utils.GetManageCustomResourceEndpoints, + enum.VIEW_CUSTOM_RESOURCE_DEFINITION: utils.GetViewCustomResourceDefinitionEndpoints, + enum.MANAGE_CUSTOM_RESOURCE_DEFINITION: utils.GetManageCustomResourceDefinitionEndpoints, + enum.VIEW_LOGS: utils.GetViewLogsEndpoints, + enum.VIEW_ENDPOINTS: utils.GetViewEndpointSliceEndpoints, + enum.MANAGE_ENDPOINTS: utils.GetManageEndpointsEndpoints, + enum.VIEW_ENDPOINT_SLICE: utils.GetViewEndpointSliceEndpoints, + enum.MANAGE_ENDPOINT_SLICE: utils.GetManageEndpointSliceEndpoints, + enum.VIEW_PDB: utils.GetViewPDBEndpoints, + enum.MANAGE_PDB: utils.GetManagePDBEndpoints, + enum.VIEW_CONTROLLER_REVISION: utils.GetViewControllerRevisionEndpoints, + enum.MANAGE_CONTROLLER_REVISION: utils.GetManageControllerRevisionEndpoints, + enum.VIEW_REPLICATION_CONTROLLER: utils.GetViewReplicationControllerEndpoints, + enum.MANAGE_REPLICATION_CONTROLLER: utils.GetManageReplicationControllerEndpoints, // Add more mappings } } diff --git a/pkg/auth/controllers/user_controller.go b/pkg/auth/controllers/user_controller.go index 1391f44..503cf5d 100644 --- a/pkg/auth/controllers/user_controller.go +++ b/pkg/auth/controllers/user_controller.go @@ -67,7 +67,7 @@ func (uc *UserController) convertDTOToUser(ctx context.Context, userDTO dto.User Username: userDTO.Username, FirstName: userDTO.FirstName, LastName: userDTO.LastName, - Password: userDTO.Password, + Password: utils.HashPassword(userDTO.Password), UserType: models.UserType(userDTO.UserType), Roles: roles, ClusterIdList: userDTO.ClusterIdList, @@ -153,3 +153,62 @@ func (uc *UserController) GetUserProfileInfoHandler(c *gin.Context) { utils.RespondWithJSON(c, http.StatusOK, user) } + +// ResetPasswordHandler handles the password reset with old password verification +func (uc *UserController) ResetPasswordHandler(c *gin.Context) { + username, exists := c.Get("username") + if !exists { + c.JSON(http.StatusBadRequest, gin.H{"error": "Username not found in context.Please Enable AUTH"}) + return + } + // username is of type interface{}, so cast it to string + usernameStr := username.(string) + + userID := c.Param("id") + if userID == "" { + utils.RespondWithError(c, http.StatusBadRequest, "user ID is required") + return + } + + var req dto.ResetPasswordRequest + if err := c.ShouldBindJSON(&req); err != nil { + utils.RespondWithError(c, http.StatusBadRequest, "invalid request payload") + return + } + + // Convert string ID to ObjectID + objectID, err := primitive.ObjectIDFromHex(userID) + if err != nil { + utils.RespondWithError(c, http.StatusBadRequest, "invalid user ID format") + return + } + + err = uc.UserService.ResetPassword(objectID, req.CurrentPassword, req.NewPassword, usernameStr) + if err != nil { + utils.RespondWithError(c, http.StatusInternalServerError, err.Error()) + return + } + + utils.RespondWithJSON(c, http.StatusOK, gin.H{ + "message": "Password updated successfully", + }) +} + +// ForgotPasswordHandler handles initiating the forgot password process +func (uc *UserController) ForgotPasswordHandler(c *gin.Context) { + var req dto.ForgotPasswordRequest + if err := c.ShouldBindJSON(&req); err != nil { + utils.RespondWithError(c, http.StatusBadRequest, "invalid request payload") + return + } + + err := uc.UserService.InitiateForgotPassword(req.Username) + if err != nil { + utils.RespondWithError(c, http.StatusInternalServerError, err.Error()) + return + } + + utils.RespondWithJSON(c, http.StatusOK, gin.H{ + "message": "Password reset link sent to email", + }) +} diff --git a/pkg/auth/dto/permission_response_dto.go b/pkg/auth/dto/permission_response_dto.go index 2443648..46d32a8 100644 --- a/pkg/auth/dto/permission_response_dto.go +++ b/pkg/auth/dto/permission_response_dto.go @@ -4,9 +4,10 @@ import "go.mongodb.org/mongo-driver/bson/primitive" // PermissionResponse represents the formatted API response type PermissionResponse struct { - DEFAULT []PermissionDTO `json:"DEFAULT"` - CLUSTER []PermissionDTO `json:"CLUSTER"` - HelmApps []PermissionDTO `json:"HELM_APPS"` + Default []PermissionDTO `json:"DEFAULT"` + Cluster []PermissionDTO `json:"CLUSTER"` + Management []PermissionDTO `json:"MANAGEMENT"` + HelmApps []PermissionDTO `json:"HELM_APPS"` } // PermissionDTO represents the simplified permission response diff --git a/pkg/auth/dto/user_dto.go b/pkg/auth/dto/user_dto.go index 93f8b5c..19430dc 100644 --- a/pkg/auth/dto/user_dto.go +++ b/pkg/auth/dto/user_dto.go @@ -12,3 +12,14 @@ type UserDTO struct { IsVerified bool `json:"is_verified"` Phone string `json:"phone,omitempty"` } + +// ResetPasswordRequest represents the request payload for resetting password +type ResetPasswordRequest struct { + CurrentPassword string `json:"currentPassword" validate:"required"` + NewPassword string `json:"newPassword" validate:"required,min=6,max=15"` +} + +// ForgotPasswordRequest represents the request payload for forgot password +type ForgotPasswordRequest struct { + Username string `json:"username" validate:"required,username"` +} diff --git a/pkg/auth/enum/permision_constants.go b/pkg/auth/enum/permision_constants.go index fc3e8df..3cec62a 100644 --- a/pkg/auth/enum/permision_constants.go +++ b/pkg/auth/enum/permision_constants.go @@ -10,96 +10,171 @@ type PermissionName string type PermissionDescription string const ( - // Permission categories - DEFAULT PermissionCategory = "DEFAULT" - CLUSTER PermissionCategory = "CLUSTER" - HELM PermissionCategory = "HELM" + //Permission categories + DEFAULT PermissionCategory = "DEFAULT" + CLUSTER PermissionCategory = "CLUSTER" + MANAGEMENT PermissionCategory = "MANAGEMENT" + HELM PermissionCategory = "HELM" - // Permission names - DEFAULT_PERMISSION PermissionName = "DEFAULT_PERMISSION" - VIEW_NAMESPACE PermissionName = "VIEW_NAMESPACE_ENDPOINTS" - MANAGE_NAMESPACE PermissionName = "MANAGE_NAMESPACE_ENDPOINTS" - CREATE_K8S_NAMESPACE PermissionName = "CREATE_K8S_NAMESPACE" - VIEW_K8S_NAMESPACE PermissionName = "VIEW_K8S_NAMESPACE" - UPDATE_K8S_NAMESPACE PermissionName = "UPDATE_K8S_NAMESPACE" - DELETE_K8S_NAMESPACE PermissionName = "DELETE_K8S_NAMESPACE" - VIEW_NAMESPACE_DEPLOYMENT PermissionName = "VIEW_NAMESPACE_DEPLOYMENT" - VIEW_NAMESPACE_REPLICA_SET PermissionName = "VIEW_NAMESPACE_REPLICA_SET" - MANAGE_NAMESPACE_POD PermissionName = "MANAGE_NAMESPACE_POD" - VIEW_NAMESPACE_POD PermissionName = "VIEW_NAMESPACE_POD" - MANAGE_NAMESPACE_DEPLOYMENT PermissionName = "MANAGE_NAMESPACE_DEPLOYMENT" - MANAGE_NAMESPACE_REPLICA_SET PermissionName = "MANAGE_NAMESPACE_REPLICA_SET" - VIEW_NAMESPACE_STATEFUL_SET PermissionName = "VIEW_NAMESPACE_STATEFUL_SET" - MANAGE_NAMESPACE_STATEFUL_SET PermissionName = "MANAGE_NAMESPACE_STATEFUL_SET" - VIEW_NAMESPACE_DAEMON_SET PermissionName = "VIEW_NAMESPACE_DAEMON_SET" - MANAGE_NAMESPACE_DAEMON_SET PermissionName = "MANAGE_NAMESPACE_DAEMON_SET" - VIEW_NAMESPACE_SECRET PermissionName = "VIEW_NAMESPACE_SECRET" - MANAGE_NAMESPACE_SECRET PermissionName = "MANAGE_NAMESPACE_SECRET" - VIEW_NAMESPACE_CONFIG_MAP PermissionName = "VIEW_NAMESPACE_CONFIG_MAP" - MANAGE_NAMESPACE_CONFIG_MAP PermissionName = "MANAGE_NAMESPACE_CONFIG_MAP" - VIEW_NAMESPACE_SERVICE_ACCOUNT PermissionName = "VIEW_NAMESPACE_SERVICE_ACCOUNT" - MANAGE_NAMESPACE_SERVICE_ACCOUNT PermissionName = "MANAGE_NAMESPACE_SERVICE_ACCOUNT" - VIEW_NAMESPACE_SERVICE PermissionName = "VIEW_NAMESPACE_SERVICE" - MANAGE_NAMESPACE_SERVICE PermissionName = "MANAGE_NAMESPACE_SERVICE" - VIEW_NAMESPACE_INGRESS PermissionName = "VIEW_NAMESPACE_INGRESS" - MANAGE_NAMESPACE_INGRESS PermissionName = "MANAGE_NAMESPACE_INGRESS" - VIEW_NAMESPACE_CERTIFICATE PermissionName = "VIEW_NAMESPACE_CERTIFICATE" - MANAGE_NAMESPACE_CERTIFICATE PermissionName = "MANAGE_NAMESPACE_CERTIFICATE" - VIEW_NAMESPACE_ROLE PermissionName = "VIEW_NAMESPACE_ROLE" - MANAGE_NAMESPACE_ROLE PermissionName = "MANAGE_NAMESPACE_ROLE" - VIEW_NAMESPACE_ROLE_BINDING PermissionName = "VIEW_NAMESPACE_ROLE_BINDING" - MANAGE_NAMESPACE_ROLE_BINDING PermissionName = "MANAGE_NAMESPACE_ROLE_BINDING" - VIEW_NAMESPACE_JOB PermissionName = "VIEW_NAMESPACE_JOB" - MANAGE_NAMESPACE_JOB PermissionName = "MANAGE_NAMESPACE_JOB" - VIEW_NAMESPACE_CRON_JOB PermissionName = "VIEW_NAMESPACE_CRON_JOB" - MANAGE_NAMESPACE_CRON_JOB PermissionName = "MANAGE_NAMESPACE_CRON_JOB" - VIEW_NAMESPACE_NETWORK_POLICY PermissionName = "VIEW_NAMESPACE_NETWORK_POLICY" - MANAGE_NAMESPACE_NETWORK_POLICY PermissionName = "MANAGE_NAMESPACE_NETWORK_POLICY" - VIEW_NAMESPACE_RESOURCE_QUOTA PermissionName = "VIEW_NAMESPACE_RESOURCE_QUOTA" - MANAGE_NAMESPACE_RESOURCE_QUOTA PermissionName = "MANAGE_NAMESPACE_RESOURCE_QUOTA" - VIEW_NAMESPACE_PERSISTENT_VOLUME PermissionName = "VIEW_NAMESPACE_PERSISTENT_VOLUME" - MANAGE_NAMESPACE_PERSISTENT_VOLUME PermissionName = "MANAGE_NAMESPACE_PERSISTENT_VOLUME" - VIEW_NAMESPACE_GATEWAY PermissionName = "VIEW_NAMESPACE_GATEWAY" - MANAGE_NAMESPACE_GATEWAY PermissionName = "MANAGE_NAMESPACE_GATEWAY" - VIEW_NAMESPACE_VIRTUAL_SERVICE PermissionName = "VIEW_NAMESPACE_VIRTUAL_SERVICE" - MANAGE_NAMESPACE_VIRTUAL_SERVICE PermissionName = "MANAGE_NAMESPACE_VIRTUAL_SERVICE" - VIEW_K8S_NODES PermissionName = "VIEW_K8S_NODES" - MANAGE_K8S_NODE_TAINT PermissionName = "MANAGE_K8S_NODE_TAINT" - DRAIN_K8S_NODE PermissionName = "DRAIN_K8S_NODE" - VIEW_K8S_PERSISTENT_VOLUME PermissionName = "VIEW_K8S_PERSISTENT_VOLUME" - MANAGE_K8S_PERSISTENT_VOLUME PermissionName = "MANAGE_K8S_PERSISTENT_VOLUME" - VIEW_K8S_CLUSTER_ROLE PermissionName = "VIEW_K8S_CLUSTER_ROLE" - MANAGE_K8S_CLUSTER_ROLE PermissionName = "MANAGE_K8S_CLUSTER_ROLE" - VIEW_K8S_CLUSTER_ROLE_BINDING PermissionName = "VIEW_K8S_CLUSTER_ROLE_BINDING" - MANAGE_K8S_CLUSTER_ROLE_BINDING PermissionName = "MANAGE_K8S_CLUSTER_ROLE_BINDING" - VIEW_K8S_STORAGE_CLASS PermissionName = "VIEW_K8S_STORAGE_CLASS" - MANAGE_K8S_STORAGE_CLASS PermissionName = "MANAGE_K8S_STORAGE_CLASS" - VIEW_K8S_CUSTOM_RESOURCES PermissionName = "VIEW_K8S_CUSTOM_RESOURCES" - MANAGE_K8S_CUSTOM_RESOURCES PermissionName = "MANAGE_K8S_CUSTOM_RESOURCES" - VIEW_K8S_CUSTOM_RESOURCE_DEFINATION PermissionName = "VIEW_K8S_CUSTOM_RESOURCE_DEFINATION" - MANAGE_K8S_CUSTOM_RESOURCE_DEFINATION PermissionName = "MANAGE_K8S_CUSTOM_RESOURCE_DEFINATION" - VIEW_LOGS PermissionName = "VIEW_LOGS" - VIEW_NAMESPACE_ENDPOINTS PermissionName = "VIEW_NAMESPACE_ENDPOINTS" - MANAGE_NAMESPACE_ENDPOINTS PermissionName = "MANAGE_NAMESPACE_ENDPOINTS" - VIEW_NAMESPACE_ENDPOINT_SLICE PermissionName = "VIEW_NAMESPACE_ENDPOINT_SLICE" - VIEW_NAMESPACE_PDB PermissionName = "VIEW_NAMESPACE_PDB" - MANAGE_NAMESPACE_PDB PermissionName = "MANAGE_NAMESPACE_PDB" - VIEW_NAMESPACE_CONTROLLER_REVISION PermissionName = "VIEW_NAMESPACE_CONTROLLER_REVISION" - MANAGE_NAMESPACE_CONTROLLER_REVISION PermissionName = "MANAGE_NAMESPACE_CONTROLLER_REVISION" - VIEW_NAMESPACE_REPLICATION_CONTROLLER PermissionName = "VIEW_NAMESPACE_REPLICATION_CONTROLLER" - MANAGE_NAMESPACE_REPLICATION_CONTROLLER PermissionName = "MANAGE_NAMESPACE_REPLICATION_CONTROLLER" + //CLUSTER Permission names + DEFAULT_PERMISSION PermissionName = "DEFAULT_PERMISSION" + MANAGE_NAMESPACE PermissionName = "MANAGE_NAMESPACE_ENDPOINTS" + CREATE_NAMESPACE PermissionName = "CREATE_K8S_NAMESPACE" + VIEW_NAMESPACE PermissionName = "VIEW_K8S_NAMESPACE" + UPDATE_NAMESPACE PermissionName = "UPDATE_K8S_NAMESPACE" + DELETE_NAMESPACE PermissionName = "DELETE_K8S_NAMESPACE" + VIEW_DEPLOYMENT PermissionName = "VIEW_NAMESPACE_DEPLOYMENT" + VIEW_REPLICA_SET PermissionName = "VIEW_NAMESPACE_REPLICA_SET" + MANAGE_POD PermissionName = "MANAGE_NAMESPACE_POD" + VIEW_POD PermissionName = "VIEW_NAMESPACE_POD" + MANAGE_DEPLOYMENT PermissionName = "MANAGE_NAMESPACE_DEPLOYMENT" + MANAGE_REPLICA_SET PermissionName = "MANAGE_NAMESPACE_REPLICA_SET" + VIEW_STATEFUL_SET PermissionName = "VIEW_NAMESPACE_STATEFUL_SET" + MANAGE_STATEFUL_SET PermissionName = "MANAGE_NAMESPACE_STATEFUL_SET" + VIEW_DAEMON_SET PermissionName = "VIEW_NAMESPACE_DAEMON_SET" + MANAGE_DAEMON_SET PermissionName = "MANAGE_NAMESPACE_DAEMON_SET" + VIEW_SECRET PermissionName = "VIEW_NAMESPACE_SECRET" + MANAGE_SECRET PermissionName = "MANAGE_NAMESPACE_SECRET" + VIEW_CONFIG_MAP PermissionName = "VIEW_NAMESPACE_CONFIG_MAP" + MANAGE_CONFIG_MAP PermissionName = "MANAGE_NAMESPACE_CONFIG_MAP" + VIEW_SERVICE_ACCOUNT PermissionName = "VIEW_NAMESPACE_SERVICE_ACCOUNT" + MANAGE_SERVICE_ACCOUNT PermissionName = "MANAGE_NAMESPACE_SERVICE_ACCOUNT" + VIEW_SERVICE PermissionName = "VIEW_NAMESPACE_SERVICE" + MANAGE_SERVICE PermissionName = "MANAGE_NAMESPACE_SERVICE" + VIEW_INGRESS PermissionName = "VIEW_NAMESPACE_INGRESS" + MANAGE_INGRESS PermissionName = "MANAGE_NAMESPACE_INGRESS" + VIEW_CERTIFICATE PermissionName = "VIEW_NAMESPACE_CERTIFICATE" + MANAGE_CERTIFICATE PermissionName = "MANAGE_NAMESPACE_CERTIFICATE" + VIEW_NAMESPACE_ROLE PermissionName = "VIEW_NAMESPACE_ROLE" + MANAGE_NAMESPACE_ROLE PermissionName = "MANAGE_NAMESPACE_ROLE" + VIEW_NAMESPACE_ROLE_BINDING PermissionName = "VIEW_NAMESPACE_ROLE_BINDING" + MANAGE_NAMESPACE_ROLE_BINDING PermissionName = "MANAGE_NAMESPACE_ROLE_BINDING" + VIEW_JOB PermissionName = "VIEW_NAMESPACE_JOB" + MANAGE_JOB PermissionName = "MANAGE_NAMESPACE_JOB" + VIEW_CRON_JOB PermissionName = "VIEW_NAMESPACE_CRON_JOB" + MANAGE_CRON_JOB PermissionName = "MANAGE_NAMESPACE_CRON_JOB" + VIEW_NAMESPACE_NETWORK_POLICY PermissionName = "VIEW_NAMESPACE_NETWORK_POLICY" + MANAGE_NAMESPACE_NETWORK_POLICY PermissionName = "MANAGE_NAMESPACE_NETWORK_POLICY" + VIEW_NAMESPACE_RESOURCE_QUOTA PermissionName = "VIEW_NAMESPACE_RESOURCE_QUOTA" + MANAGE_RESOURCE_QUOTA PermissionName = "MANAGE_NAMESPACE_RESOURCE_QUOTA" + VIEW_PERSISTENT_VOLUME PermissionName = "VIEW_NAMESPACE_PERSISTENT_VOLUME" + MANAGE_PERSISTENT_VOLUME PermissionName = "MANAGE_NAMESPACE_PERSISTENT_VOLUME" + VIEW_PERSISTENT_VOLUME_CLAIM PermissionName = "VIEW_NAMESPACE_PERSISTENT_VOLUME_CLAIM" + MANAGE_PERSISTENT_VOLUME_CLAIM PermissionName = "MANAGE_NAMESPACE_PERSISTENT_VOLUME_CLAIM" + VIEW_GATEWAY PermissionName = "VIEW_NAMESPACE_GATEWAY" + MANAGE_GATEWAY PermissionName = "MANAGE_NAMESPACE_GATEWAY" + VIEW_VIRTUAL_SERVICE PermissionName = "VIEW_NAMESPACE_VIRTUAL_SERVICE" + MANAGE_VIRTUAL_SERVICE PermissionName = "MANAGE_NAMESPACE_VIRTUAL_SERVICE" + VIEW_NODES PermissionName = "VIEW_K8S_NODES" + MANAGE_NODE_TAINT PermissionName = "MANAGE_K8S_NODE_TAINT" + DRAIN_NODE PermissionName = "DRAIN_K8S_NODE" + VIEW_CLUSTER_ROLE PermissionName = "VIEW_K8S_CLUSTER_ROLE" + MANAGE_CLUSTER_ROLE PermissionName = "MANAGE_K8S_CLUSTER_ROLE" + VIEW_CLUSTER_ROLE_BINDING PermissionName = "VIEW_K8S_CLUSTER_ROLE_BINDING" + MANAGE_CLUSTER_ROLE_BINDING PermissionName = "MANAGE_K8S_CLUSTER_ROLE_BINDING" + VIEW_STORAGE_CLASS PermissionName = "VIEW_K8S_STORAGE_CLASS" + MANAGE_STORAGE_CLASS PermissionName = "MANAGE_K8S_STORAGE_CLASS" + VIEW_CUSTOM_RESOURCES PermissionName = "VIEW_K8S_CUSTOM_RESOURCES" + MANAGE_CUSTOM_RESOURCES PermissionName = "MANAGE_K8S_CUSTOM_RESOURCES" + VIEW_CUSTOM_RESOURCE_DEFINITION PermissionName = "VIEW_K8S_CUSTOM_RESOURCE_DEFINITION" + MANAGE_CUSTOM_RESOURCE_DEFINITION PermissionName = "MANAGE_K8S_CUSTOM_RESOURCE_DEFINITION" + VIEW_LOGS PermissionName = "VIEW_LOGS" + VIEW_ENDPOINTS PermissionName = "VIEW_NAMESPACE_ENDPOINTS" + MANAGE_ENDPOINTS PermissionName = "MANAGE_ENDPOINTS_ENDPOINTS" + VIEW_ENDPOINT_SLICE PermissionName = "VIEW_NAMESPACE_ENDPOINT_SLICE" + MANAGE_ENDPOINT_SLICE PermissionName = "MANAGE_ENDPOINT_SLICE" + VIEW_PDB PermissionName = "VIEW_NAMESPACE_PDB" + MANAGE_PDB PermissionName = "MANAGE_NAMESPACE_PDB" + VIEW_CONTROLLER_REVISION PermissionName = "VIEW_NAMESPACE_CONTROLLER_REVISION" + MANAGE_CONTROLLER_REVISION PermissionName = "MANAGE_NAMESPACE_CONTROLLER_REVISION" + VIEW_REPLICATION_CONTROLLER PermissionName = "VIEW_NAMESPACE_REPLICATION_CONTROLLER" + MANAGE_REPLICATION_CONTROLLER PermissionName = "MANAGE_NAMESPACE_REPLICATION_CONTROLLER" - VIEW_ENDPOINT_SLICE PermissionName = "VIEW_ENDPOINT_SLICE" - MANAGE_ENDPOINT_SLICE PermissionName = "MANAGE_ENDPOINT_SLICE" - VIEW_PDB PermissionName = "VIEW_PDB" - MANAGE_PDB PermissionName = "MANAGE_PDB" + //MANAGEMENT Permission names + VIEW_USER PermissionName = "VIEW_USER" + MANAGE_USER PermissionName = "MANAGE_USER" - // Permission descriptions - DEFAULT_PERMISSION_DESCRIPTION PermissionDescription = "DEFAULT_PERMISSION" - VIEW_NAMESPACE_DESCRIPTION PermissionDescription = "Permission to view namespace endpoints" - MANAGE_NAMESPACE_DESCRIPTION PermissionDescription = "Permission to manage namespace endpoints" - VIEW_ENDPOINT_SLICE_DESCRIPTION PermissionDescription = "Permission to view endpoint slices" - MANAGE_ENDPOINT_SLICE_DESCRIPTION PermissionDescription = "Permission to manage endpoint slices" - VIEW_PDB_DESCRIPTION PermissionDescription = "Permission to view PDBs" - MANAGE_PDB_DESCRIPTION PermissionDescription = "Permission to manage PDBs" + VIEW_ROLE PermissionName = "VIEW_ROLE" + MANAGE_ROLE PermissionName = "MANAGE_ROLE" + + //CLUSTER Permission descriptions + DEFAULT_PERMISSION_DESCRIPTION PermissionDescription = "Default permission for basic access" + MANAGE_NAMESPACE_DESCRIPTION PermissionDescription = "Permission to manage namespace endpoints" + CREATE_NAMESPACE_DESCRIPTION PermissionDescription = "Permission to create Kubernetes namespaces" + VIEW_NAMESPACE_DESCRIPTION PermissionDescription = "Permission to view Kubernetes namespaces" + UPDATE_NAMESPACE_DESCRIPTION PermissionDescription = "Permission to update Kubernetes namespaces" + DELETE_NAMESPACE_DESCRIPTION PermissionDescription = "Permission to delete Kubernetes namespaces" + VIEW_DEPLOYMENT_DESCRIPTION PermissionDescription = "Permission to view deployments" + VIEW_REPLICA_SET_DESCRIPTION PermissionDescription = "Permission to view replica sets" + MANAGE_POD_DESCRIPTION PermissionDescription = "Permission to manage pods" + VIEW_POD_DESCRIPTION PermissionDescription = "Permission to view pods" + MANAGE_DEPLOYMENT_DESCRIPTION PermissionDescription = "Permission to manage deployments" + MANAGE_REPLICA_SET_DESCRIPTION PermissionDescription = "Permission to manage replica sets" + VIEW_STATEFUL_SET_DESCRIPTION PermissionDescription = "Permission to view stateful sets" + MANAGE_STATEFUL_SET_DESCRIPTION PermissionDescription = "Permission to manage stateful sets" + VIEW_DAEMON_SET_DESCRIPTION PermissionDescription = "Permission to view daemon sets" + MANAGE_DAEMON_SET_DESCRIPTION PermissionDescription = "Permission to manage daemon sets" + VIEW_SECRET_DESCRIPTION PermissionDescription = "Permission to view secrets" + MANAGE_SECRET_DESCRIPTION PermissionDescription = "Permission to manage secrets" + VIEW_CONFIG_MAP_DESCRIPTION PermissionDescription = "Permission to view config maps" + MANAGE_CONFIG_MAP_DESCRIPTION PermissionDescription = "Permission to manage config maps" + VIEW_SERVICE_ACCOUNT_DESCRIPTION PermissionDescription = "Permission to view service accounts" + MANAGE_SERVICE_ACCOUNT_DESCRIPTION PermissionDescription = "Permission to manage service accounts" + VIEW_SERVICE_DESCRIPTION PermissionDescription = "Permission to view services" + MANAGE_SERVICE_DESCRIPTION PermissionDescription = "Permission to manage services" + VIEW_INGRESS_DESCRIPTION PermissionDescription = "Permission to view ingress resources" + MANAGE_INGRESS_DESCRIPTION PermissionDescription = "Permission to manage ingress resources" + VIEW_CERTIFICATE_DESCRIPTION PermissionDescription = "Permission to view certificates" + MANAGE_CERTIFICATE_DESCRIPTION PermissionDescription = "Permission to manage certificates" + VIEW_NAMESPACE_ROLE_DESCRIPTION PermissionDescription = "Permission to view roles" + MANAGE_NAMESPACE_ROLE_DESCRIPTION PermissionDescription = "Permission to manage roles" + VIEW_NAMESPACE_ROLE_BINDING_DESCRIPTION PermissionDescription = "Permission to view role bindings" + MANAGE_NAMESPACE_ROLE_BINDING_DESCRIPTION PermissionDescription = "Permission to manage role bindings" + VIEW_JOB_DESCRIPTION PermissionDescription = "Permission to view jobs" + MANAGE_JOB_DESCRIPTION PermissionDescription = "Permission to manage jobs" + VIEW_CRON_JOB_DESCRIPTION PermissionDescription = "Permission to view cron jobs" + MANAGE_CRON_JOB_DESCRIPTION PermissionDescription = "Permission to manage cron jobs" + VIEW_NAMESPACE_NETWORK_POLICY_DESCRIPTION PermissionDescription = "Permission to view network policies" + MANAGE_NAMESPACE_NETWORK_POLICY_DESCRIPTION PermissionDescription = "Permission to manage network policies" + VIEW_NAMESPACE_RESOURCE_QUOTA_DESCRIPTION PermissionDescription = "Permission to view resource quotas" + MANAGE_RESOURCE_QUOTA_DESCRIPTION PermissionDescription = "Permission to manage resource quotas" + VIEW_PERSISTENT_VOLUME_DESCRIPTION PermissionDescription = "Permission to view persistent volumes" + MANAGE_PERSISTENT_VOLUME_DESCRIPTION PermissionDescription = "Permission to manage persistent volumes" + VIEW_PERSISTENT_VOLUME_CLAIM_DESCRIPTION PermissionDescription = "Permission to view persistent volumes claim" + MANAGE_PERSISTENT_VOLUME_CLAIM_DESCRIPTION PermissionDescription = "Permission to manage persistent volumes claim" + VIEW_GATEWAY_DESCRIPTION PermissionDescription = "Permission to view gateways" + MANAGE_GATEWAY_DESCRIPTION PermissionDescription = "Permission to manage gateways" + VIEW_VIRTUAL_SERVICE_DESCRIPTION PermissionDescription = "Permission to view virtual services" + MANAGE_VIRTUAL_SERVICE_DESCRIPTION PermissionDescription = "Permission to manage virtual services" + VIEW_NODES_DESCRIPTION PermissionDescription = "Permission to view Kubernetes nodes" + MANAGE_NODE_TAINT_DESCRIPTION PermissionDescription = "Permission to manage Kubernetes node taints" + DRAIN_NODE_DESCRIPTION PermissionDescription = "Permission to drain Kubernetes nodes" + VIEW_CLUSTER_ROLE_DESCRIPTION PermissionDescription = "Permission to view Kubernetes cluster roles" + MANAGE_CLUSTER_ROLE_DESCRIPTION PermissionDescription = "Permission to manage Kubernetes cluster roles" + VIEW_CLUSTER_ROLE_BINDING_DESCRIPTION PermissionDescription = "Permission to view Kubernetes cluster role bindings" + MANAGE_CLUSTER_ROLE_BINDING_DESCRIPTION PermissionDescription = "Permission to manage Kubernetes cluster role bindings" + VIEW_STORAGE_CLASS_DESCRIPTION PermissionDescription = "Permission to view Kubernetes storage classes" + MANAGE_STORAGE_CLASS_DESCRIPTION PermissionDescription = "Permission to manage Kubernetes storage classes" + VIEW_CUSTOM_RESOURCES_DESCRIPTION PermissionDescription = "Permission to view Kubernetes custom resources" + MANAGE_CUSTOM_RESOURCES_DESCRIPTION PermissionDescription = "Permission to manage Kubernetes custom resources" + VIEW_CUSTOM_RESOURCE_DEFINATION_DESCRIPTION PermissionDescription = "Permission to view Kubernetes custom resource definitions" + MANAGE_CUSTOM_RESOURCE_DEFINATION_DESCRIPTION PermissionDescription = "Permission to manage Kubernetes custom resource definitions" + VIEW_LOGS_DESCRIPTION PermissionDescription = "Permission to view logs" + VIEW_ENDPOINTS_DESCRIPTION PermissionDescription = "Permission to view endpoints" + MANAGE_ENDPOINTS_DESCRIPTION PermissionDescription = "Permission to manage endpoints" + VIEW_ENDPOINT_SLICE_DESCRIPTION PermissionDescription = "Permission to view endpoint slices" + MANAGE_ENDPOINT_SLICE_DESCRIPTION PermissionDescription = "Permission to manage endpoint slices" + VIEW_PDB_DESCRIPTION PermissionDescription = "Permission to view pod disruption budgets" + MANAGE_PDB_DESCRIPTION PermissionDescription = "Permission to manage pod disruption budgets" + VIEW_CONTROLLER_REVISION_DESCRIPTION PermissionDescription = "Permission to view controller revisions" + MANAGE_CONTROLLER_REVISION_DESCRIPTION PermissionDescription = "Permission to manage controller revisions" + VIEW_REPLICATION_CONTROLLER_DESCRIPTION PermissionDescription = "Permission to view replication controllers" + MANAGE_REPLICATION_CONTROLLER_DESCRIPTION PermissionDescription = "Permission to manage replication controllers" + + //MANAGEMENT Permission names + VIEW_USER_DESCRIPTION PermissionDescription = "Permission to view user" + MANAGE_USER_DESCRIPTION PermissionDescription = "Permission to manage user" + + VIEW_ROLE_DESCRIPTION PermissionDescription = "Permission to view roles" + MANAGE_ROLE_DESCRIPTION PermissionDescription = "Permission to manage roles" ) diff --git a/pkg/auth/enum/permission_mapping.go b/pkg/auth/enum/permission_mapping.go index cafa7b9..78b3e68 100644 --- a/pkg/auth/enum/permission_mapping.go +++ b/pkg/auth/enum/permission_mapping.go @@ -12,29 +12,305 @@ var PermissionDefinitions = map[PermissionName]PermissionDefinition{ Description: DEFAULT_PERMISSION_DESCRIPTION, Category: DEFAULT, }, + VIEW_USER: { + Description: VIEW_USER_DESCRIPTION, + Category: MANAGEMENT, + }, + MANAGE_USER: { + Description: MANAGE_USER_DESCRIPTION, + Category: MANAGEMENT, + }, + VIEW_ROLE: { + Description: VIEW_ROLE_DESCRIPTION, + Category: MANAGEMENT, + }, + MANAGE_ROLE: { + Description: MANAGE_ROLE_DESCRIPTION, + Category: MANAGEMENT, + }, + CREATE_NAMESPACE: { + Description: CREATE_NAMESPACE_DESCRIPTION, + Category: CLUSTER, + }, VIEW_NAMESPACE: { Description: VIEW_NAMESPACE_DESCRIPTION, Category: CLUSTER, }, + UPDATE_NAMESPACE: { + Description: UPDATE_NAMESPACE_DESCRIPTION, + Category: CLUSTER, + }, + DELETE_NAMESPACE: { + Description: DELETE_NAMESPACE_DESCRIPTION, + Category: CLUSTER, + }, MANAGE_NAMESPACE: { Description: MANAGE_NAMESPACE_DESCRIPTION, Category: CLUSTER, }, - /* VIEW_ENDPOINT_SLICE: { - Description: VIEW_ENDPOINT_SLICE_DESCRIPTION, - Category: CLUSTER, - }, - MANAGE_ENDPOINT_SLICE: { - Description: MANAGE_ENDPOINT_SLICE_DESCRIPTION, - Category: CLUSTER, - }, - VIEW_PDB: { - Description: VIEW_PDB_DESCRIPTION, - Category: CLUSTER, - }, - MANAGE_PDB: { - Description: MANAGE_PDB_DESCRIPTION, - Category: CLUSTER, - },*/ + VIEW_DEPLOYMENT: { + Description: VIEW_DEPLOYMENT_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_REPLICA_SET: { + Description: VIEW_REPLICA_SET_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_POD: { + Description: MANAGE_POD_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_POD: { + Description: VIEW_POD_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_DEPLOYMENT: { + Description: MANAGE_DEPLOYMENT_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_REPLICA_SET: { + Description: MANAGE_REPLICA_SET_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_STATEFUL_SET: { + Description: VIEW_STATEFUL_SET_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_STATEFUL_SET: { + Description: MANAGE_STATEFUL_SET_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_DAEMON_SET: { + Description: VIEW_DAEMON_SET_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_DAEMON_SET: { + Description: MANAGE_DAEMON_SET_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_SECRET: { + Description: VIEW_SECRET_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_SECRET: { + Description: MANAGE_SECRET_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_CONFIG_MAP: { + Description: VIEW_CONFIG_MAP_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_CONFIG_MAP: { + Description: MANAGE_CONFIG_MAP_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_SERVICE_ACCOUNT: { + Description: VIEW_SERVICE_ACCOUNT_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_SERVICE_ACCOUNT: { + Description: MANAGE_SERVICE_ACCOUNT_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_SERVICE: { + Description: VIEW_SERVICE_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_SERVICE: { + Description: MANAGE_SERVICE_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_INGRESS: { + Description: VIEW_INGRESS_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_INGRESS: { + Description: MANAGE_INGRESS_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_CERTIFICATE: { + Description: VIEW_CERTIFICATE_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_CERTIFICATE: { + Description: MANAGE_CERTIFICATE_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_NAMESPACE_ROLE: { + Description: VIEW_NAMESPACE_ROLE_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_NAMESPACE_ROLE: { + Description: MANAGE_NAMESPACE_ROLE_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_NAMESPACE_ROLE_BINDING: { + Description: VIEW_NAMESPACE_ROLE_BINDING_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_NAMESPACE_ROLE_BINDING: { + Description: MANAGE_NAMESPACE_ROLE_BINDING_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_JOB: { + Description: VIEW_JOB_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_JOB: { + Description: MANAGE_JOB_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_CRON_JOB: { + Description: VIEW_CRON_JOB_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_CRON_JOB: { + Description: MANAGE_CRON_JOB_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_NAMESPACE_NETWORK_POLICY: { + Description: VIEW_NAMESPACE_NETWORK_POLICY_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_NAMESPACE_NETWORK_POLICY: { + Description: MANAGE_NAMESPACE_NETWORK_POLICY_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_NAMESPACE_RESOURCE_QUOTA: { + Description: VIEW_NAMESPACE_RESOURCE_QUOTA_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_RESOURCE_QUOTA: { + Description: MANAGE_RESOURCE_QUOTA_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_PERSISTENT_VOLUME: { + Description: VIEW_PERSISTENT_VOLUME_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_PERSISTENT_VOLUME: { + Description: MANAGE_PERSISTENT_VOLUME_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_PERSISTENT_VOLUME_CLAIM: { + Description: VIEW_PERSISTENT_VOLUME_CLAIM_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_PERSISTENT_VOLUME_CLAIM: { + Description: MANAGE_PERSISTENT_VOLUME_CLAIM_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_GATEWAY: { + Description: VIEW_GATEWAY_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_GATEWAY: { + Description: MANAGE_GATEWAY_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_VIRTUAL_SERVICE: { + Description: VIEW_VIRTUAL_SERVICE_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_VIRTUAL_SERVICE: { + Description: MANAGE_VIRTUAL_SERVICE_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_NODES: { + Description: VIEW_NODES_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_NODE_TAINT: { + Description: MANAGE_NODE_TAINT_DESCRIPTION, + Category: CLUSTER, + }, + DRAIN_NODE: { + Description: DRAIN_NODE_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_CLUSTER_ROLE: { + Description: VIEW_CLUSTER_ROLE_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_CLUSTER_ROLE: { + Description: MANAGE_CLUSTER_ROLE_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_CLUSTER_ROLE_BINDING: { + Description: VIEW_CLUSTER_ROLE_BINDING_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_CLUSTER_ROLE_BINDING: { + Description: MANAGE_CLUSTER_ROLE_BINDING_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_STORAGE_CLASS: { + Description: VIEW_STORAGE_CLASS_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_STORAGE_CLASS: { + Description: MANAGE_STORAGE_CLASS_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_CUSTOM_RESOURCES: { + Description: VIEW_CUSTOM_RESOURCES_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_CUSTOM_RESOURCES: { + Description: MANAGE_CUSTOM_RESOURCES_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_CUSTOM_RESOURCE_DEFINITION: { + Description: VIEW_CUSTOM_RESOURCE_DEFINATION_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_CUSTOM_RESOURCE_DEFINITION: { + Description: MANAGE_CUSTOM_RESOURCE_DEFINATION_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_LOGS: { + Description: VIEW_LOGS_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_ENDPOINTS: { + Description: VIEW_ENDPOINTS_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_ENDPOINTS: { + Description: MANAGE_ENDPOINTS_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_ENDPOINT_SLICE: { + Description: VIEW_ENDPOINT_SLICE_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_ENDPOINT_SLICE: { + Description: MANAGE_ENDPOINT_SLICE_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_PDB: { + Description: VIEW_PDB_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_PDB: { + Description: MANAGE_PDB_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_CONTROLLER_REVISION: { + Description: VIEW_CONTROLLER_REVISION_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_CONTROLLER_REVISION: { + Description: MANAGE_CONTROLLER_REVISION_DESCRIPTION, + Category: CLUSTER, + }, + VIEW_REPLICATION_CONTROLLER: { + Description: VIEW_REPLICATION_CONTROLLER_DESCRIPTION, + Category: CLUSTER, + }, + MANAGE_REPLICATION_CONTROLLER: { + Description: MANAGE_REPLICATION_CONTROLLER_DESCRIPTION, + Category: CLUSTER, + }, // Add more permission definitions here } diff --git a/pkg/auth/services/rbac_service.go b/pkg/auth/services/rbac_service.go index 1dbb513..280576f 100644 --- a/pkg/auth/services/rbac_service.go +++ b/pkg/auth/services/rbac_service.go @@ -277,9 +277,10 @@ func (r *RbacService) GetPermissionsByUserType(username string) (*dto.Permission // Initialize response response := &dto.PermissionResponse{ - DEFAULT: make([]dto.PermissionDTO, 0), - CLUSTER: make([]dto.PermissionDTO, 0), - HelmApps: make([]dto.PermissionDTO, 0), + Default: make([]dto.PermissionDTO, 0), + Cluster: make([]dto.PermissionDTO, 0), + Management: make([]dto.PermissionDTO, 0), + HelmApps: make([]dto.PermissionDTO, 0), } // Create filter for Valid permissions @@ -315,12 +316,15 @@ func (r *RbacService) GetPermissionsByUserType(username string) (*dto.Permission switch perm.Category { case enum.DEFAULT: - response.DEFAULT = append(response.DEFAULT, dto) + response.Default = append(response.Default, dto) case enum.CLUSTER: - response.CLUSTER = append(response.CLUSTER, dto) + response.Cluster = append(response.Cluster, dto) + case enum.MANAGEMENT: + response.Management = append(response.Management, dto) case enum.HELM: response.HelmApps = append(response.HelmApps, dto) } + //add category here } @@ -379,7 +383,6 @@ func (r *RbacService) GetUsersByRoleID(roleID primitive.ObjectID, page, limit in {"$match", bson.D{ {"roles._id", roleID}, {"status", enum.VALID}, - {"user_is_active", true}, }}, } diff --git a/pkg/auth/services/user_service.go b/pkg/auth/services/user_service.go index 353a2eb..f3f0ada 100644 --- a/pkg/auth/services/user_service.go +++ b/pkg/auth/services/user_service.go @@ -7,6 +7,7 @@ import ( db "github.com/krack8/lighthouse/pkg/auth/config" "github.com/krack8/lighthouse/pkg/auth/enum" "github.com/krack8/lighthouse/pkg/auth/utils" + "golang.org/x/crypto/bcrypt" "time" "github.com/krack8/lighthouse/pkg/auth/models" @@ -281,3 +282,96 @@ func (s *UserService) GetRolesByIds(ctx context.Context, roleIds []string) ([]mo return roles, nil } + +// ResetPassword handles password reset with old password verification +func (s *UserService) ResetPassword(userID primitive.ObjectID, oldPassword, newPassword string, requester string) error { + // Find user by ID + var user models.User + var req models.User + err := db.UserCollection.FindOne(context.Background(), bson.M{"_id": userID}).Decode(&user) + if err != nil { + if err == mongo.ErrNoDocuments { + return fmt.Errorf("user not found") + } + return fmt.Errorf("failed to fetch user: %w", err) + } + + // Verify old password + err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(oldPassword)) + if err != nil { + return fmt.Errorf("incorrect old password") + } + + if user.Username != requester { + err := db.UserCollection.FindOne(context.Background(), bson.M{"username": requester}).Decode(&req) + if err != nil { + if err == mongo.ErrNoDocuments { + return fmt.Errorf("requester not found") + } + return fmt.Errorf("failed to fetch requester data: %w", err) + } + if req.UserType != models.AdminUser { + return fmt.Errorf("unauthorized !! you don't have ADMIN permission") + } + + } + + // Update password in database + update := bson.M{ + "$set": bson.M{ + "password": utils.HashPassword(newPassword), + "updated_at": time.Now(), + }, + } + + _, err = db.UserCollection.UpdateOne( + context.Background(), + bson.M{"_id": userID}, + update, + ) + if err != nil { + return fmt.Errorf("failed to update password: %w", err) + } + + return nil +} + +// InitiateForgotPassword starts the forgot password process +func (s *UserService) InitiateForgotPassword(email string) error { + // Find user by email + var user models.User + err := db.UserCollection.FindOne(context.Background(), bson.M{"username": email}).Decode(&user) + if err != nil { + if err == mongo.ErrNoDocuments { + return fmt.Errorf("user not found") + } + return fmt.Errorf("failed to fetch user: %w", err) + } + + // Generate reset token + token := utils.GenerateResetToken() + + // Update user with reset token + update := bson.M{ + "$set": bson.M{ + "forgot_password_token": token, + "updated_at": time.Now(), + }, + } + + _, err = db.UserCollection.UpdateOne( + context.Background(), + bson.M{"_id": user.ID}, + update, + ) + if err != nil { + return fmt.Errorf("failed to update reset token: %w", err) + } + + // TODO: Send email with reset link + // This part would integrate with your email service + resetLink := fmt.Sprintf("https://yourdomain.com/reset-password?token=%s", token) + _ = resetLink // Remove this line when implementing email sending + + return nil +} diff --git a/pkg/auth/utils/endpoints.go b/pkg/auth/utils/endpoints.go index 9b56a5f..25fc2cf 100644 --- a/pkg/auth/utils/endpoints.go +++ b/pkg/auth/utils/endpoints.go @@ -1,35 +1,57 @@ package utils -import "github.com/krack8/lighthouse/pkg/auth/models" +import ( + "github.com/krack8/lighthouse/pkg/auth/models" +) -// GetDefaultEndpoints returns endpoints for creating K8s namespaces +// GetDefaultEndpoints returns endpoints for creating namespaces func GetDefaultEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/clusters"}, + {Method: "GET", Route: "/api/v1/clusters/@"}, + {Method: "GET", Route: "/api/v1/users/profile"}, + {Method: "GET", Route: "/api/v1/permissions"}, + {Method: "GET", Route: "/api/v1/permissions/@"}, + {Method: "GET", Route: "/api/v1/permissions/users"}, } } -// GetCreateNamespaceEndpoints returns endpoints for creating K8s namespaces -func GetCreateNamespaceEndpoints() []models.Endpoint { +// GetUserEndpoints returns endpoints for creating namespaces +func GetUserEndpoints() []models.Endpoint { return []models.Endpoint{ - {Method: "POST", Route: "/api/v1/namespace"}, - {Method: "GET", Route: "/api/v1/namespace"}, - {Method: "GET", Route: "/api/v1/namespace/@"}, + {Method: "GET", Route: "/api/v1/users"}, + {Method: "GET", Route: "/api/v1/users/@"}, } } -// GetViewNamespaceEndpoints returns endpoints for viewing K8s namespaces -func GetViewNamespaceEndpoints() []models.Endpoint { +// GetManageUserEndpoints returns endpoints for creating namespaces +func GetManageUserEndpoints() []models.Endpoint { return []models.Endpoint{ - {Method: "GET", Route: "/api/v1/namespace"}, - {Method: "GET", Route: "/api/v1/namespace/names"}, - {Method: "GET", Route: "/api/v1/namespace/@"}, - {Method: "GET", Route: "/api/v1/event"}, + {Method: "POST", Route: "/api/v1/users"}, + {Method: "DELETE", Route: "/api/v1/users/@"}, } } -// GetK8sNamespaceCreateEndpoints returns endpoints for creating K8s namespaces -func GetK8sNamespaceCreateEndpoints() []models.Endpoint { +// GetRolesEndpoints returns endpoints for creating namespaces +func GetRolesEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/roles"}, + {Method: "GET", Route: "/api/v1/roles/@"}, + } +} + +// GetManageRolesEndpoints returns endpoints for creating namespaces +func GetManageRolesEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/roles"}, + {Method: "DELETE", Route: "/api/v1/roles/@"}, + {Method: "GET", Route: "/api/v1/roles/@/users"}, + {Method: "POST", Route: "/api/v1/assign-roles"}, + } +} + +// GetCreateNamespaceEndpoints returns endpoints for creating namespaces +func GetCreateNamespaceEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/namespace"}, {Method: "GET", Route: "/api/v1/namespace"}, @@ -37,32 +59,32 @@ func GetK8sNamespaceCreateEndpoints() []models.Endpoint { } } -// GetViewK8sNamespaceEndpoints returns endpoints for viewing K8s namespaces -func GetViewK8sNamespaceEndpoints() []models.Endpoint { +// GetViewNamespaceEndpoints returns endpoints for viewing namespaces +func GetViewNamespaceEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/namespace"}, - {Method: "GET", Route: "api/v1/namespace/names"}, + {Method: "GET", Route: "/api/v1/namespace/names"}, {Method: "GET", Route: "/api/v1/namespace/@"}, {Method: "GET", Route: "/api/v1/event"}, } } -// GetK8sNamespaceUpdateEndpoints returns endpoints for updating K8s namespaces -func GetK8sNamespaceUpdateEndpoints() []models.Endpoint { +// GetUpdateNamespaceEndpoints returns endpoints for updating namespaces +func GetUpdateNamespaceEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/namespace"}, } } -// GetK8sNamespaceDeleteEndpoints returns endpoints for deleting K8s namespaces -func GetK8sNamespaceDeleteEndpoints() []models.Endpoint { +// GetDeleteNamespaceEndpoints returns endpoints for deleting namespaces +func GetDeleteNamespaceEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "DELETE", Route: "/api/v1/namespace/@"}, } } -// GetViewK8sNamespaceDeploymentEndpoints returns endpoints for viewing K8s namespace deployments -func GetViewK8sNamespaceDeploymentEndpoints() []models.Endpoint { +// GetViewDeploymentEndpoints returns endpoints for viewing namespace deployments +func GetViewDeploymentEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/deployment"}, {Method: "GET", Route: "/api/v1/deployment/stats"}, @@ -71,16 +93,16 @@ func GetViewK8sNamespaceDeploymentEndpoints() []models.Endpoint { } } -// GetK8sNamespaceManageDeploymentEndpoints returns endpoints for managing K8s namespace deployments -func GetK8sNamespaceManageDeploymentEndpoints() []models.Endpoint { +// GetManageDeploymentEndpoints returns endpoints for managing namespace deployments +func GetManageDeploymentEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/deployment"}, {Method: "DELETE", Route: "/api/v1/deployment/@"}, } } -// GetViewK8sNamespacePodEndpoints returns endpoints for viewing K8s namespace pods -func GetViewK8sNamespacePodEndpoints() []models.Endpoint { +// GetViewPodEndpoints returns endpoints for viewing namespace pods +func GetViewPodEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/pod"}, {Method: "GET", Route: "/api/v1/pod/@"}, @@ -88,32 +110,32 @@ func GetViewK8sNamespacePodEndpoints() []models.Endpoint { } } -// GetK8sNamespaceManagePodEndpoints returns endpoints for managing K8s namespace pods -func GetK8sNamespaceManagePodEndpoints() []models.Endpoint { +// GetManagePodEndpoints returns endpoints for managing namespace pods +func GetManagePodEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/pod"}, {Method: "DELETE", Route: "/api/v1/pod/@"}, } } -// GetViewK8sNamespaceReplicaSetEndpoints returns endpoints for viewing K8s namespace replica sets -func GetViewK8sNamespaceReplicaSetEndpoints() []models.Endpoint { +// GetViewReplicaSetEndpoints returns endpoints for viewing namespace replica sets +func GetViewReplicaSetEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/replicaset"}, {Method: "GET", Route: "/api/v1/replicaset/@"}, } } -// GetK8sNamespaceManageReplicaSetEndpoints returns endpoints for managing K8s namespace replica sets -func GetK8sNamespaceManageReplicaSetEndpoints() []models.Endpoint { +// GetManageReplicaSetEndpoints returns endpoints for managing namespace replica sets +func GetManageReplicaSetEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/replicaset"}, {Method: "DELETE", Route: "/api/v1/replicaset/@"}, } } -// GetViewK8sNamespaceStatefulSetEndpoints returns endpoints for viewing K8s namespace stateful sets -func GetViewK8sNamespaceStatefulSetEndpoints() []models.Endpoint { +// GetViewStatefulSetEndpoints returns endpoints for viewing namespace stateful sets +func GetViewStatefulSetEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/statefulset"}, {Method: "GET", Route: "/api/v1/statefulset/@"}, @@ -122,125 +144,141 @@ func GetViewK8sNamespaceStatefulSetEndpoints() []models.Endpoint { } } -// GetK8sNamespaceManageStatefulSetEndpoints returns endpoints for managing K8s namespace stateful sets -func GetK8sNamespaceManageStatefulSetEndpoints() []models.Endpoint { +// GetManageStatefulSetEndpoints returns endpoints for managing namespace stateful sets +func GetManageStatefulSetEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/statefulset"}, {Method: "DELETE", Route: "/api/v1/statefulset/@"}, } } -// GetViewK8sNamespaceSecretEndpoints returns endpoints for viewing K8s namespace secrets -func GetViewK8sNamespaceSecretEndpoints() []models.Endpoint { +// GetViewDaemonSetEndpoints returns endpoints for viewing daemon sets +func GetViewDaemonSetEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/daemonset"}, + {Method: "GET", Route: "/api/v1/daemonset/stats"}, + {Method: "GET", Route: "/api/v1/daemonset/@"}, + } +} + +// GetManageDaemonSetEndpoints returns endpoints for managing daemon sets +func GetManageDaemonSetEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/daemonset"}, + {Method: "DELETE", Route: "/api/v1/daemonset/@"}, + } +} + +// GetViewSecretEndpoints returns endpoints for viewing namespace secrets +func GetViewSecretEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/secret"}, {Method: "GET", Route: "/api/v1/secret/@"}, } } -// GetK8sNamespaceManageSecretEndpoints returns endpoints for managing K8s namespace secrets -func GetK8sNamespaceManageSecretEndpoints() []models.Endpoint { +// GetManageSecretEndpoints returns endpoints for managing namespace secrets +func GetManageSecretEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/secret"}, {Method: "DELETE", Route: "/api/v1/secret/@"}, } } -// GetViewK8sNamespaceConfigMapEndpoints returns endpoints for viewing K8s namespace config maps -func GetViewK8sNamespaceConfigMapEndpoints() []models.Endpoint { +// GetViewConfigMapEndpoints returns endpoints for viewing namespace config maps +func GetViewConfigMapEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/config-map"}, {Method: "GET", Route: "/api/v1/config-map/@"}, } } -// GetK8sNamespaceManageConfigMapEndpoints returns endpoints for managing K8s namespace config maps -func GetK8sNamespaceManageConfigMapEndpoints() []models.Endpoint { +// GetManageConfigMapEndpoints returns endpoints for managing namespace config maps +func GetManageConfigMapEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/config-map"}, {Method: "DELETE", Route: "/api/v1/config-map/@"}, } } -// GetViewK8sNamespaceServiceEndpoints returns endpoints for viewing K8s namespace services -func GetViewK8sNamespaceServiceEndpoints() []models.Endpoint { +// GetViewServiceEndpoints returns endpoints for viewing namespace services +func GetViewServiceEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/service"}, {Method: "GET", Route: "/api/v1/service/@"}, } } -// GetK8sNamespaceManageServiceEndpoints returns endpoints for managing K8s namespace services -func GetK8sNamespaceManageServiceEndpoints() []models.Endpoint { +// GetManageServiceEndpoints returns endpoints for managing namespace services +func GetManageServiceEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/service"}, {Method: "DELETE", Route: "/api/v1/service/@"}, } } -// GetViewK8sNamespaceServiceAccountEndpoints returns endpoints for viewing K8s namespace service accounts -func GetViewK8sNamespaceServiceAccountEndpoints() []models.Endpoint { +// GetViewServiceAccountEndpoints returns endpoints for viewing namespace service accounts +func GetViewServiceAccountEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/service-account"}, {Method: "GET", Route: "/api/v1/service-account/@"}, } } -// GetK8sNamespaceManageServiceAccountEndpoints returns endpoints for managing K8s namespace service accounts -func GetK8sNamespaceManageServiceAccountEndpoints() []models.Endpoint { +// GetManageServiceAccountEndpoints returns endpoints for managing namespace service accounts +func GetManageServiceAccountEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/service-account"}, {Method: "GET", Route: "/api/v1/service-account/@"}, } } -// GetViewK8sNodeEndpoints returns endpoints for viewing K8s nodes -func GetViewK8sNodeEndpoints() []models.Endpoint { +// GetViewNodeEndpoints returns endpoints for viewing nodes +func GetViewNodeEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/node"}, {Method: "GET", Route: "/api/v1/node/@"}, } } -// GetManageK8sNodeTaintEndpoints returns endpoints for managing K8s node taints -func GetManageK8sNodeTaintEndpoints() []models.Endpoint { +// GetManageNodeTaintEndpoints returns endpoints for managing node taints +func GetManageNodeTaintEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "api/v1/node/taint/@"}, {Method: "POST", Route: "api/v1/node/untaint/@"}, } } -// GetViewK8sCustomResourceEndpoints returns endpoints for viewing K8s custom resources -func GetViewK8sCustomResourceEndpoints() []models.Endpoint { +// GetDrainNodeEndpoints returns endpoints for draining nodes +func GetDrainNodeEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/node/cordon/@"}, + } +} + +// GetViewCustomResourceEndpoints returns endpoints for viewing custom resources +func GetViewCustomResourceEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/custom-resource"}, {Method: "GET", Route: "/api/v1/custom-resource/@"}, } } -// GetManageK8sCustomResourceEndpoints returns endpoints for managing K8s custom resources -func GetManageK8sCustomResourceEndpoints() []models.Endpoint { +// GetManageCustomResourceEndpoints returns endpoints for managing custom resources +func GetManageCustomResourceEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/custom-resource"}, {Method: "DELETE", Route: "/api/v1/custom-resource/@"}, } } -// GetViewK8sNamespaceLogsEndpoints returns endpoints for viewing K8s namespace logs -func GetViewK8sNamespaceLogsEndpoints() []models.Endpoint { +// GetViewLogsEndpoints returns endpoints for viewing namespace logs +func GetViewLogsEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/pod/logs/"}, } } -// GetManageNamespaceEndpoints returns endpoints for managing K8s namespace endpoints -func GetManageNamespaceEndpoints() []models.Endpoint { - return []models.Endpoint{ - {Method: "POST", Route: "api/v1/endpoints"}, - {Method: "DELETE", Route: "api/v1/endpoints/@"}, - } -} - // GetManageEndpointsEndpoints returns endpoints for managing endpoints func GetManageEndpointsEndpoints() []models.Endpoint { return []models.Endpoint{ @@ -257,50 +295,314 @@ func GetViewEndpointSliceEndpoints() []models.Endpoint { } } -// ViewNamespacePDB returns endpoints for viewing PDBs -func ViewNamespacePDB() []models.Endpoint { +// GetManageEndpointSliceEndpoints returns endpoints for viewing endpoint slices +func GetManageEndpointSliceEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/endpoint-slice"}, + {Method: "DELETE", Route: "/api/v1/endpoint-slice/@"}, + } +} + +// GetViewPDBEndpoints returns endpoints for viewing pod disruption budgets +func GetViewPDBEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/PDB"}, {Method: "GET", Route: "/api/v1/PDB/@"}, } } -// ManageNamespacePDB returns endpoints for managing PDBs -func ManageNamespacePDB() []models.Endpoint { +// GetManagePDBEndpoints returns endpoints for managing pod disruption budgets +func GetManagePDBEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/PDB"}, {Method: "DELETE", Route: "/api/v1/PDB/@"}, } } -// ViewNamespaceControllerRevision returns endpoints for viewing controller revisions -func ViewNamespaceControllerRevision() []models.Endpoint { +// GetViewControllerRevisionEndpoints returns endpoints for viewing controller revisions +func GetViewControllerRevisionEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/controller-revision"}, {Method: "GET", Route: "/api/v1/controller-revision/@"}, } } -// ManageNamespaceControllerRevision returns endpoints for managing controller revisions -func ManageNamespaceControllerRevision() []models.Endpoint { +// GetManageControllerRevisionEndpoints returns endpoints for managing controller revisions +func GetManageControllerRevisionEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/controller-revision"}, {Method: "DELETE", Route: "/api/v1/controller-revision/@"}, } } -// ViewNamespaceReplicationController returns endpoints for viewing replication controllers -func ViewNamespaceReplicationController() []models.Endpoint { +// GetViewReplicationControllerEndpoints returns endpoints for viewing replication controllers +func GetViewReplicationControllerEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "GET", Route: "/api/v1/replication-controller"}, {Method: "GET", Route: "/api/v1/replication-controller/@"}, } } -// ManageNamespaceReplicationController returns endpoints for managing replication controllers -func ManageNamespaceReplicationController() []models.Endpoint { +// GetManageReplicationControllerEndpoints returns endpoints for managing replication controllers +func GetManageReplicationControllerEndpoints() []models.Endpoint { return []models.Endpoint{ {Method: "POST", Route: "/api/v1/replication-controller"}, {Method: "DELETE", Route: "/api/v1/replication-controller/@"}, } } + +// GetManageCustomResourceDefinitionEndpoints returns endpoints for managing custom resource definitions +func GetManageCustomResourceDefinitionEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/crd"}, + {Method: "DELETE", Route: "/api/v1/crd/@"}, + } +} + +// GetViewCustomResourceDefinitionEndpoints returns endpoints for viewing custom resource definitions +func GetViewCustomResourceDefinitionEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/crd"}, + {Method: "GET", Route: "/api/v1/crd/@"}, + } +} + +// GetManageStorageClassEndpoints returns endpoints for managing storage classes +func GetManageStorageClassEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/storage-class"}, + {Method: "DELETE", Route: "/api/v1/storage-class/@"}, + } +} + +// GetViewStorageClassEndpoints returns endpoints for viewing storage classes +func GetViewStorageClassEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/storage-class"}, + {Method: "GET", Route: "/api/v1/storage-class/@"}, + } +} + +// GetManageClusterRoleBindingEndpoints returns endpoints for managing cluster role bindings +func GetManageClusterRoleBindingEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/cluster-role-binding"}, + {Method: "DELETE", Route: "/api/v1/cluster-role-binding/@"}, + } +} + +// GetViewClusterRoleBindingEndpoints returns endpoints for viewing cluster role bindings +func GetViewClusterRoleBindingEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/cluster-role-binding"}, + {Method: "GET", Route: "/api/v1/cluster-role-binding/@"}, + } +} + +// GetManageClusterRoleEndpoints returns endpoints for managing cluster roles +func GetManageClusterRoleEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/cluster-role"}, + {Method: "DELETE", Route: "/api/v1/cluster-role/@"}, + } +} + +// GetViewClusterRoleEndpoints returns endpoints for viewing cluster roles +func GetViewClusterRoleEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/cluster-role"}, + {Method: "GET", Route: "/api/v1/cluster-role/@"}, + } +} + +// GetManagePersistentVolumeEndpoints returns endpoints for managing persistent volumes +func GetManagePersistentVolumeEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/pv"}, + {Method: "DELETE", Route: "/api/v1/pv/@"}, + } +} + +// GetViewPersistentVolumeEndpoints returns endpoints for viewing persistent volumes +func GetViewPersistentVolumeEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/pv"}, + {Method: "GET", Route: "/api/v1/pv/@"}, + } +} + +// GetViewIngressEndpoints returns endpoints for viewing ingresses +func GetViewIngressEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/ingress"}, + {Method: "GET", Route: "/api/v1/ingress/@"}, + } +} + +// GetManageIngressEndpoints returns endpoints for managing ingresses +func GetManageIngressEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/ingress"}, + {Method: "DELETE", Route: "/api/v1/ingress/@"}, + } +} + +// GetViewCertificateEndpoints returns endpoints for viewing certificates +func GetViewCertificateEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/certificate"}, + {Method: "GET", Route: "/api/v1/certificate/@"}, + } +} + +// GetManageCertificateEndpoints returns endpoints for managing certificates +func GetManageCertificateEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/certificate"}, + {Method: "DELETE", Route: "/api/v1/certificate/@"}, + } +} + +// GetViewNamespaceRoleEndpoints returns endpoints for viewing roles +func GetViewNamespaceRoleEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/role"}, + {Method: "GET", Route: "/api/v1/role/@"}, + } +} + +// GetManageNamespaceRoleEndpoints returns endpoints for managing roles +func GetManageNamespaceRoleEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/role"}, + {Method: "DELETE", Route: "/api/v1/role/@"}, + } +} + +// GetViewNamespaceRoleBindingEndpoints returns endpoints for viewing role bindings +func GetViewNamespaceRoleBindingEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/role-binding"}, + {Method: "GET", Route: "/api/v1/role-binding/@"}, + } +} + +// GetManageNamespaceRoleBindingEndpoints returns endpoints for managing role bindings +func GetManageNamespaceRoleBindingEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/role-binding"}, + {Method: "DELETE", Route: "/api/v1/role-binding/@"}, + } +} + +// GetViewJobEndpoints returns endpoints for viewing jobs +func GetViewJobEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/job"}, + {Method: "GET", Route: "/api/v1/job/@"}, + } +} + +// GetManageJobEndpoints returns endpoints for managing jobs +func GetManageJobEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/job"}, + {Method: "DELETE", Route: "/api/v1/job/@"}, + } +} + +// GetViewCronJobEndpoints returns endpoints for viewing cron jobs +func GetViewCronJobEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/cronjob"}, + {Method: "GET", Route: "/api/v1/cronjob/@"}, + } +} + +// GetManageCronJobEndpoints returns endpoints for managing cron jobs +func GetManageCronJobEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/cronjob"}, + {Method: "DELETE", Route: "/api/v1/cronjob/@"}, + } +} + +// GetViewNetworkPolicyEndpoints returns endpoints for viewing network policies +func GetViewNetworkPolicyEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/network-policy"}, + {Method: "GET", Route: "/api/v1/network-policy/@"}, + } +} + +// GetManageNetworkPolicyEndpoints returns endpoints for managing network policies +func GetManageNetworkPolicyEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/network-policy"}, + {Method: "DELETE", Route: "/api/v1/network-policy/@"}, + } +} + +// GetViewResourceQuotaEndpoints returns endpoints for viewing resource quotas +func GetViewResourceQuotaEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/resource-quota"}, + {Method: "GET", Route: "/api/v1/resource-quota/@"}, + } +} + +// GetManageResourceQuotaEndpoints returns endpoints for managing resource quotas +func GetManageResourceQuotaEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/resource-quota"}, + {Method: "DELETE", Route: "/api/v1/resource-quota/@"}, + } +} + +// GetViewGatewayEndpoints returns endpoints for viewing gateways +func GetViewGatewayEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/gateway"}, + {Method: "GET", Route: "/api/v1/gateway/@"}, + } +} + +// GetManageGatewayEndpoints returns endpoints for managing gateways +func GetManageGatewayEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/gateway"}, + {Method: "DELETE", Route: "/api/v1/gateway/@"}, + } +} + +// GetViewVirtualServiceEndpoints returns endpoints for viewing virtual services +func GetViewVirtualServiceEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/virtual-service"}, + {Method: "GET", Route: "/api/v1/virtual-service/@"}, + } +} + +// GetManageVirtualServiceEndpoints returns endpoints for managing virtual services +func GetManageVirtualServiceEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/virtual-service"}, + {Method: "DELETE", Route: "/api/v1/virtual-service/@"}, + } +} + +// GetViewPersistentVolumeClaimEndpoints returns endpoints for viewing PVCs +func GetViewPersistentVolumeClaimEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "GET", Route: "/api/v1/pvc"}, + {Method: "GET", Route: "/api/v1/pvc/@"}, + } +} + +// GetManagePersistentVolumeClaimEndpoints returns endpoints for managing PVCs +func GetManagePersistentVolumeClaimEndpoints() []models.Endpoint { + return []models.Endpoint{ + {Method: "POST", Route: "/api/v1/pvc"}, + {Method: "DELETE", Route: "/api/v1/pvc/@"}, + } +} diff --git a/pkg/auth/utils/utils.go b/pkg/auth/utils/utils.go index 1c5bf55..19ec3d7 100644 --- a/pkg/auth/utils/utils.go +++ b/pkg/auth/utils/utils.go @@ -32,3 +32,13 @@ func GenerateSecureToken(length int) string { } return hex.EncodeToString(bytes) } + +// Helper function to generate reset token +func GenerateResetToken() string { + b := make([]byte, 32) + _, err := rand.Read(b) + if err != nil { + return "" + } + return fmt.Sprintf("%x", b) +} diff --git a/pkg/server/router/routes.go b/pkg/server/router/routes.go index c87d549..3061744 100644 --- a/pkg/server/router/routes.go +++ b/pkg/server/router/routes.go @@ -21,13 +21,14 @@ func AddApiRoutes(httpRg *gin.RouterGroup) { httpRg.PUT("/users/:id", authApi.UserController.UpdateUserHandler) httpRg.DELETE("/users/:id", authApi.UserController.DeleteUserHandler) httpRg.GET("/users/profile", authApi.UserController.GetUserProfileInfoHandler) + httpRg.POST("/:id/reset-password", authApi.UserController.ResetPasswordHandler) + //httpRg.POST("/forgot-password", authApi.UserController.ForgotPasswordHandler) //TODO: need to integrate mail server // Cluster routes httpRg.GET("/clusters", authApi.ClusterController.GetAllClustersHandler) httpRg.GET("/clusters/:id", authApi.ClusterController.GetClusterHandler) // RBAC routes - //httpRg.POST("/permissions", authApi.RbacController.CreatePermissionHandler) /test-api to create permission for dev httpRg.POST("/roles", authApi.RbacController.CreateRoleHandler) httpRg.POST("/assign-roles", authApi.RbacController.AssignRolesHandler) httpRg.GET("/permissions", authApi.RbacController.GetAllPermissionsHandler) From afc3a0390db1523895436f10b9e618f2329bc66f Mon Sep 17 00:00:00 2001 From: Toha Date: Wed, 5 Feb 2025 14:19:09 +0600 Subject: [PATCH 48/64] remove env --- pkg/.env | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 pkg/.env diff --git a/pkg/.env b/pkg/.env deleted file mode 100644 index 140e8ae..0000000 --- a/pkg/.env +++ /dev/null @@ -1,21 +0,0 @@ -# Server Configuration -PORT=8080 - -# MongoDB Configuration -MONGO_URI=mongodb://localhost:27017 -DB_NAME=lighthouse - -# Default User Configuration -USER_EMAIL=admin@default.com -PASSWORD=admin123 - -# JWT Secrets -JWT_SECRET=your_jwt_secret_key -JWT_REFRESH_SECRET=your_refresh_jwt_secret_key - -# Token Expiry Configuration -ACCESS_TOKEN_EXPIRY=15m -REFRESH_TOKEN_EXPIRY=24h -#TRUE/FALSE -AUTH_ENABLED="FALSE" -KUBE_CONFIG_FILE="dev-config.yaml" \ No newline at end of file From 5579a4079db770482152d734d1d752166191d996 Mon Sep 17 00:00:00 2001 From: Toha Date: Wed, 5 Feb 2025 14:21:36 +0600 Subject: [PATCH 49/64] update gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 7646f8d..326a933 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ .vscode node_modules coverage -.env +*.env +pkg/*.env *.patch \ No newline at end of file From ec3ffc663aa67e7a09031259291db1c6894afbb1 Mon Sep 17 00:00:00 2001 From: Nahid Date: Wed, 5 Feb 2025 14:22:02 +0600 Subject: [PATCH 50/64] chore: write unit test --- pkg/auth/utils/utils.go | 12 +- pkg/auth/utils/utils_test.go | 249 +++++++++++++++++++++++++++++++++-- 2 files changed, 251 insertions(+), 10 deletions(-) diff --git a/pkg/auth/utils/utils.go b/pkg/auth/utils/utils.go index 19ec3d7..f184fde 100644 --- a/pkg/auth/utils/utils.go +++ b/pkg/auth/utils/utils.go @@ -9,10 +9,20 @@ import ( ) func HashPassword(password string) string { + // Check password length before hashing + if len(password) == 0 { + log.Printf("Error: Empty password") + return "" + } + if len(password) > 72 { + log.Printf("Error: Password length exceeds 72 bytes") + return "" + } + // Generate a bcrypt hash of the password with a default cost hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { - log.Printf("Error : %v", err) + log.Printf("Error generating hash: %v", err) return "" } return string(hash) diff --git a/pkg/auth/utils/utils_test.go b/pkg/auth/utils/utils_test.go index 23b4bd2..4d5fcd6 100644 --- a/pkg/auth/utils/utils_test.go +++ b/pkg/auth/utils/utils_test.go @@ -1,21 +1,252 @@ package utils -import "testing" +import ( + "encoding/hex" + "strings" + "testing" +) func TestHashPassword(t *testing.T) { - password := "password123" - hashedPassword := HashPassword(password) + tests := []struct { + name string + password string + wantErr bool + }{ + { + name: "Valid password", + password: "password123", + wantErr: false, + }, + { + name: "Empty password", + password: "", + wantErr: true, + }, + { + name: "Long password", + password: strings.Repeat("a", 72), // bcrypt's maximum length + wantErr: false, + }, + } - if hashedPassword == "" { - t.Error("HashPassword returned an empty string") + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + hashedPassword := HashPassword(tt.password) + if (hashedPassword == "") != tt.wantErr { + t.Errorf("HashPassword() error = %v, wantErr %v", hashedPassword == "", tt.wantErr) + return + } + + if !tt.wantErr && !strings.HasPrefix(hashedPassword, "$2a$") { + t.Error("HashPassword() did not generate a valid bcrypt hash") + } + }) } } func TestCheckPassword(t *testing.T) { - password := "password123" - hashedPassword := HashPassword(password) + tests := []struct { + name string + password string + wrongPassword string + wantMatch bool + }{ + { + name: "Matching passwords", + password: "password123", + wrongPassword: "password123", + wantMatch: true, + }, + { + name: "Non-matching passwords", + password: "password123", + wrongPassword: "password124", + wantMatch: false, + }, + { + name: "Case sensitivity", + password: "Password123", + wrongPassword: "password123", + wantMatch: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + hashedPassword := HashPassword(tt.password) + if hashedPassword == "" { + t.Fatal("Failed to hash password") + } + + // Test matching password + if got := CheckPassword(tt.wrongPassword, hashedPassword); got != tt.wantMatch { + t.Errorf("CheckPassword() = %v, want %v", got, tt.wantMatch) + } + }) + } +} + +func TestGenerateSecureToken(t *testing.T) { + tests := []struct { + name string + length int + want int // Expected length of hex string (twice the input length) + }{ + { + name: "16 bytes token", + length: 16, + want: 32, + }, + { + name: "32 bytes token", + length: 32, + want: 64, + }, + { + name: "Zero length", + length: 0, + want: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := GenerateSecureToken(tt.length) + if len(got) != tt.want { + t.Errorf("GenerateSecureToken() length = %v, want %v", len(got), tt.want) + } + + // Verify it's a valid hex string + if tt.length > 0 { + if _, err := hex.DecodeString(got); err != nil { + t.Errorf("GenerateSecureToken() generated invalid hex string: %v", err) + } + } + }) + } +} + +func TestGenerateResetToken(t *testing.T) { + // Test multiple token generations + tokens := make(map[string]bool) + for i := 0; i < 100; i++ { + token := GenerateResetToken() + + // Check token is not empty + if token == "" { + t.Error("GenerateResetToken() returned empty string") + } + + // Check token length (32 bytes = 64 hex chars) + if len(token) != 64 { + t.Errorf("GenerateResetToken() returned token of length %d, want 64", len(token)) + } + + // Check uniqueness + if tokens[token] { + t.Error("GenerateResetToken() generated duplicate token") + } + tokens[token] = true + + // Verify it's a valid hex string + if _, err := hex.DecodeString(token); err != nil { + t.Errorf("GenerateResetToken() generated invalid hex string: %v", err) + } + } +} + +func TestPasswordComplexity(t *testing.T) { + tests := []struct { + name string + password string + wantHash bool + testWrongPassword bool // Flag to control wrong password test + }{ + { + name: "Complex password", + password: "Password123!@#", + wantHash: true, + testWrongPassword: true, + }, + { + name: "Simple password", + password: "password", + wantHash: true, + testWrongPassword: true, + }, + { + name: "Maximum length password", + password: strings.Repeat("a", 72), + wantHash: true, + testWrongPassword: false, // Skip wrong password test for max length + }, + { + name: "Too long password", + password: strings.Repeat("a", 73), + wantHash: false, + testWrongPassword: false, + }, + { + name: "Empty password", + password: "", + wantHash: false, + testWrongPassword: false, + }, + { + name: "Unicode password", + password: "パスワード123", + wantHash: true, + testWrongPassword: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + hashedPassword := HashPassword(tt.password) + hashExists := hashedPassword != "" + + if hashExists != tt.wantHash { + t.Errorf("HashPassword() with %v returned hash = %v, want %v", + tt.password, hashExists, tt.wantHash) + return + } + + // Only verify CheckPassword if we expect a valid hash + if tt.wantHash { + // Verify correct password works + if !CheckPassword(tt.password, hashedPassword) { + t.Error("CheckPassword() failed to verify valid password") + } + + // Only test wrong password for non-maximum length passwords + if tt.testWrongPassword { + wrongPassword := tt.password + "wrong" + if CheckPassword(wrongPassword, hashedPassword) { + t.Error("CheckPassword() incorrectly verified wrong password") + } + } + } + }) + } +} + +// Additional test specifically for maximum length password +func TestMaxLengthPassword(t *testing.T) { + maxLengthPwd := strings.Repeat("a", 72) + hashedPassword := HashPassword(maxLengthPwd) + + if hashedPassword == "" { + t.Fatal("Failed to hash maximum length password") + } + + // Test correct password + if !CheckPassword(maxLengthPwd, hashedPassword) { + t.Error("Failed to verify correct maximum length password") + } - if !CheckPassword(password, hashedPassword) { - t.Error("CheckPassword failed to match the password") + // Test slightly different password + slightlyDifferent := strings.Repeat("a", 71) + "b" + if CheckPassword(slightlyDifferent, hashedPassword) { + t.Error("Incorrectly verified different maximum length password") } } From 5bb2fd9a6dc0e3bdb5ba107bece6a8706c98930a Mon Sep 17 00:00:00 2001 From: Nahid Date: Wed, 5 Feb 2025 14:43:32 +0600 Subject: [PATCH 51/64] chore: add extra checking in reset password API --- pkg/auth/services/user_service.go | 12 ++++++------ pkg/k8s_test/k8s_test.go | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pkg/auth/services/user_service.go b/pkg/auth/services/user_service.go index f3f0ada..f52c65f 100644 --- a/pkg/auth/services/user_service.go +++ b/pkg/auth/services/user_service.go @@ -296,12 +296,6 @@ func (s *UserService) ResetPassword(userID primitive.ObjectID, oldPassword, newP return fmt.Errorf("failed to fetch user: %w", err) } - // Verify old password - err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(oldPassword)) - if err != nil { - return fmt.Errorf("incorrect old password") - } - if user.Username != requester { err := db.UserCollection.FindOne(context.Background(), bson.M{"username": requester}).Decode(&req) if err != nil { @@ -314,6 +308,12 @@ func (s *UserService) ResetPassword(userID primitive.ObjectID, oldPassword, newP return fmt.Errorf("unauthorized !! you don't have ADMIN permission") } + } else { + // Verify old password + err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(oldPassword)) + if err != nil { + return fmt.Errorf("incorrect old password") + } } // Update password in database diff --git a/pkg/k8s_test/k8s_test.go b/pkg/k8s_test/k8s_test.go index a3e8475..ebf5449 100644 --- a/pkg/k8s_test/k8s_test.go +++ b/pkg/k8s_test/k8s_test.go @@ -1,5 +1,6 @@ package k8s_test +/* import ( "context" cfg "github.com/krack8/lighthouse/pkg/config" @@ -91,3 +92,4 @@ func (s *EndToEndSuite) TestHealthIndex() { body, _ := io.ReadAll(resp.Body) s.Equal("This is KloverCloud Lighthouse", string(body)) } +*/ From 4858dcd3b0b51dbdd7d9b6948cc55c0aa46c1af0 Mon Sep 17 00:00:00 2001 From: Nahid Date: Wed, 5 Feb 2025 14:47:37 +0600 Subject: [PATCH 52/64] chore: update error message --- pkg/auth/services/user_service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/auth/services/user_service.go b/pkg/auth/services/user_service.go index f52c65f..3965353 100644 --- a/pkg/auth/services/user_service.go +++ b/pkg/auth/services/user_service.go @@ -312,7 +312,7 @@ func (s *UserService) ResetPassword(userID primitive.ObjectID, oldPassword, newP // Verify old password err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(oldPassword)) if err != nil { - return fmt.Errorf("incorrect old password") + return fmt.Errorf("incorrect current password") } } From 0a501c3b45a3d05493111fa22d40c8e4d85a63ed Mon Sep 17 00:00:00 2001 From: Toha Date: Wed, 5 Feb 2025 18:16:05 +0600 Subject: [PATCH 53/64] namespace test --- pkg/k8s/namespace.go | 10 ++-- pkg/k8s_test/namespace_test.go | 100 +++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 5 deletions(-) diff --git a/pkg/k8s/namespace.go b/pkg/k8s/namespace.go index c592e4b..5174271 100644 --- a/pkg/k8s/namespace.go +++ b/pkg/k8s/namespace.go @@ -56,11 +56,6 @@ type GetNamespaceListInputParams struct { output OutputNamespaceList } -type GetNamespaceInputParams struct { - NamespaceName string - output corev1.Namespace -} - func (p *GetNamespaceListInputParams) Find(c context.Context, namespaceClient v1.NamespaceInterface, pageSize int64) error { log.Logger.Debugw("Entering Search mode....", "src", "namespace") filteredNamespaces := []corev1.Namespace{} @@ -202,6 +197,11 @@ func (namespace *namespaceService) GetNamespaceNameList(c context.Context, p Get }, nil } +type GetNamespaceInputParams struct { + NamespaceName string + output corev1.Namespace +} + func (p *GetNamespaceInputParams) Process(c context.Context) error { log.Logger.Debugw("fetching namespace details of ....", p.NamespaceName) namespacesClient := cfg.GetKubeClientSet().CoreV1().Namespaces() diff --git a/pkg/k8s_test/namespace_test.go b/pkg/k8s_test/namespace_test.go index 6de729e..268b57e 100644 --- a/pkg/k8s_test/namespace_test.go +++ b/pkg/k8s_test/namespace_test.go @@ -1 +1,101 @@ package k8s_test + +// +//import ( +// "context" +// "github.com/krack8/lighthouse/pkg/controller/api" +// "github.com/krack8/lighthouse/pkg/k8s" +// "github.com/stretchr/testify/assert" +// "github.com/stretchr/testify/suite" +// v1 "k8s.io/api/core/v1" +// metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +// "k8s.io/client-go/kubernetes/fake" +// "testing" +//) +// +//type NamespaceTestSuite struct { +// suite.Suite +// clientSet *fake.Clientset +//} +// +//func TestNamespace(t *testing.T) { +// suite.Run(t, new(NamespaceTestSuite)) +//} +// +//func (s *NamespaceTestSuite) SetupNamespaceSuite() { +//} +// +//func (s *NamespaceTestSuite) SetupTest() { +// s.clientSet = fake.NewClientset() +// // Set up before *each* test runs (e.g., reset mocks, clear databases) +//} +// +//func (s *NamespaceTestSuite) TearDownTest() { +// // Clean up after *each* test runs +//} +// +//func (s *NamespaceTestSuite) TestGetNamespaceDetails(t *testing.T) { +// // Mock the Kubernetes client +// clientset := fake.NewSimpleClientset(&corev1.Namespace{ +// ObjectMeta: metav1.ObjectMeta{ +// Name: "test-namespace", +// }, +// }) +// cfg.kubeClientSet = clientset // Assign the fake clientset +// +// // Test case 1: Successful retrieval +// t.Run("Success", func(t *testing.T) { +// p := GetNamespaceInputParams{ +// NamespaceName: "test-namespace", +// } +// expectedNamespace := corev1.Namespace{ +// ObjectMeta: metav1.ObjectMeta{ +// Name: "test-namespace", +// }, +// } +// expectedNamespace = removeNamespaceFields(expectedNamespace) // Apply the function +// +// result, err := namespaceService{}.GetNamespaceDetails(context.Background(), p) +// assert.NoError(t, err) +// assert.NotNil(t, result) +// +// response, ok := result.(ResponseDTO) +// assert.True(t, ok) +// assert.Equal(t, "success", response.Status) +// assert.Equal(t, expectedNamespace, response.Data) +// +// }) +// +// // Test case 2: Namespace not found +// t.Run("NotFound", func(t *testing.T) { +// p := GetNamespaceInputParams{ +// NamespaceName: "non-existent-namespace", +// } +// +// result, err := namespaceService{}.GetNamespaceDetails(context.Background(), p) +// +// assert.Error(t, err) +// assert.Nil(t, result) +// +// }) +//} +// +// +//// A dummy removeNamespaceFields function for testing purposes +//func removeNamespaceFields(ns corev1.Namespace) corev1.Namespace{ +// return ns +//} +// +//type ResponseDTO struct { +// Status string `json:"status"` +// Data interface{} `json:"data"` +//} +//var cfg config +// +//type config struct { +// KubeClientSet *fake.Clientset +//} +// +//func (c *config) GetKubeClientSet() *fake.Clientset { +// return c.KubeClientSet +//} From 0730b8e72f0eeca1484d7b2610435fe36344a73f Mon Sep 17 00:00:00 2001 From: Toha Date: Wed, 5 Feb 2025 18:31:04 +0600 Subject: [PATCH 54/64] delete secret bug fix --- pkg/controller/api/secret.go | 7 +++++++ pkg/k8s/secret.go | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/pkg/controller/api/secret.go b/pkg/controller/api/secret.go index 62846a0..a2b983d 100644 --- a/pkg/controller/api/secret.go +++ b/pkg/controller/api/secret.go @@ -141,6 +141,13 @@ func (ctrl *secretController) DeleteSecret(ctx *gin.Context) { var result ResponseDTO input := new(k8s.DeleteSecretInputParams) input.SecretName = ctx.Param("name") + queryNamespace := ctx.Query("namespace") + if queryNamespace == "" { + log.Logger.Errorw("Namespace required in query params", "value", queryNamespace) + SendErrorResponse(ctx, "Namespace required in query params") + return + } + input.NamespaceName = queryNamespace taskName := tasks.GetTaskName(k8s.SecretService().DeleteSecret) logRequestedTaskController("secret", taskName) inputTask, err := json.Marshal(input) diff --git a/pkg/k8s/secret.go b/pkg/k8s/secret.go index ebeb427..f965295 100644 --- a/pkg/k8s/secret.go +++ b/pkg/k8s/secret.go @@ -244,8 +244,8 @@ type DeleteSecretInputParams struct { } func (p *DeleteSecretInputParams) Process(c context.Context) error { - log.Logger.Debugw("deleting secret of ....", p.NamespaceName) - secretClient := cfg.GetKubeClientSet().CoreV1().PersistentVolumes() + log.Logger.Info("deleting secret of ....", p.NamespaceName) + secretClient := cfg.GetKubeClientSet().CoreV1().Secrets(p.NamespaceName) _, err := secretClient.Get(context.Background(), p.SecretName, metav1.GetOptions{}) if err != nil { log.Logger.Errorw("get secret ", p.SecretName, "err", err.Error()) From 4d188920e097b0dc5a2716b42f974000ce559ac2 Mon Sep 17 00:00:00 2001 From: Toha Date: Wed, 5 Feb 2025 18:31:35 +0600 Subject: [PATCH 55/64] delete secret bug fix --- pkg/k8s/secret.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/k8s/secret.go b/pkg/k8s/secret.go index f965295..d617c0d 100644 --- a/pkg/k8s/secret.go +++ b/pkg/k8s/secret.go @@ -244,7 +244,7 @@ type DeleteSecretInputParams struct { } func (p *DeleteSecretInputParams) Process(c context.Context) error { - log.Logger.Info("deleting secret of ....", p.NamespaceName) + log.Logger.Debugw("deleting secret of ....", p.NamespaceName) secretClient := cfg.GetKubeClientSet().CoreV1().Secrets(p.NamespaceName) _, err := secretClient.Get(context.Background(), p.SecretName, metav1.GetOptions{}) if err != nil { From 95b8d025e33e7ed2f029cae5bb6cd00c51ac597e Mon Sep 17 00:00:00 2001 From: Md Sajal Mia Date: Wed, 5 Feb 2025 18:54:57 +0600 Subject: [PATCH 56/64] remove unused package, non admin permission fix --- frontend/angular.json | 2 - frontend/package-lock.json | 494 +++++------------- frontend/package.json | 6 +- .../projects/core-ui/src/guards/auth.guard.ts | 9 - .../core-ui/src/guards/role-guard.service.ts | 9 +- .../src/interceptors/errors.interceptor.ts | 4 +- .../src/services/permission.service.ts | 2 +- .../core-ui/src/services/requester.service.ts | 2 +- .../toolbar-user-dropdown.component.html | 4 +- .../toolbar-user-dropdown.component.ts | 2 +- frontend/src/app/auth/auth.service.ts | 30 +- .../src/app/auth/login/login.component.ts | 20 +- .../src/app/cluster/cluster-routing.module.ts | 2 +- .../onboard-cluster-prerequisite.component.ts | 2 +- .../k8s-namespaces/k8s-namespaces.module.ts | 2 - .../user-role-update-form.component.html | 2 +- .../user-role-update-form.component.ts | 1 - .../user/user-form/user-form.component.html | 6 +- .../user/user-form/user-form.component.ts | 13 +- .../change-password.component.ts | 50 +- .../user-profile-details.component.html | 2 +- .../user-profile/user-profile.endpoints.ts | 1 + .../app/user-profile/user-profile.module.ts | 4 +- .../app/user-profile/user-profile.service.ts | 14 + frontend/src/data/navigation.ts | 4 +- 25 files changed, 213 insertions(+), 474 deletions(-) create mode 100644 frontend/src/app/user-profile/user-profile.endpoints.ts create mode 100644 frontend/src/app/user-profile/user-profile.service.ts diff --git a/frontend/angular.json b/frontend/angular.json index 4e88304..f942ec3 100644 --- a/frontend/angular.json +++ b/frontend/angular.json @@ -67,8 +67,6 @@ "pluralize", "@dagrejs/dagre", - "@iconify/icons-fa-solid/info-circle", - "@iconify/icons-ic/twotone-filter-list", "@iconify/icons-ic/twotone-lock", "@iconify/icons-ic/twotone-greater-than", diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 61bb65c..6a84a9b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -20,13 +20,9 @@ "@angular/platform-browser-dynamic": "14.3.0", "@angular/router": "14.3.0", "@dagrejs/dagre": "^1.1.4", - "@iconify/icons-fa-brands": "^1.2.4", - "@iconify/icons-fa-solid": "^1.2.4", "@iconify/icons-ic": "^1.2.13", "@ngx-loading-bar/core": "^6.0.2", "@ngx-loading-bar/router": "^6.0.2", - "@swimlane/ngx-charts": "^20.5.0", - "@types/pluralize": "^0.0.33", "@visurel/iconify-angular": "^11.0.0", "ace-builds": "^1.32.6", "dayjs": "^1.11.10", @@ -40,7 +36,6 @@ "ng2-search-filter": "0.5.1", "ngx-webstorage": "^10.0.1", "normalize.css": "8.0.1", - "pako": "1.0.11", "pluralize": "^8.0.0", "rxjs": "^6.6.7", "sockjs-client": "1.3.0", @@ -60,6 +55,7 @@ "@types/jasmine": "~3.6.0", "@types/jasminewd2": "2.0.8", "@types/node": "^12.20.55", + "@types/pluralize": "^0.0.33", "@types/simplebar": "2.4.2", "codelyzer": "^6.0.2", "jasmine-core": "^3.8.0", @@ -3595,22 +3591,6 @@ "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", "dev": true }, - "node_modules/@iconify/icons-fa-brands": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@iconify/icons-fa-brands/-/icons-fa-brands-1.2.4.tgz", - "integrity": "sha512-MnUUfPhKJ6ECvVNxipBCmyuvJPDgRJcJ1f9nfgv0obikp6D9d6dGtMrR+bw4Gku6Gr/WCnS1e/Qd5gdmXlE84w==", - "dependencies": { - "@iconify/types": "*" - } - }, - "node_modules/@iconify/icons-fa-solid": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@iconify/icons-fa-solid/-/icons-fa-solid-1.2.4.tgz", - "integrity": "sha512-gLH+zYl/Srpnlsb++vys7WNXNGPTXjd/BaUO0Q9Z52vpZnmdiHx420TzsGSS5Pi5AR3QL1wdbkopS3EIaSdsZg==", - "dependencies": { - "@iconify/types": "*" - } - }, "node_modules/@iconify/icons-ic": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/@iconify/icons-ic/-/icons-ic-1.2.13.tgz", @@ -4034,38 +4014,6 @@ "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", "dev": true }, - "node_modules/@swimlane/ngx-charts": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@swimlane/ngx-charts/-/ngx-charts-20.5.0.tgz", - "integrity": "sha512-PNBIHdu/R3ceD7jnw1uCBVOj4k3T6IxfdW6xsDsglGkZyoWMEEq4tLoEurjLEKzmDtRv9c35kVNOXy0lkOuXeA==", - "dependencies": { - "d3-array": "^3.1.1", - "d3-brush": "^3.0.0", - "d3-color": "^3.1.0", - "d3-ease": "^3.0.1", - "d3-format": "^3.1.0", - "d3-hierarchy": "^3.1.0", - "d3-interpolate": "^3.0.1", - "d3-sankey": "^0.12.3", - "d3-scale": "^4.0.2", - "d3-selection": "^3.0.0", - "d3-shape": "^3.2.0", - "d3-time-format": "^3.0.0", - "d3-transition": "^3.0.1", - "rfdc": "^1.3.0", - "tslib": "^2.0.0" - }, - "peerDependencies": { - "@angular/animations": ">=12.0.0", - "@angular/cdk": ">=12.0.0", - "@angular/common": ">=12.0.0", - "@angular/core": ">=12.0.0", - "@angular/forms": ">=12.0.0", - "@angular/platform-browser": ">=12.0.0", - "@angular/platform-browser-dynamic": ">=12.0.0", - "rxjs": "^6.5.3 || ^7.4.0" - } - }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -4285,7 +4233,8 @@ "node_modules/@types/pluralize": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/@types/pluralize/-/pluralize-0.0.33.tgz", - "integrity": "sha512-JOqsl+ZoCpP4e8TDke9W79FDcSgPAR0l6pixx2JHkhnRjvShyYiAYw2LVsnA7K08Y6DeOnaU6ujmENO4os/cYg==" + "integrity": "sha512-JOqsl+ZoCpP4e8TDke9W79FDcSgPAR0l6pixx2JHkhnRjvShyYiAYw2LVsnA7K08Y6DeOnaU6ujmENO4os/cYg==", + "dev": true }, "node_modules/@types/q": { "version": "0.0.32", @@ -6281,9 +6230,9 @@ "dev": true }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "dependencies": { "path-key": "^3.1.0", @@ -6483,238 +6432,6 @@ "node": ">=0.12" } }, - "node_modules/d3-array": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", - "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", - "dependencies": { - "internmap": "1 - 2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-brush": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", - "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "3", - "d3-transition": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dispatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", - "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-drag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", - "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-selection": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-ease": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-format": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", - "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-hierarchy": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", - "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "dependencies": { - "d3-color": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-path": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", - "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" - }, - "node_modules/d3-sankey": { - "version": "0.12.3", - "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", - "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", - "dependencies": { - "d3-array": "1 - 2", - "d3-shape": "^1.2.0" - } - }, - "node_modules/d3-sankey/node_modules/d3-array": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", - "dependencies": { - "internmap": "^1.0.0" - } - }, - "node_modules/d3-sankey/node_modules/d3-shape": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", - "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", - "dependencies": { - "d3-path": "1" - } - }, - "node_modules/d3-sankey/node_modules/internmap": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", - "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" - }, - "node_modules/d3-scale": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "dependencies": { - "d3-array": "2.10.0 - 3", - "d3-format": "1 - 3", - "d3-interpolate": "1.2.0 - 3", - "d3-time": "2.1.1 - 3", - "d3-time-format": "2 - 4" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-shape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", - "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", - "dependencies": { - "d3-path": "^3.1.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-shape/node_modules/d3-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", - "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", - "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", - "dependencies": { - "d3-array": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time-format": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz", - "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==", - "dependencies": { - "d3-time": "1 - 2" - } - }, - "node_modules/d3-time-format/node_modules/d3-array": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", - "dependencies": { - "internmap": "^1.0.0" - } - }, - "node_modules/d3-time-format/node_modules/d3-time": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz", - "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", - "dependencies": { - "d3-array": "2" - } - }, - "node_modules/d3-time-format/node_modules/internmap": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", - "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" - }, - "node_modules/d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-transition": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", - "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", - "dependencies": { - "d3-color": "1 - 3", - "d3-dispatch": "1 - 3", - "d3-ease": "1 - 3", - "d3-interpolate": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "d3-selection": "2 - 3" - } - }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -7918,9 +7635,9 @@ "dev": true }, "node_modules/express": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dev": true, "dependencies": { "accepts": "~1.3.8", @@ -7942,7 +7659,7 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", @@ -7957,6 +7674,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express/node_modules/debug": { @@ -9148,14 +8869,6 @@ "tslib": "^2.1.0" } }, - "node_modules/internmap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", - "engines": { - "node": ">=12" - } - }, "node_modules/ip-address": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", @@ -10742,9 +10455,9 @@ "dev": true }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "funding": [ { "type": "github", @@ -11563,7 +11276,8 @@ "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true }, "node_modules/parent-module": { "version": "1.0.1", @@ -11701,9 +11415,9 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "dev": true }, "node_modules/path-type": { @@ -12906,34 +12620,6 @@ "node": ">=8" } }, - "node_modules/protractor/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/protractor/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/protractor/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/protractor/node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -12973,31 +12659,6 @@ "node": ">=0.8.0" } }, - "node_modules/protractor/node_modules/webdriver-manager": { - "version": "12.1.9", - "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.9.tgz", - "integrity": "sha512-Yl113uKm8z4m/KMUVWHq1Sjtla2uxEBtx2Ue3AmIlnlPAKloDn/Lvmy6pqWCUersVISpdMeVpAaGbNnvMuT2LQ==", - "dev": true, - "dependencies": { - "adm-zip": "^0.5.2", - "chalk": "^1.1.1", - "del": "^2.2.0", - "glob": "^7.0.3", - "ini": "^1.3.4", - "minimist": "^1.2.0", - "q": "^1.4.1", - "request": "^2.87.0", - "rimraf": "^2.5.2", - "semver": "^5.3.0", - "xml2js": "^0.4.17" - }, - "bin": { - "webdriver-manager": "bin/webdriver-manager" - }, - "engines": { - "node": ">=6.9.x" - } - }, "node_modules/protractor/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -13663,7 +13324,8 @@ "node_modules/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==" + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true }, "node_modules/rgb-regex": { "version": "1.0.1", @@ -16069,6 +15731,114 @@ "node": ">=6.9.x" } }, + "node_modules/webdriver-manager": { + "version": "12.1.9", + "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.9.tgz", + "integrity": "sha512-Yl113uKm8z4m/KMUVWHq1Sjtla2uxEBtx2Ue3AmIlnlPAKloDn/Lvmy6pqWCUersVISpdMeVpAaGbNnvMuT2LQ==", + "dev": true, + "dependencies": { + "adm-zip": "^0.5.2", + "chalk": "^1.1.1", + "del": "^2.2.0", + "glob": "^7.0.3", + "ini": "^1.3.4", + "minimist": "^1.2.0", + "q": "^1.4.1", + "request": "^2.87.0", + "rimraf": "^2.5.2", + "semver": "^5.3.0", + "xml2js": "^0.4.17" + }, + "bin": { + "webdriver-manager": "bin/webdriver-manager" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/webdriver-manager/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/webdriver-manager/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/webdriver-manager/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/webdriver-manager/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/webpack": { "version": "5.76.1", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index e0a8d6c..f57e961 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -28,13 +28,9 @@ "@angular/platform-browser-dynamic": "14.3.0", "@angular/router": "14.3.0", "@dagrejs/dagre": "^1.1.4", - "@iconify/icons-fa-brands": "^1.2.4", - "@iconify/icons-fa-solid": "^1.2.4", "@iconify/icons-ic": "^1.2.13", "@ngx-loading-bar/core": "^6.0.2", "@ngx-loading-bar/router": "^6.0.2", - "@swimlane/ngx-charts": "^20.5.0", - "@types/pluralize": "^0.0.33", "@visurel/iconify-angular": "^11.0.0", "ace-builds": "^1.32.6", "dayjs": "^1.11.10", @@ -48,7 +44,6 @@ "ng2-search-filter": "0.5.1", "ngx-webstorage": "^10.0.1", "normalize.css": "8.0.1", - "pako": "1.0.11", "pluralize": "^8.0.0", "rxjs": "^6.6.7", "sockjs-client": "1.3.0", @@ -68,6 +63,7 @@ "@types/jasmine": "~3.6.0", "@types/jasminewd2": "2.0.8", "@types/node": "^12.20.55", + "@types/pluralize": "^0.0.33", "@types/simplebar": "2.4.2", "codelyzer": "^6.0.2", "jasmine-core": "^3.8.0", diff --git a/frontend/projects/core-ui/src/guards/auth.guard.ts b/frontend/projects/core-ui/src/guards/auth.guard.ts index 4fc6860..98b71fb 100644 --- a/frontend/projects/core-ui/src/guards/auth.guard.ts +++ b/frontend/projects/core-ui/src/guards/auth.guard.ts @@ -34,21 +34,12 @@ export class AuthGuard implements CanActivate, CanActivateChild { } protected checkAuthentication(stateUrl?: string): boolean { - const requester = this.requesterService.get(); - // Checking Authorization if (!this.requesterService.isAuthenticated()) { this.router.navigate(['/auth/login']); return false; } - // Checking User Is Verification - // ? Don't place it requester service. - if (requester?.userInfo?.is_verified !== true) { - this.router.navigate(['/email-verification']); - return false; - } - return true; } } diff --git a/frontend/projects/core-ui/src/guards/role-guard.service.ts b/frontend/projects/core-ui/src/guards/role-guard.service.ts index b20d317..140e505 100644 --- a/frontend/projects/core-ui/src/guards/role-guard.service.ts +++ b/frontend/projects/core-ui/src/guards/role-guard.service.ts @@ -64,15 +64,8 @@ export class RoleGuardService implements CanActivate, CanActivateChild, CanLoad return false; } - // TODO: optimize it when userProfile data fetch - // Checking User Is Verification - // Don't place it requester service. - if (requester?.userInfo?.is_verified !== true) { - return this.router.navigate(['/email-verification']); - } - // Check Permission - return this._checkRolePermission(requester.userInfo?.user_type || '', route.data['permissions'] || [], state.url); + return this._checkRolePermission(requester?.userInfo?.user_type || '', route.data['permissions'] || [], state.url); } /** diff --git a/frontend/projects/core-ui/src/interceptors/errors.interceptor.ts b/frontend/projects/core-ui/src/interceptors/errors.interceptor.ts index 65148fb..0838c92 100644 --- a/frontend/projects/core-ui/src/interceptors/errors.interceptor.ts +++ b/frontend/projects/core-ui/src/interceptors/errors.interceptor.ts @@ -28,8 +28,8 @@ export class ErrorsInterceptor implements HttpInterceptor { } case status === 403: { const currentUser = this.requesterSvc.get(); - if (currentUser?.userInfo?.user_type === 'NON_ADMIN') { - if (response?.error?.path !== '/api/v1/current-user/permissions') { + if (currentUser?.userInfo?.user_type === 'USER') { + if (response?.error?.path !== '/v1/permissions/users') { // TODO: Need to handle 403 error from api error // this.router.navigate(["/403"]); this.permissionSvc.fetchUserPermissions().subscribe(); diff --git a/frontend/projects/core-ui/src/services/permission.service.ts b/frontend/projects/core-ui/src/services/permission.service.ts index 698f82a..8fa9e4c 100644 --- a/frontend/projects/core-ui/src/services/permission.service.ts +++ b/frontend/projects/core-ui/src/services/permission.service.ts @@ -50,7 +50,7 @@ export class PermissionService { // Dep fetchUserPermissions(): Observable { - return this._httpService.get('/v1//permissions/users').pipe( + return this._httpService.get('/v1/permissions/users').pipe( map(res => { const _permissions: string[] = ['*']; Object.entries(res).map(([_, value]) => { diff --git a/frontend/projects/core-ui/src/services/requester.service.ts b/frontend/projects/core-ui/src/services/requester.service.ts index 278b0d1..7693f27 100644 --- a/frontend/projects/core-ui/src/services/requester.service.ts +++ b/frontend/projects/core-ui/src/services/requester.service.ts @@ -32,7 +32,7 @@ export class RequesterService { if (currentUser) { // ? Checking User Status if (currentUser?.userInfo?.user_is_active === false) { - if (currentUser?.userInfo?.user_type === 'NON_ADMIN') { + if (currentUser?.userInfo?.user_type === 'USER') { this.snackBar.open('Your account is deactivated. Please contact your admin', 'Close', { duration: 10000 }); diff --git a/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user-dropdown/toolbar-user-dropdown.component.html b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user-dropdown/toolbar-user-dropdown.component.html index 4d21e70..381381e 100644 --- a/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user-dropdown/toolbar-user-dropdown.component.html +++ b/frontend/projects/sdk-ui/src/layout/toolbar/toolbar-user/toolbar-user-dropdown/toolbar-user-dropdown.component.html @@ -2,7 +2,7 @@ diff --git a/frontend/src/app/user-profile/user-profile.endpoints.ts b/frontend/src/app/user-profile/user-profile.endpoints.ts new file mode 100644 index 0000000..877e92b --- /dev/null +++ b/frontend/src/app/user-profile/user-profile.endpoints.ts @@ -0,0 +1 @@ +export const RESET_PASSWORD = '/v1/{0}/reset-password'; diff --git a/frontend/src/app/user-profile/user-profile.module.ts b/frontend/src/app/user-profile/user-profile.module.ts index d24f8b1..47130eb 100644 --- a/frontend/src/app/user-profile/user-profile.module.ts +++ b/frontend/src/app/user-profile/user-profile.module.ts @@ -15,6 +15,7 @@ import { HttpClientModule } from '@angular/common/http'; import { MatProgressBarModule } from '@angular/material/progress-bar'; import { MatDialogModule } from '@angular/material/dialog'; import { MatMenuModule } from '@angular/material/menu'; +import { UserProfileService } from './user-profile.service'; @NgModule({ declarations: [UserProfileDetailsComponent], @@ -34,6 +35,7 @@ import { MatMenuModule } from '@angular/material/menu'; IconModule, FlexModule, MatMenuModule - ] + ], + providers: [UserProfileService] }) export class UserProfileModule {} diff --git a/frontend/src/app/user-profile/user-profile.service.ts b/frontend/src/app/user-profile/user-profile.service.ts new file mode 100644 index 0000000..a383229 --- /dev/null +++ b/frontend/src/app/user-profile/user-profile.service.ts @@ -0,0 +1,14 @@ +import { inject, Injectable } from '@angular/core'; +import { HttpService } from '@core-ui/services'; +import { Utils } from '@shared-ui/utils'; +import { Observable } from 'rxjs'; +import * as endpoints from './user-profile.endpoints'; + +@Injectable() +export class UserProfileService { + private http = inject(HttpService); + + resetPassword(userId: string, payload: Record): Observable { + return this.http.post(Utils.formatString(endpoints.RESET_PASSWORD, userId), payload); + } +} diff --git a/frontend/src/data/navigation.ts b/frontend/src/data/navigation.ts index 839a046..9f93190 100644 --- a/frontend/src/data/navigation.ts +++ b/frontend/src/data/navigation.ts @@ -28,9 +28,7 @@ export const SIDENAV_LIST: SidenavLink[] = [ label: 'Clusters', route: '/clusters', icon: icGroupWork, - id: 'clusters', - envName: 'cluster', - permissionName: 'VIEW_CLUSTER' + id: 'clusters' }, // { // type: 'link', From 5c0a7c6fdb57e8f6d1ccdb9a7f287efec5231405 Mon Sep 17 00:00:00 2001 From: RashidChy Date: Thu, 6 Feb 2025 11:21:42 +0600 Subject: [PATCH 57/64] on-boarded-cluster title removed --- .../src/app/cluster/cluster-list/cluster-list.component.html | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/frontend/src/app/cluster/cluster-list/cluster-list.component.html b/frontend/src/app/cluster/cluster-list/cluster-list.component.html index d2d1b5b..bdd19f1 100644 --- a/frontend/src/app/cluster/cluster-list/cluster-list.component.html +++ b/frontend/src/app/cluster/cluster-list/cluster-list.component.html @@ -21,10 +21,7 @@

    Internal server error!!!

    {{ cluster?.name }} -
    - On-boarded cluster -
    -
    +
    {{ cluster?.is_active ? 'Active' : 'Pending...' }}
    From 7f236f0743c001805c90536b54f008bd94688f39 Mon Sep 17 00:00:00 2001 From: Md Sajal Mia Date: Thu, 6 Feb 2025 11:58:02 +0600 Subject: [PATCH 58/64] UI fix --- .../access-role-form.component.html | 6 +++--- .../access-role-form.component.scss | 17 ++++++----------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/frontend/src/app/management/access-role/containers/access-role-form/access-role-form.component.html b/frontend/src/app/management/access-role/containers/access-role-form/access-role-form.component.html index d4ff1fd..6e74f72 100644 --- a/frontend/src/app/management/access-role/containers/access-role-form/access-role-form.component.html +++ b/frontend/src/app/management/access-role/containers/access-role-form/access-role-form.component.html @@ -9,15 +9,15 @@

    {{ roleId ? 'Update' : 'Create New' }} Role

    -
    - +
    + Role Name Role Name is required - + Description diff --git a/frontend/src/app/management/access-role/containers/access-role-form/access-role-form.component.scss b/frontend/src/app/management/access-role/containers/access-role-form/access-role-form.component.scss index 913f752..3950cf2 100644 --- a/frontend/src/app/management/access-role/containers/access-role-form/access-role-form.component.scss +++ b/frontend/src/app/management/access-role/containers/access-role-form/access-role-form.component.scss @@ -19,13 +19,6 @@ } } -::ng-deep { - .role-name-mat-form-field, - .role-desc-mat-form-field { - max-width: 500px; - } -} - ._role-expansion { &_container { background-color: var(--background-card); @@ -229,7 +222,9 @@ border-radius: 6px; padding: 15px; } -.mat-expansion-panel-header .mat-checkbox { - display: flex; - align-items: center; -} + + +.actions { + position: sticky; + bottom: 20px; +} \ No newline at end of file From f38af56e1af74e2232e1e9f29a1ffad7df0758e2 Mon Sep 17 00:00:00 2001 From: Toha Date: Sun, 9 Feb 2025 18:19:51 +0600 Subject: [PATCH 59/64] test structure --- README.md | 12 +++ pkg/k8s/namespace.go | 28 +++-- pkg/k8s_test/k8s_test.go | 187 +++++++++++++++++---------------- pkg/k8s_test/namespace_test.go | 155 ++++++++++++++------------- 4 files changed, 204 insertions(+), 178 deletions(-) diff --git a/README.md b/README.md index 94bc2b4..4a39fce 100644 --- a/README.md +++ b/README.md @@ -28,4 +28,16 @@ environment variables NO_AUTH="TRUE" // Noauth disabled NO_AUTH="FALSE" +``` + +Go Test +```azure +cd pkg/k8s_test +go test +-- for specific func +go test -run TestFunctionA +-- coverage +go tool cover --html=coverage.out +-- to view in browser +go tool cover --html=coverage.out ``` \ No newline at end of file diff --git a/pkg/k8s/namespace.go b/pkg/k8s/namespace.go index 5174271..9c168cc 100644 --- a/pkg/k8s/namespace.go +++ b/pkg/k8s/namespace.go @@ -20,7 +20,8 @@ type NamespaceServiceInterface interface { DeleteNamespace(c context.Context, p DeleteNamespaceInputParams) (interface{}, error) } -type namespaceService struct{} +type namespaceService struct { +} var nss namespaceService @@ -28,6 +29,14 @@ func NamespaceService() *namespaceService { return &nss } +func (p *GetNamespaceInputParams) setClient() { + p.Client = cfg.GetKubeClientSet().CoreV1().Namespaces() +} + +func getNamespaceClient() v1.NamespaceInterface { + return cfg.GetKubeClientSet().CoreV1().Namespaces() +} + func (p *GetNamespaceListInputParams) removeNamespaceListFields() interface{} { namespaceList := p.output.Result.([]corev1.Namespace) for idx, _ := range namespaceList { @@ -198,16 +207,23 @@ func (namespace *namespaceService) GetNamespaceNameList(c context.Context, p Get } type GetNamespaceInputParams struct { + Client v1.NamespaceInterface NamespaceName string output corev1.Namespace } +func (p *GetNamespaceInputParams) GetClient() v1.NamespaceInterface { + if p.Client != nil { + return p.Client + } + return getNamespaceClient() +} + func (p *GetNamespaceInputParams) Process(c context.Context) error { log.Logger.Debugw("fetching namespace details of ....", p.NamespaceName) - namespacesClient := cfg.GetKubeClientSet().CoreV1().Namespaces() - output, err := namespacesClient.Get(context.Background(), p.NamespaceName, metav1.GetOptions{}) + output, err := p.GetClient().Get(context.Background(), p.NamespaceName, metav1.GetOptions{}) if err != nil { - log.Logger.Errorw("Failed to get namespace ", p.NamespaceName, "err", err.Error()) + log.Logger.Errorw("Failed to get namespace "+p.NamespaceName, "err", err.Error()) return err } output.ManagedFields = nil @@ -274,8 +290,8 @@ type DeleteNamespaceInputParams struct { func (p *DeleteNamespaceInputParams) Process(c context.Context) error { log.Logger.Debugw("Deleting Namespace ....", "value", p.NamespaceName) - namespacesClient := cfg.GetKubeClientSet().CoreV1().Namespaces() - err := namespacesClient.Delete(context.Background(), p.NamespaceName, metav1.DeleteOptions{}) + namespaceClient := cfg.GetKubeClientSet().CoreV1().Namespaces() + err := namespaceClient.Delete(context.Background(), p.NamespaceName, metav1.DeleteOptions{}) if err != nil { log.Logger.Errorw("Failed to delete namespace "+p.NamespaceName, "err", err.Error()) return err diff --git a/pkg/k8s_test/k8s_test.go b/pkg/k8s_test/k8s_test.go index ebf5449..af19798 100644 --- a/pkg/k8s_test/k8s_test.go +++ b/pkg/k8s_test/k8s_test.go @@ -1,95 +1,96 @@ package k8s_test -/* -import ( - "context" - cfg "github.com/krack8/lighthouse/pkg/config" - "github.com/krack8/lighthouse/pkg/k8s" - "github.com/stretchr/testify/suite" - "io" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes/fake" - "net/http" - "testing" -) - -func TestListNamespaces(t *testing.T) { - // Mock the Kubernetes client using a fake client - clientset := fake.NewClientset() - - // Create mock namespaces - namespaceNames := []string{"default", "kube-system", "test-namespace"} - for _, ns := range namespaceNames { - _, err := clientset.CoreV1().Namespaces().Create(context.TODO(), &v1.Namespace{ - ObjectMeta: metav1.ObjectMeta{Name: ns}, - }, metav1.CreateOptions{}) - if err != nil { - t.Fatalf("Failed to create namespace: %v", err) - } - } - - // Fetch namespaces using FetchNamespaces function - fetchedNamespaces, err := k8s.ListNamespaces(clientset) - if err != nil { - t.Fatalf("FetchNamespaces failed: %v", err) - } - - // Validate the fetched namespaces - for _, expected := range namespaceNames { - found := false - for _, actual := range fetchedNamespaces { - if expected == actual { - found = true - break - } - } - if !found { - t.Errorf("Expected namespace %q not found", expected) - } - } -} - -var ( - BaseUrl = "http://127.0.0.1:" + cfg.ServerPort - HealthEndpoint = "/health" - IndexEndpoint = "/" -) - -type EndToEndSuite struct { - suite.Suite - client *http.Client -} - -func TestEndToEnd(t *testing.T) { - suite.Run(t, new(EndToEndSuite)) -} - -func (s *EndToEndSuite) SetupSuite() { - s.client = &http.Client{} -} - -func (s *EndToEndSuite) SetupTest() { - // Set up before *each* test runs (e.g., reset mocks, clear databases) -} - -func (s *EndToEndSuite) TearDownTest() { - // Clean up after *each* test runs -} - -func (s *EndToEndSuite) TestHealthCheck() { - resp, _ := s.client.Get(BaseUrl + HealthEndpoint) - defer resp.Body.Close() - s.Equal(resp.StatusCode, http.StatusOK) - body, _ := io.ReadAll(resp.Body) - s.Equal("I am live!", string(body)) -} - -func (s *EndToEndSuite) TestHealthIndex() { - resp, _ := s.client.Get(BaseUrl + IndexEndpoint) - defer resp.Body.Close() - s.Equal(resp.StatusCode, http.StatusOK) - body, _ := io.ReadAll(resp.Body) - s.Equal("This is KloverCloud Lighthouse", string(body)) -} -*/ +// +//import ( +// "context" +// _cfg "github.com/krack8/lighthouse/pkg/config" +// "github.com/krack8/lighthouse/pkg/k8s" +// "github.com/stretchr/testify/suite" +// "io" +// v1 "k8s.io/api/core/v1" +// metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +// "k8s.io/client-go/kubernetes/fake" +// "net/http" +// "testing" +//) +// +//var IsTesting = false +// +//func TestListNamespaces(t *testing.T) { +// // Mock the Kubernetes client using a fake client +// clientset := fake.NewClientset() +// +// // Create mock namespaces +// namespaceNames := []string{"default", "kube-system", "test-namespace"} +// for _, ns := range namespaceNames { +// _, err := clientset.CoreV1().Namespaces().Create(context.TODO(), &v1.Namespace{ +// ObjectMeta: metav1.ObjectMeta{Name: ns}, +// }, metav1.CreateOptions{}) +// if err != nil { +// t.Fatalf("Failed to create namespace: %v", err) +// } +// } +// +// // Fetch namespaces using FetchNamespaces function +// fetchedNamespaces, err := k8s.ListNamespaces(clientset) +// if err != nil { +// t.Fatalf("FetchNamespaces failed: %v", err) +// } +// +// // Validate the fetched namespaces +// for _, expected := range namespaceNames { +// found := false +// for _, actual := range fetchedNamespaces { +// if expected == actual { +// found = true +// break +// } +// } +// if !found { +// t.Errorf("Expected namespace %q not found", expected) +// } +// } +//} +// +//var ( +// BaseUrl = "http://127.0.0.1:" + _cfg.ServerPort +// HealthEndpoint = "/health" +// IndexEndpoint = "/" +//) +// +//type EndToEndSuite struct { +// suite.Suite +// client *http.Client +//} +// +//func TestEndToEnd(t *testing.T) { +// suite.Run(t, new(EndToEndSuite)) +//} +// +//func (s *EndToEndSuite) SetupSuite() { +// s.client = &http.Client{} +//} +// +//func (s *EndToEndSuite) SetupTest() { +// // Set up before *each* test runs (e.g., reset mocks, clear databases) +//} +// +//func (s *EndToEndSuite) TearDownTest() { +// // Clean up after *each* test runs +//} +// +//func (s *EndToEndSuite) TestHealthCheck() { +// resp, _ := s.client.Get(BaseUrl + HealthEndpoint) +// defer resp.Body.Close() +// s.Equal(resp.StatusCode, http.StatusOK) +// body, _ := io.ReadAll(resp.Body) +// s.Equal("I am live!", string(body)) +//} +// +//func (s *EndToEndSuite) TestHealthIndex() { +// resp, _ := s.client.Get(BaseUrl + IndexEndpoint) +// defer resp.Body.Close() +// s.Equal(resp.StatusCode, http.StatusOK) +// body, _ := io.ReadAll(resp.Body) +// s.Equal("This is KloverCloud Lighthouse", string(body)) +//} diff --git a/pkg/k8s_test/namespace_test.go b/pkg/k8s_test/namespace_test.go index 268b57e..3ee5ecc 100644 --- a/pkg/k8s_test/namespace_test.go +++ b/pkg/k8s_test/namespace_test.go @@ -1,18 +1,16 @@ package k8s_test -// -//import ( -// "context" -// "github.com/krack8/lighthouse/pkg/controller/api" -// "github.com/krack8/lighthouse/pkg/k8s" -// "github.com/stretchr/testify/assert" -// "github.com/stretchr/testify/suite" -// v1 "k8s.io/api/core/v1" -// metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -// "k8s.io/client-go/kubernetes/fake" -// "testing" -//) -// +import ( + "context" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/fake" + "testing" +) + //type NamespaceTestSuite struct { // suite.Suite // clientSet *fake.Clientset @@ -33,69 +31,68 @@ package k8s_test //func (s *NamespaceTestSuite) TearDownTest() { // // Clean up after *each* test runs //} -// -//func (s *NamespaceTestSuite) TestGetNamespaceDetails(t *testing.T) { -// // Mock the Kubernetes client -// clientset := fake.NewSimpleClientset(&corev1.Namespace{ -// ObjectMeta: metav1.ObjectMeta{ -// Name: "test-namespace", -// }, -// }) -// cfg.kubeClientSet = clientset // Assign the fake clientset -// -// // Test case 1: Successful retrieval -// t.Run("Success", func(t *testing.T) { -// p := GetNamespaceInputParams{ -// NamespaceName: "test-namespace", -// } -// expectedNamespace := corev1.Namespace{ -// ObjectMeta: metav1.ObjectMeta{ -// Name: "test-namespace", -// }, -// } -// expectedNamespace = removeNamespaceFields(expectedNamespace) // Apply the function -// -// result, err := namespaceService{}.GetNamespaceDetails(context.Background(), p) -// assert.NoError(t, err) -// assert.NotNil(t, result) -// -// response, ok := result.(ResponseDTO) -// assert.True(t, ok) -// assert.Equal(t, "success", response.Status) -// assert.Equal(t, expectedNamespace, response.Data) -// -// }) -// -// // Test case 2: Namespace not found -// t.Run("NotFound", func(t *testing.T) { -// p := GetNamespaceInputParams{ -// NamespaceName: "non-existent-namespace", -// } -// -// result, err := namespaceService{}.GetNamespaceDetails(context.Background(), p) -// -// assert.Error(t, err) -// assert.Nil(t, result) -// -// }) -//} -// -// -//// A dummy removeNamespaceFields function for testing purposes -//func removeNamespaceFields(ns corev1.Namespace) corev1.Namespace{ -// return ns -//} -// -//type ResponseDTO struct { -// Status string `json:"status"` -// Data interface{} `json:"data"` -//} -//var cfg config -// -//type config struct { -// KubeClientSet *fake.Clientset -//} -// -//func (c *config) GetKubeClientSet() *fake.Clientset { -// return c.KubeClientSet -//} + +func TestGetNamespaceDetails(t *testing.T) { + log.InitializeLogger() + // Mock the Kubernetes client + clientset := fake.NewClientset(&corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-namespace", + }, + }) + + cfg.KubeClientSet = clientset // Assign the fake clientset + // Test case 1: Successful retrieval + t.Run("Success", func(t *testing.T) { + p := k8s.GetNamespaceInputParams{ + NamespaceName: "test-namespace", + Client: clientset.CoreV1().Namespaces(), + } + expectedNamespace := corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-namespace", + }, + } + expectedNamespace = removeNamespaceFields(expectedNamespace) // Apply the function + + result, err := k8s.NamespaceService().GetNamespaceDetails(context.Background(), p) + assert := assert.New(t) + assert.NoError(err) + assert.NotNil(result) + + response, ok := result.(k8s.ResponseDTO) + assert.True(ok) + assert.Equal("success", response.Status) + assert.Equal(expectedNamespace, response.Data) + + }) + + // Test case 2: Namespace not found + t.Run("Error", func(t *testing.T) { + p := k8s.GetNamespaceInputParams{ + NamespaceName: "non-existent-namespace", + Client: clientset.CoreV1().Namespaces(), + } + + result, err := k8s.NamespaceService().GetNamespaceDetails(context.Background(), p) + assert := assert.New(t) + assert.Error(err) + assert.Nil(result) + + }) +} + +// A dummy removeNamespaceFields function for testing purposes +func removeNamespaceFields(ns corev1.Namespace) corev1.Namespace { + return ns +} + +var cfg config + +type config struct { + KubeClientSet *fake.Clientset +} + +func (c *config) GetKubeClientSet() *fake.Clientset { + return c.KubeClientSet +} From 048eb4681f9d03b24a61f1f00b959a140d2f5d8a Mon Sep 17 00:00:00 2001 From: Toha Date: Mon, 10 Feb 2025 15:24:47 +0600 Subject: [PATCH 60/64] test namespace --- pkg/k8s/namespace.go | 28 +++- pkg/k8s_test/namespace_test.go | 261 ++++++++++++++++++++++++++------- pkg/log/logger.go | 12 ++ 3 files changed, 239 insertions(+), 62 deletions(-) diff --git a/pkg/k8s/namespace.go b/pkg/k8s/namespace.go index 9c168cc..f79d3bb 100644 --- a/pkg/k8s/namespace.go +++ b/pkg/k8s/namespace.go @@ -246,14 +246,21 @@ func (namespace *namespaceService) GetNamespaceDetails(c context.Context, p GetN type DeployNamespaceInputParams struct { Namespace *corev1.Namespace output *corev1.Namespace + Client v1.NamespaceInterface +} + +func (p *DeployNamespaceInputParams) GetClient() v1.NamespaceInterface { + if p.Client != nil { + return p.Client + } + return getNamespaceClient() } func (p *DeployNamespaceInputParams) Process(c context.Context) error { - namespaceClient := cfg.GetKubeClientSet().CoreV1().Namespaces() - _, err := namespaceClient.Get(context.Background(), p.Namespace.Name, metav1.GetOptions{}) + _, err := p.GetClient().Get(context.Background(), p.Namespace.Name, metav1.GetOptions{}) if err != nil { log.Logger.Infow("Creating namespace "+p.Namespace.Name, "value", p.Namespace.Name) - p.output, err = namespaceClient.Create(context.Background(), p.Namespace, metav1.CreateOptions{}) + p.output, err = p.GetClient().Create(context.Background(), p.Namespace, metav1.CreateOptions{}) if err != nil { log.Logger.Errorw("failed to create namespace "+p.Namespace.Name, "err", err.Error()) return err @@ -262,7 +269,7 @@ func (p *DeployNamespaceInputParams) Process(c context.Context) error { } else { log.Logger.Infow("Namespace exists "+p.Namespace.Name, "value", p.Namespace.Name) log.Logger.Infow("Updating namespace "+p.Namespace.Name, "value", p.Namespace.Name) - p.output, err = namespaceClient.Update(context.Background(), p.Namespace, metav1.UpdateOptions{}) + p.output, err = p.GetClient().Update(context.Background(), p.Namespace, metav1.UpdateOptions{}) if err != nil { log.Logger.Errorw("failed to update namespace ", p.Namespace.Name, "err", err.Error()) return err @@ -277,7 +284,7 @@ func (namespace *namespaceService) DeployNamespace(c context.Context, p DeployNa if err != nil { return nil, err } - + p.output.ManagedFields = nil return ResponseDTO{ Status: "success", Data: p.output, @@ -286,12 +293,19 @@ func (namespace *namespaceService) DeployNamespace(c context.Context, p DeployNa type DeleteNamespaceInputParams struct { NamespaceName string + Client v1.NamespaceInterface +} + +func (p *DeleteNamespaceInputParams) GetClient() v1.NamespaceInterface { + if p.Client != nil { + return p.Client + } + return getNamespaceClient() } func (p *DeleteNamespaceInputParams) Process(c context.Context) error { log.Logger.Debugw("Deleting Namespace ....", "value", p.NamespaceName) - namespaceClient := cfg.GetKubeClientSet().CoreV1().Namespaces() - err := namespaceClient.Delete(context.Background(), p.NamespaceName, metav1.DeleteOptions{}) + err := p.GetClient().Delete(context.Background(), p.NamespaceName, metav1.DeleteOptions{}) if err != nil { log.Logger.Errorw("Failed to delete namespace "+p.NamespaceName, "err", err.Error()) return err diff --git a/pkg/k8s_test/namespace_test.go b/pkg/k8s_test/namespace_test.go index 3ee5ecc..9b6953a 100644 --- a/pkg/k8s_test/namespace_test.go +++ b/pkg/k8s_test/namespace_test.go @@ -5,57 +5,184 @@ import ( "github.com/krack8/lighthouse/pkg/k8s" "github.com/krack8/lighthouse/pkg/log" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes/fake" + k8stesting "k8s.io/client-go/testing" "testing" ) -//type NamespaceTestSuite struct { -// suite.Suite -// clientSet *fake.Clientset -//} -// -//func TestNamespace(t *testing.T) { -// suite.Run(t, new(NamespaceTestSuite)) -//} -// -//func (s *NamespaceTestSuite) SetupNamespaceSuite() { -//} -// -//func (s *NamespaceTestSuite) SetupTest() { -// s.clientSet = fake.NewClientset() -// // Set up before *each* test runs (e.g., reset mocks, clear databases) -//} -// -//func (s *NamespaceTestSuite) TearDownTest() { -// // Clean up after *each* test runs -//} - -func TestGetNamespaceDetails(t *testing.T) { - log.InitializeLogger() - // Mock the Kubernetes client - clientset := fake.NewClientset(&corev1.Namespace{ +type NoopLogger struct{} + +func (l NoopLogger) Debugw(msg string, keysAndValues ...interface{}) {} +func (l NoopLogger) Errorw(msg string, keysAndValues ...interface{}) {} + +type NamespaceTestSuite struct { + suite.Suite + clientSet *fake.Clientset +} + +func TestNamespace(t *testing.T) { + suite.Run(t, new(NamespaceTestSuite)) +} + +func (s *NamespaceTestSuite) SetupSuite() { // Setup for the entire suite + log.InitializeTestLogger() + // Initialize Test logger once for the suite +} + +func (s *NamespaceTestSuite) TearDownSuite() { // Teardown for the entire suite + // Close resources, etc. if needed. +} + +func (s *NamespaceTestSuite) SetupTest() { + s.clientSet = fake.NewClientset(&corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-namespace", + }, + }) + // Setup before each test + // Reset mocks, clear databases, etc. if needed for *each* test +} + +func (s *NamespaceTestSuite) TearDownTest() { // Teardown after each test + // Clean up after *each* test runs +} + +func (s *NamespaceTestSuite) TestGetNamespaceDetailsSuccess() { + p := k8s.GetNamespaceInputParams{ + NamespaceName: "test-namespace", + Client: s.clientSet.CoreV1().Namespaces(), // Use the clientSet from SetupSuite + } + expectedNamespace := corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: "test-namespace", }, + } + expectedNamespace = removeNamespaceFields(expectedNamespace) + + result, err := k8s.NamespaceService().GetNamespaceDetails(context.Background(), p) + assert := assert.New(s.T()) + assert.NoError(err) + assert.NotNil(result) + + response, ok := result.(k8s.ResponseDTO) + assert.True(ok) + assert.Equal("success", response.Status) + assert.Equal(expectedNamespace, response.Data) +} + +func (s *NamespaceTestSuite) TestGetNamespaceDetailsError() { + p := k8s.GetNamespaceInputParams{ + NamespaceName: "non-existent-namespace", + Client: s.clientSet.CoreV1().Namespaces(), // Use the clientSet from SetupSuite + } + + result, err := k8s.NamespaceService().GetNamespaceDetails(context.Background(), p) + assert := assert.New(s.T()) + assert.Error(err) + assert.Nil(result) +} + +// A dummy removeNamespaceFields function for testing purposes +func removeNamespaceFields(ns corev1.Namespace) corev1.Namespace { + return ns +} + +func (s *NamespaceTestSuite) TestDeleteNamespaceSuccess() { + + p := k8s.DeleteNamespaceInputParams{ + NamespaceName: "test-namespace", + Client: s.clientSet.CoreV1().Namespaces(), + } + + result, err := k8s.NamespaceService().DeleteNamespace(context.Background(), p) + assert := assert.New(s.T()) + assert.NoError(err) + assert.NotNil(result) + + response, ok := result.(k8s.ResponseDTO) + assert.True(ok) + assert.Equal("success", response.Status) + assert.Equal("deleted namespace test-namespace", response.Msg) + + _, err = s.clientSet.CoreV1().Namespaces().Get(context.Background(), "test-namespace", metav1.GetOptions{}) + assert.Error(err) + + s.T().Run("Test Namespace Error", func(t *testing.T) { + t.Log("Test CASE: Delete Namespace with non-existent namespace") + p := k8s.DeleteNamespaceInputParams{ + NamespaceName: "non-existent-namespace", + Client: s.clientSet.CoreV1().Namespaces(), + } + + result, err := k8s.NamespaceService().DeleteNamespace(context.Background(), p) + assert.Error(err) + assert.Nil(result) }) +} + +func (s *NamespaceTestSuite) TestDeleteNamespaceError() { + p := k8s.DeleteNamespaceInputParams{ + NamespaceName: "non-existent-namespace", + Client: s.clientSet.CoreV1().Namespaces(), + } + + result, err := k8s.NamespaceService().DeleteNamespace(context.Background(), p) + + assert := assert.New(s.T()) + assert.Error(err) + assert.Nil(result) +} + +func (s *NamespaceTestSuite) TestDeployNamespace() { + s.T().Run("Success CreateNamespace", func(t *testing.T) { + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "new-namespace", + }, + TypeMeta: metav1.TypeMeta{ + Kind: "Namespace", + APIVersion: "v1", + }, + } - cfg.KubeClientSet = clientset // Assign the fake clientset - // Test case 1: Successful retrieval - t.Run("Success", func(t *testing.T) { - p := k8s.GetNamespaceInputParams{ - NamespaceName: "test-namespace", - Client: clientset.CoreV1().Namespaces(), + p := k8s.DeployNamespaceInputParams{ + Namespace: namespace, + Client: s.clientSet.CoreV1().Namespaces(), } - expectedNamespace := corev1.Namespace{ + + result, err := k8s.NamespaceService().DeployNamespace(context.Background(), p) + assert := assert.New(t) + assert.NoError(err) + assert.NotNil(result) + + response, ok := result.(k8s.ResponseDTO) + assert.True(ok) + assert.Equal("success", response.Status) + assert.Equal(namespace, response.Data) + // Verify namespace exists + fetchedNamespace, err := s.clientSet.CoreV1().Namespaces().Get(context.Background(), namespace.Name, metav1.GetOptions{}) + assert.NoError(err) + assert.Equal(namespace.Name, fetchedNamespace.Name) + }) + + s.T().Run("Success UpdateNamespace", func(t *testing.T) { + updatedLabels := map[string]string{"updated": "true"} + namespace := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-namespace", + Name: "test-namespace", + Labels: updatedLabels, }, } - expectedNamespace = removeNamespaceFields(expectedNamespace) // Apply the function - result, err := k8s.NamespaceService().GetNamespaceDetails(context.Background(), p) + p := k8s.DeployNamespaceInputParams{ + Namespace: namespace, + Client: s.clientSet.CoreV1().Namespaces(), + } + result, err := k8s.NamespaceService().DeployNamespace(context.Background(), p) assert := assert.New(t) assert.NoError(err) assert.NotNil(result) @@ -63,36 +190,60 @@ func TestGetNamespaceDetails(t *testing.T) { response, ok := result.(k8s.ResponseDTO) assert.True(ok) assert.Equal("success", response.Status) - assert.Equal(expectedNamespace, response.Data) + assert.Equal(namespace, response.Data) + // Verify namespace was updated + fetchedNamespace, err := s.clientSet.CoreV1().Namespaces().Get(context.Background(), "test-namespace", metav1.GetOptions{}) + assert.NoError(err) + assert.Equal(updatedLabels, fetchedNamespace.Labels) }) + s.T().Run("Error CreateNamespace - Create Fails", func(t *testing.T) { + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "new-namespace", + }, + } + clientSet := fake.NewClientset() + // Make the fake client return an error on create + clientSet.PrependReactor("create", "namespaces", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, assert.AnError // Return an error + }) - // Test case 2: Namespace not found - t.Run("Error", func(t *testing.T) { - p := k8s.GetNamespaceInputParams{ - NamespaceName: "non-existent-namespace", - Client: clientset.CoreV1().Namespaces(), + p := k8s.DeployNamespaceInputParams{ + Namespace: namespace, + Client: clientSet.CoreV1().Namespaces(), } - result, err := k8s.NamespaceService().GetNamespaceDetails(context.Background(), p) + result, err := k8s.NamespaceService().DeployNamespace(context.Background(), p) assert := assert.New(t) assert.Error(err) assert.Nil(result) - }) -} - -// A dummy removeNamespaceFields function for testing purposes -func removeNamespaceFields(ns corev1.Namespace) corev1.Namespace { - return ns -} + s.T().Run("Error UpdateNamespace - Update Fails", func(t *testing.T) { + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-namespace", + }, + } -var cfg config + clientSet := fake.NewClientset(&corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-namespace", + }, + }) + // Make the fake client return an error on update + clientSet.PrependReactor("update", "namespaces", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, assert.AnError // Return an error + }) -type config struct { - KubeClientSet *fake.Clientset -} + p := k8s.DeployNamespaceInputParams{ + Namespace: namespace, + Client: clientSet.CoreV1().Namespaces(), + } -func (c *config) GetKubeClientSet() *fake.Clientset { - return c.KubeClientSet + result, err := k8s.NamespaceService().DeployNamespace(context.Background(), p) + assert := assert.New(t) + assert.Error(err) + assert.Nil(result) + }) } diff --git a/pkg/log/logger.go b/pkg/log/logger.go index 5099347..14125fc 100644 --- a/pkg/log/logger.go +++ b/pkg/log/logger.go @@ -33,3 +33,15 @@ func InitializeLogger() { Logger = ZLogger.Sugar() defer Logger.Sync() } + +// this is for test +func InitializeTestLogger() { + config := zap.NewProductionEncoderConfig() + // Setting time encoder + config.EncodeTime = zapcore.ISO8601TimeEncoder + // Setting Log level should be printed in capital letters with level colors + config.EncodeLevel = zapcore.CapitalColorLevelEncoder + + Logger = zap.NewNop().Sugar() // zap.NewNop() creates a no-op logger + ZLogger = zap.NewNop() +} From 4100faefb6a91cd6f1551f56cae9ddcd755fce07 Mon Sep 17 00:00:00 2001 From: Toha Date: Mon, 10 Feb 2025 16:46:33 +0600 Subject: [PATCH 61/64] test namespace --- pkg/k8s_test/k8s_test.go | 16 ---------------- pkg/k8s_test/namespace_test.go | 5 ----- 2 files changed, 21 deletions(-) diff --git a/pkg/k8s_test/k8s_test.go b/pkg/k8s_test/k8s_test.go index af19798..15fa767 100644 --- a/pkg/k8s_test/k8s_test.go +++ b/pkg/k8s_test/k8s_test.go @@ -1,21 +1,5 @@ package k8s_test -// -//import ( -// "context" -// _cfg "github.com/krack8/lighthouse/pkg/config" -// "github.com/krack8/lighthouse/pkg/k8s" -// "github.com/stretchr/testify/suite" -// "io" -// v1 "k8s.io/api/core/v1" -// metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -// "k8s.io/client-go/kubernetes/fake" -// "net/http" -// "testing" -//) -// -//var IsTesting = false -// //func TestListNamespaces(t *testing.T) { // // Mock the Kubernetes client using a fake client // clientset := fake.NewClientset() diff --git a/pkg/k8s_test/namespace_test.go b/pkg/k8s_test/namespace_test.go index 9b6953a..822a325 100644 --- a/pkg/k8s_test/namespace_test.go +++ b/pkg/k8s_test/namespace_test.go @@ -14,11 +14,6 @@ import ( "testing" ) -type NoopLogger struct{} - -func (l NoopLogger) Debugw(msg string, keysAndValues ...interface{}) {} -func (l NoopLogger) Errorw(msg string, keysAndValues ...interface{}) {} - type NamespaceTestSuite struct { suite.Suite clientSet *fake.Clientset From dac2ef5a6255b78500939fbf186058e49c3dfad7 Mon Sep 17 00:00:00 2001 From: Toha Date: Mon, 10 Feb 2025 17:28:38 +0600 Subject: [PATCH 62/64] namespace and configmap --- pkg/k8s_test/configmap_test.go | 239 +++++++++++++++++++++++++++++++++ pkg/k8s_test/namespace_test.go | 117 ++++++++-------- 2 files changed, 296 insertions(+), 60 deletions(-) create mode 100644 pkg/k8s_test/configmap_test.go diff --git a/pkg/k8s_test/configmap_test.go b/pkg/k8s_test/configmap_test.go new file mode 100644 index 0000000..e563703 --- /dev/null +++ b/pkg/k8s_test/configmap_test.go @@ -0,0 +1,239 @@ +package k8s + +//import ( +// "github.com/krack8/lighthouse/pkg/log" +// "github.com/stretchr/testify/suite" +// corev1 "k8s.io/api/core/v1" +// metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +// "k8s.io/client-go/kubernetes/fake" +// "testing" +//) +// +//type ConfigMapTestSuite struct { +// suite.Suite +// clientSet *fake.Clientset +//} +// +//func TestConfigMap(t *testing.T) { +// suite.Run(t, new(ConfigMapTestSuite)) +//} +// +//func (s *ConfigMapTestSuite) SetupSuite() { // Setup for the entire suite +// log.InitializeTestLogger() +// // Initialize Test logger once for the suite +//} +// +//func (s *ConfigMapTestSuite) TearDownSuite() { // Teardown for the entire suite +// // Close resources, etc. if needed. +//} +// +//func (s *ConfigMapTestSuite) SetupTest() { +// s.clientSet = fake.NewClientset(&corev1.ConfigMap{ +// ObjectMeta: metav1.ObjectMeta{ +// Name: "test-namespace", +// }, +// }) +// // Setup before each test +// // Reset mocks, clear databases, etc. if needed for *each* test +//} +// +//func (s *ConfigMapTestSuite) TearDownTest() { // Teardown after each test +// // Clean up after *each* test runs +//} +// +//func (s *ConfigMapTestSuite) TestGetConfigMapDetailsSuccess() { +// p := k8s.GetConfigMapDetailsInputParams{ +// ConfigMapName: "test-namespace", +// Client: s.clientSet.CoreV1().ConfigMaps(), // Use the clientSet from SetupSuite +// } +// expectedConfigMap := corev1.ConfigMap{ +// ObjectMeta: metav1.ObjectMeta{ +// Name: "test-namespace", +// }, +// } +// expectedConfigMap = removeConfigMapFields(expectedConfigMap) +// +// result, err := k8s.ConfigMapService().GetConfigMapDetails(context.Background(), p) +// assert := assert.New(s.T()) +// assert.NoError(err) +// assert.NotNil(result) +// +// response, ok := result.(k8s.ResponseDTO) +// assert.True(ok) +// assert.Equal("success", response.Status) +// assert.Equal(expectedConfigMap, response.Data) +//} +// +//func (s *ConfigMapTestSuite) TestGetConfigMapDetailsError() { +// p := k8s.GetConfigMapInputParams{ +// ConfigMapName: "non-existent-namespace", +// Client: s.clientSet.CoreV1().ConfigMaps(), // Use the clientSet from SetupSuite +// } +// +// result, err := k8s.ConfigMapService().GetConfigMapDetails(context.Background(), p) +// assert := assert.New(s.T()) +// assert.Error(err) +// assert.Nil(result) +//} +// +//// A dummy removeConfigMapFields function for testing purposes +//func removeConfigMapFields(ns corev1.ConfigMap) corev1.ConfigMap { +// return ns +//} +// +//func (s *ConfigMapTestSuite) TestDeleteConfigMapSuccess() { +// +// p := k8s.DeleteConfigMapInputParams{ +// ConfigMapName: "test-namespace", +// Client: s.clientSet.CoreV1().ConfigMaps(), +// } +// +// result, err := k8s.ConfigMapService().DeleteConfigMap(context.Background(), p) +// assert := assert.New(s.T()) +// assert.NoError(err) +// assert.NotNil(result) +// +// response, ok := result.(k8s.ResponseDTO) +// assert.True(ok) +// assert.Equal("success", response.Status) +// assert.Equal("deleted namespace test-namespace", response.Msg) +// +// _, err = s.clientSet.CoreV1().ConfigMaps().Get(context.Background(), "test-namespace", metav1.GetOptions{}) +// assert.Error(err) +// +// s.T().Run("Test ConfigMap Error", func(t *testing.T) { +// t.Log("Test CASE: Delete ConfigMap with non-existent namespace") +// p := k8s.DeleteConfigMapInputParams{ +// ConfigMapName: "non-existent-namespace", +// Client: s.clientSet.CoreV1().ConfigMaps(), +// } +// +// result, err := k8s.ConfigMapService().DeleteConfigMap(context.Background(), p) +// assert.Error(err) +// assert.Nil(result) +// }) +//} +// +//func (s *ConfigMapTestSuite) TestDeleteConfigMapError() { +// p := k8s.DeleteConfigMapInputParams{ +// ConfigMapName: "non-existent-namespace", +// Client: s.clientSet.CoreV1().ConfigMaps(), +// } +// +// result, err := k8s.ConfigMapService().DeleteConfigMap(context.Background(), p) +// +// assert := assert.New(s.T()) +// assert.Error(err) +// assert.Nil(result) +//} +// +//func (s *ConfigMapTestSuite) TestDeployConfigMap() { +// s.T().Run("Success CreateConfigMap", func(t *testing.T) { +// namespace := &corev1.ConfigMap{ +// ObjectMeta: metav1.ObjectMeta{ +// Name: "new-namespace", +// }, +// TypeMeta: metav1.TypeMeta{ +// Kind: "ConfigMap", +// APIVersion: "v1", +// }, +// } +// +// p := k8s.DeployConfigMapInputParams{ +// ConfigMap: namespace, +// Client: s.clientSet.CoreV1().ConfigMaps(), +// } +// +// result, err := k8s.ConfigMapService().DeployConfigMap(context.Background(), p) +// assert := assert.New(t) +// assert.NoError(err) +// assert.NotNil(result) +// +// response, ok := result.(k8s.ResponseDTO) +// assert.True(ok) +// assert.Equal("success", response.Status) +// assert.Equal(namespace, response.Data) +// // Verify namespace exists +// fetchedConfigMap, err := s.clientSet.CoreV1().ConfigMaps().Get(context.Background(), namespace.Name, metav1.GetOptions{}) +// assert.NoError(err) +// assert.Equal(namespace.Name, fetchedConfigMap.Name) +// }) +// +// s.T().Run("Success UpdateConfigMap", func(t *testing.T) { +// updatedLabels := map[string]string{"updated": "true"} +// namespace := &corev1.ConfigMap{ +// ObjectMeta: metav1.ObjectMeta{ +// Name: "test-namespace", +// Labels: updatedLabels, +// }, +// } +// +// p := k8s.DeployConfigMapInputParams{ +// ConfigMap: namespace, +// Client: s.clientSet.CoreV1().ConfigMaps(), +// } +// result, err := k8s.ConfigMapService().DeployConfigMap(context.Background(), p) +// assert := assert.New(t) +// assert.NoError(err) +// assert.NotNil(result) +// +// response, ok := result.(k8s.ResponseDTO) +// assert.True(ok) +// assert.Equal("success", response.Status) +// assert.Equal(namespace, response.Data) +// +// // Verify namespace was updated +// fetchedConfigMap, err := s.clientSet.CoreV1().ConfigMaps().Get(context.Background(), "test-namespace", metav1.GetOptions{}) +// assert.NoError(err) +// assert.Equal(updatedLabels, fetchedConfigMap.Labels) +// }) +// s.T().Run("Error CreateConfigMap - Create Fails", func(t *testing.T) { +// namespace := &corev1.ConfigMap{ +// ObjectMeta: metav1.ObjectMeta{ +// Name: "new-namespace", +// }, +// } +// clientSet := fake.NewClientset() +// // Make the fake client return an error on create +// clientSet.PrependReactor("create", "namespaces", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { +// return true, nil, assert.AnError // Return an error +// }) +// +// p := k8s.DeployConfigMapInputParams{ +// ConfigMap: namespace, +// Client: clientSet.CoreV1().ConfigMaps(), +// } +// +// result, err := k8s.ConfigMapService().DeployConfigMap(context.Background(), p) +// assert := assert.New(t) +// assert.Error(err) +// assert.Nil(result) +// }) +// s.T().Run("Error UpdateConfigMap - Update Fails", func(t *testing.T) { +// namespace := &corev1.ConfigMap{ +// ObjectMeta: metav1.ObjectMeta{ +// Name: "test-namespace", +// }, +// } +// +// clientSet := fake.NewClientset(&corev1.ConfigMap{ +// ObjectMeta: metav1.ObjectMeta{ +// Name: "test-namespace", +// }, +// }) +// // Make the fake client return an error on update +// clientSet.PrependReactor("update", "namespaces", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { +// return true, nil, assert.AnError // Return an error +// }) +// +// p := k8s.DeployConfigMapInputParams{ +// ConfigMap: namespace, +// Client: clientSet.CoreV1().ConfigMaps(), +// } +// +// result, err := k8s.ConfigMapService().DeployConfigMap(context.Background(), p) +// assert := assert.New(t) +// assert.Error(err) +// assert.Nil(result) +// }) +//} diff --git a/pkg/k8s_test/namespace_test.go b/pkg/k8s_test/namespace_test.go index 822a325..e574d1a 100644 --- a/pkg/k8s_test/namespace_test.go +++ b/pkg/k8s_test/namespace_test.go @@ -46,39 +46,42 @@ func (s *NamespaceTestSuite) TearDownTest() { // Teardown after each test // Clean up after *each* test runs } -func (s *NamespaceTestSuite) TestGetNamespaceDetailsSuccess() { - p := k8s.GetNamespaceInputParams{ - NamespaceName: "test-namespace", - Client: s.clientSet.CoreV1().Namespaces(), // Use the clientSet from SetupSuite - } - expectedNamespace := corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-namespace", - }, - } - expectedNamespace = removeNamespaceFields(expectedNamespace) - - result, err := k8s.NamespaceService().GetNamespaceDetails(context.Background(), p) - assert := assert.New(s.T()) - assert.NoError(err) - assert.NotNil(result) - - response, ok := result.(k8s.ResponseDTO) - assert.True(ok) - assert.Equal("success", response.Status) - assert.Equal(expectedNamespace, response.Data) -} +func (s *NamespaceTestSuite) TestGetNamespaceDetails() { + s.T().Run("Success GetNamespaceDetails", func(t *testing.T) { + t.Log("Test CASE: Get Namespace with existing namespace") + p := k8s.GetNamespaceInputParams{ + NamespaceName: "test-namespace", + Client: s.clientSet.CoreV1().Namespaces(), // Use the clientSet from SetupSuite + } + expectedNamespace := corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-namespace", + }, + } + expectedNamespace = removeNamespaceFields(expectedNamespace) -func (s *NamespaceTestSuite) TestGetNamespaceDetailsError() { - p := k8s.GetNamespaceInputParams{ - NamespaceName: "non-existent-namespace", - Client: s.clientSet.CoreV1().Namespaces(), // Use the clientSet from SetupSuite - } + result, err := k8s.NamespaceService().GetNamespaceDetails(context.Background(), p) + assert := assert.New(s.T()) + assert.NoError(err) + assert.NotNil(result) - result, err := k8s.NamespaceService().GetNamespaceDetails(context.Background(), p) - assert := assert.New(s.T()) - assert.Error(err) - assert.Nil(result) + response, ok := result.(k8s.ResponseDTO) + assert.True(ok) + assert.Equal("success", response.Status) + assert.Equal(expectedNamespace, response.Data) + }) + s.T().Run("Error GetNamespaceDetails", func(t *testing.T) { + t.Log("Test CASE: Get Namespace with non-existent namespace") + p := k8s.GetNamespaceInputParams{ + NamespaceName: "non-existent-namespace", + Client: s.clientSet.CoreV1().Namespaces(), // Use the clientSet from SetupSuite + } + + result, err := k8s.NamespaceService().GetNamespaceDetails(context.Background(), p) + assert := assert.New(s.T()) + assert.Error(err) + assert.Nil(result) + }) } // A dummy removeNamespaceFields function for testing purposes @@ -87,26 +90,28 @@ func removeNamespaceFields(ns corev1.Namespace) corev1.Namespace { } func (s *NamespaceTestSuite) TestDeleteNamespaceSuccess() { + s.T().Run("Success DeleteNamespace", func(t *testing.T) { + t.Log("Test CASE: Delete Namespace with existing namespace") + p := k8s.DeleteNamespaceInputParams{ + NamespaceName: "test-namespace", + Client: s.clientSet.CoreV1().Namespaces(), + } - p := k8s.DeleteNamespaceInputParams{ - NamespaceName: "test-namespace", - Client: s.clientSet.CoreV1().Namespaces(), - } - - result, err := k8s.NamespaceService().DeleteNamespace(context.Background(), p) - assert := assert.New(s.T()) - assert.NoError(err) - assert.NotNil(result) + result, err := k8s.NamespaceService().DeleteNamespace(context.Background(), p) + assert := assert.New(s.T()) + assert.NoError(err) + assert.NotNil(result) - response, ok := result.(k8s.ResponseDTO) - assert.True(ok) - assert.Equal("success", response.Status) - assert.Equal("deleted namespace test-namespace", response.Msg) + response, ok := result.(k8s.ResponseDTO) + assert.True(ok) + assert.Equal("success", response.Status) + assert.Equal("deleted namespace test-namespace", response.Msg) - _, err = s.clientSet.CoreV1().Namespaces().Get(context.Background(), "test-namespace", metav1.GetOptions{}) - assert.Error(err) + _, err = s.clientSet.CoreV1().Namespaces().Get(context.Background(), "test-namespace", metav1.GetOptions{}) + assert.Error(err) + }) - s.T().Run("Test Namespace Error", func(t *testing.T) { + s.T().Run("Error DeleteNamespace", func(t *testing.T) { t.Log("Test CASE: Delete Namespace with non-existent namespace") p := k8s.DeleteNamespaceInputParams{ NamespaceName: "non-existent-namespace", @@ -114,26 +119,15 @@ func (s *NamespaceTestSuite) TestDeleteNamespaceSuccess() { } result, err := k8s.NamespaceService().DeleteNamespace(context.Background(), p) + assert := assert.New(s.T()) assert.Error(err) assert.Nil(result) }) } -func (s *NamespaceTestSuite) TestDeleteNamespaceError() { - p := k8s.DeleteNamespaceInputParams{ - NamespaceName: "non-existent-namespace", - Client: s.clientSet.CoreV1().Namespaces(), - } - - result, err := k8s.NamespaceService().DeleteNamespace(context.Background(), p) - - assert := assert.New(s.T()) - assert.Error(err) - assert.Nil(result) -} - func (s *NamespaceTestSuite) TestDeployNamespace() { s.T().Run("Success CreateNamespace", func(t *testing.T) { + t.Log("Test CASE: Create Namespace with new namespace") namespace := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: "new-namespace", @@ -165,6 +159,7 @@ func (s *NamespaceTestSuite) TestDeployNamespace() { }) s.T().Run("Success UpdateNamespace", func(t *testing.T) { + t.Log("Test CASE: Update Namespace with existing namespace") updatedLabels := map[string]string{"updated": "true"} namespace := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -193,6 +188,7 @@ func (s *NamespaceTestSuite) TestDeployNamespace() { assert.Equal(updatedLabels, fetchedNamespace.Labels) }) s.T().Run("Error CreateNamespace - Create Fails", func(t *testing.T) { + t.Log("Test CASE: Create Namespace with new namespace fail") namespace := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: "new-namespace", @@ -215,6 +211,7 @@ func (s *NamespaceTestSuite) TestDeployNamespace() { assert.Nil(result) }) s.T().Run("Error UpdateNamespace - Update Fails", func(t *testing.T) { + t.Log("Test CASE: Update Namespace with existing namespace fail") namespace := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: "test-namespace", From 5515fd92b066239555cccb037894ddfaa2cc393e Mon Sep 17 00:00:00 2001 From: Toha Date: Mon, 10 Feb 2025 17:44:45 +0600 Subject: [PATCH 63/64] configmap test --- pkg/k8s/configmap.go | 14 ++- pkg/k8s_test/configmap_test.go | 221 +++++++++++++++++---------------- 2 files changed, 124 insertions(+), 111 deletions(-) diff --git a/pkg/k8s/configmap.go b/pkg/k8s/configmap.go index d9c5aa3..0c633e3 100644 --- a/pkg/k8s/configmap.go +++ b/pkg/k8s/configmap.go @@ -27,6 +27,10 @@ func ConfigMapService() *configMapService { return &cms } +func getConfigMapClient(namespace string) v1.ConfigMapInterface { + return cfg.GetKubeClientSet().CoreV1().ConfigMaps(namespace) +} + type OutputConfigMapList struct { Result []corev1.ConfigMap Resource string @@ -164,12 +168,18 @@ type GetConfigMapDetailsInputParams struct { NamespaceName string ConfigMapName string output corev1.ConfigMap + Client v1.ConfigMapInterface } +func (p *GetConfigMapDetailsInputParams) GetClient() v1.ConfigMapInterface { + if p.Client != nil { + return p.Client + } + return getConfigMapClient(p.NamespaceName) +} func (p *GetConfigMapDetailsInputParams) Process(c context.Context) error { log.Logger.Debugw("fetching configMap details of ....", p.NamespaceName) - configMapClient := cfg.GetKubeClientSet().CoreV1().ConfigMaps(p.NamespaceName) - output, err := configMapClient.Get(context.Background(), p.ConfigMapName, metav1.GetOptions{}) + output, err := p.GetClient().Get(context.Background(), p.ConfigMapName, metav1.GetOptions{}) if err != nil { log.Logger.Errorw("Failed to get configMap ", p.ConfigMapName, "err", err.Error()) return err diff --git a/pkg/k8s_test/configmap_test.go b/pkg/k8s_test/configmap_test.go index e563703..be0d24a 100644 --- a/pkg/k8s_test/configmap_test.go +++ b/pkg/k8s_test/configmap_test.go @@ -1,107 +1,118 @@ package k8s -//import ( -// "github.com/krack8/lighthouse/pkg/log" -// "github.com/stretchr/testify/suite" -// corev1 "k8s.io/api/core/v1" -// metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -// "k8s.io/client-go/kubernetes/fake" -// "testing" -//) -// -//type ConfigMapTestSuite struct { -// suite.Suite -// clientSet *fake.Clientset -//} -// -//func TestConfigMap(t *testing.T) { -// suite.Run(t, new(ConfigMapTestSuite)) -//} -// -//func (s *ConfigMapTestSuite) SetupSuite() { // Setup for the entire suite -// log.InitializeTestLogger() -// // Initialize Test logger once for the suite -//} -// -//func (s *ConfigMapTestSuite) TearDownSuite() { // Teardown for the entire suite -// // Close resources, etc. if needed. -//} -// -//func (s *ConfigMapTestSuite) SetupTest() { -// s.clientSet = fake.NewClientset(&corev1.ConfigMap{ -// ObjectMeta: metav1.ObjectMeta{ -// Name: "test-namespace", -// }, -// }) -// // Setup before each test -// // Reset mocks, clear databases, etc. if needed for *each* test -//} -// -//func (s *ConfigMapTestSuite) TearDownTest() { // Teardown after each test -// // Clean up after *each* test runs -//} -// -//func (s *ConfigMapTestSuite) TestGetConfigMapDetailsSuccess() { -// p := k8s.GetConfigMapDetailsInputParams{ -// ConfigMapName: "test-namespace", -// Client: s.clientSet.CoreV1().ConfigMaps(), // Use the clientSet from SetupSuite -// } -// expectedConfigMap := corev1.ConfigMap{ -// ObjectMeta: metav1.ObjectMeta{ -// Name: "test-namespace", -// }, -// } -// expectedConfigMap = removeConfigMapFields(expectedConfigMap) -// -// result, err := k8s.ConfigMapService().GetConfigMapDetails(context.Background(), p) -// assert := assert.New(s.T()) -// assert.NoError(err) -// assert.NotNil(result) -// -// response, ok := result.(k8s.ResponseDTO) -// assert.True(ok) -// assert.Equal("success", response.Status) -// assert.Equal(expectedConfigMap, response.Data) -//} -// -//func (s *ConfigMapTestSuite) TestGetConfigMapDetailsError() { -// p := k8s.GetConfigMapInputParams{ -// ConfigMapName: "non-existent-namespace", -// Client: s.clientSet.CoreV1().ConfigMaps(), // Use the clientSet from SetupSuite -// } -// -// result, err := k8s.ConfigMapService().GetConfigMapDetails(context.Background(), p) -// assert := assert.New(s.T()) -// assert.Error(err) -// assert.Nil(result) -//} -// -//// A dummy removeConfigMapFields function for testing purposes -//func removeConfigMapFields(ns corev1.ConfigMap) corev1.ConfigMap { -// return ns -//} +import ( + "context" + "github.com/krack8/lighthouse/pkg/k8s" + "github.com/krack8/lighthouse/pkg/log" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/fake" + "testing" +) + +type ConfigMapTestSuite struct { + suite.Suite + clientSet *fake.Clientset + configMap *corev1.ConfigMap +} + +func TestConfigMap(t *testing.T) { + suite.Run(t, new(ConfigMapTestSuite)) +} + +func (s *ConfigMapTestSuite) SetupSuite() { // Setup for the entire suite + log.InitializeTestLogger() + // Initialize Test logger once for the suite +} + +func (s *ConfigMapTestSuite) TearDownSuite() { // Teardown for the entire suite + // Close resources, etc. if needed. +} + +func (s *ConfigMapTestSuite) SetupTest() { + s.configMap = &corev1.ConfigMap{} + s.configMap.Name = "test-configmap" + s.configMap.Namespace = "test-namespace" + s.clientSet = fake.NewClientset(s.configMap) + // Setup before each test + // Reset mocks, clear databases, etc. if needed for *each* test +} + +func (s *ConfigMapTestSuite) TearDownTest() { // Teardown after each test + // Clean up after *each* test runs +} + +func (s *ConfigMapTestSuite) TestGetConfigMapDetails() { + s.T().Run("Success GetConfigMapDetails", func(t *testing.T) { + t.Log("Test CASE: Get existing ConfigMap with existing namespace") + p := k8s.GetConfigMapDetailsInputParams{ + ConfigMapName: s.configMap.Name, + NamespaceName: s.configMap.Namespace, + Client: s.clientSet.CoreV1().ConfigMaps(s.configMap.Namespace), // Use the clientSet from SetupSuite + } + expectedConfigMap := corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: s.configMap.Name, + Namespace: s.configMap.Namespace, + }, + } + expectedConfigMap = removeConfigMapFields(expectedConfigMap) + + result, err := k8s.ConfigMapService().GetConfigMapDetails(context.Background(), p) + assert := assert.New(s.T()) + assert.NoError(err) + assert.NotNil(result) + + response, ok := result.(k8s.ResponseDTO) + assert.True(ok) + assert.Equal("success", response.Status) + assert.Equal(expectedConfigMap, response.Data) + }) + s.T().Run("Error GetConfigMapDetails", func(t *testing.T) { + t.Log("Test CASE: Get ConfigMap with non-existent namespace") + p := k8s.GetConfigMapDetailsInputParams{ + ConfigMapName: "non-existent-namespace", + Client: s.clientSet.CoreV1().ConfigMaps(s.configMap.Namespace), // Use the clientSet from SetupSuite + } + + result, err := k8s.ConfigMapService().GetConfigMapDetails(context.Background(), p) + assert := assert.New(s.T()) + assert.Error(err) + assert.Nil(result) + }) +} + +// A dummy removeConfigMapFields function for testing purposes +func removeConfigMapFields(ns corev1.ConfigMap) corev1.ConfigMap { + return ns +} + // //func (s *ConfigMapTestSuite) TestDeleteConfigMapSuccess() { +// s.T().Run("Success DeleteConfigMap", func(t *testing.T) { +// t.Log("Test CASE: Delete ConfigMap with existing namespace") +// p := k8s.DeleteConfigMapInputParams{ +// ConfigMapName: "test-namespace", +// Client: s.clientSet.CoreV1().ConfigMaps(), +// } // -// p := k8s.DeleteConfigMapInputParams{ -// ConfigMapName: "test-namespace", -// Client: s.clientSet.CoreV1().ConfigMaps(), -// } -// -// result, err := k8s.ConfigMapService().DeleteConfigMap(context.Background(), p) -// assert := assert.New(s.T()) -// assert.NoError(err) -// assert.NotNil(result) +// result, err := k8s.ConfigMapService().DeleteConfigMap(context.Background(), p) +// assert := assert.New(s.T()) +// assert.NoError(err) +// assert.NotNil(result) // -// response, ok := result.(k8s.ResponseDTO) -// assert.True(ok) -// assert.Equal("success", response.Status) -// assert.Equal("deleted namespace test-namespace", response.Msg) +// response, ok := result.(k8s.ResponseDTO) +// assert.True(ok) +// assert.Equal("success", response.Status) +// assert.Equal("deleted namespace test-namespace", response.Msg) // -// _, err = s.clientSet.CoreV1().ConfigMaps().Get(context.Background(), "test-namespace", metav1.GetOptions{}) -// assert.Error(err) +// _, err = s.clientSet.CoreV1().ConfigMaps().Get(context.Background(), "test-namespace", metav1.GetOptions{}) +// assert.Error(err) +// }) // -// s.T().Run("Test ConfigMap Error", func(t *testing.T) { +// s.T().Run("Error DeleteConfigMap", func(t *testing.T) { // t.Log("Test CASE: Delete ConfigMap with non-existent namespace") // p := k8s.DeleteConfigMapInputParams{ // ConfigMapName: "non-existent-namespace", @@ -109,26 +120,15 @@ package k8s // } // // result, err := k8s.ConfigMapService().DeleteConfigMap(context.Background(), p) +// assert := assert.New(s.T()) // assert.Error(err) // assert.Nil(result) // }) //} // -//func (s *ConfigMapTestSuite) TestDeleteConfigMapError() { -// p := k8s.DeleteConfigMapInputParams{ -// ConfigMapName: "non-existent-namespace", -// Client: s.clientSet.CoreV1().ConfigMaps(), -// } -// -// result, err := k8s.ConfigMapService().DeleteConfigMap(context.Background(), p) -// -// assert := assert.New(s.T()) -// assert.Error(err) -// assert.Nil(result) -//} -// //func (s *ConfigMapTestSuite) TestDeployConfigMap() { // s.T().Run("Success CreateConfigMap", func(t *testing.T) { +// t.Log("Test CASE: Create ConfigMap with new namespace") // namespace := &corev1.ConfigMap{ // ObjectMeta: metav1.ObjectMeta{ // Name: "new-namespace", @@ -160,6 +160,7 @@ package k8s // }) // // s.T().Run("Success UpdateConfigMap", func(t *testing.T) { +// t.Log("Test CASE: Update ConfigMap with existing namespace") // updatedLabels := map[string]string{"updated": "true"} // namespace := &corev1.ConfigMap{ // ObjectMeta: metav1.ObjectMeta{ @@ -188,6 +189,7 @@ package k8s // assert.Equal(updatedLabels, fetchedConfigMap.Labels) // }) // s.T().Run("Error CreateConfigMap - Create Fails", func(t *testing.T) { +// t.Log("Test CASE: Create ConfigMap with new namespace fail") // namespace := &corev1.ConfigMap{ // ObjectMeta: metav1.ObjectMeta{ // Name: "new-namespace", @@ -210,6 +212,7 @@ package k8s // assert.Nil(result) // }) // s.T().Run("Error UpdateConfigMap - Update Fails", func(t *testing.T) { +// t.Log("Test CASE: Update ConfigMap with existing namespace fail") // namespace := &corev1.ConfigMap{ // ObjectMeta: metav1.ObjectMeta{ // Name: "test-namespace", From 727a7034ecaa07052c9f47d3ead794463ad6b9ce Mon Sep 17 00:00:00 2001 From: Toha Date: Tue, 11 Feb 2025 11:58:19 +0600 Subject: [PATCH 64/64] configmap test --- pkg/k8s/configmap.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/k8s/configmap.go b/pkg/k8s/configmap.go index 0c633e3..01a2166 100644 --- a/pkg/k8s/configmap.go +++ b/pkg/k8s/configmap.go @@ -177,6 +177,7 @@ func (p *GetConfigMapDetailsInputParams) GetClient() v1.ConfigMapInterface { } return getConfigMapClient(p.NamespaceName) } + func (p *GetConfigMapDetailsInputParams) Process(c context.Context) error { log.Logger.Debugw("fetching configMap details of ....", p.NamespaceName) output, err := p.GetClient().Get(context.Background(), p.ConfigMapName, metav1.GetOptions{})

    jkPynaTuZ`ea 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�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%0DPr~I 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∋{?lD>(YWdmW; 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 z zUK$fNk4~-<)!id{^6F9q9f@}XQCGA3i`bv-%TdE3X)J>$!(&lVUs2)ff|7b79RW?jfb3w{c%WJ5iqgpFafD6 z0YIi3gs{{D&uiLOhh^L52Uo_hrr1e{FYEzAh0EAw{bdiJUib*NDudJJm;htGVS6&( zSw$1A6d&1*%YPM*Cd4)^)mAGOmj8yrV~kYm(`+#mo1g^g(wnhop_8}4E72SHvl))p& zXtV9U(6`paK`wiO1jw8$J}{1_&Go#>tFIrc7-NR#ypC2iHtKwQA1kdj=gJ>?LUNZK zuaLd5E=~huT^F}1zpROo)LTCQD#-Cp=;@4YD`l5o|Mib5IO1)4UD#libRcIu_;yh4 z{66V;TulONJrnWq(jd0E+3kO0Sxac@;fCAzuYgD05f~o~-+(A17nh_~9T9?c=K{NJ zdvM~KHuHl1G<))WkP&Z?c%bDe0^D|x-+O@SY5|dd*2A^IqrDE{0tqfe^;hIePBEf}ElXzvOFyc_$cWp1OiTxuy zfOcAgrl+X}O4Iuvrb#n|PtGXknVApuqx3J|Iv?~jx%g+dI&Wu$qz=f9s}9sgZL-Hr z2^sAOV;+Gs9oRLyNkyQavj*PUEfXHwf1W_{19OiGm489i+5Y(KG{|FoVUS=>XotQA z`LR2_KAZEQ7ZaJTqj6VHSBkur$ij%!e~K~IRe~i&Nv?|UAr6i(KG7hY1S8K=Q3Ixd zJ4{&Yz?CU}7S6QYa-z%WAr#mBU@W~oAPOEf_lLsz04lJk)6u#IZ3t*QekqqD3s@XL z5-*$K149SUd4`A8=^}VYn1Sacu}e^rAIxt8a)|QIexl)28G$cRECQgjBb)G5Tf{$l zh|28oIx+kRlRtW}K)&@>JVUP*)n|L_%FyISNv?a3xSlmJ0-5LYXf8T!&-2Zg8 zTK^72WAX-n#B!(GcQ^$k;Ao|^XR0{%@A*nY8YKcH;Q~U{occb=eJT$)=kI!wEdeOzI zn2)rHNk{Oz3z`IrVX`s$^)YaL0zGR~>iN^pRrXDIcu1=E#6H)o--1J?xO1OMz8Iut zT~a9?&T=~0uZO`ZK1RXqHc4TI@Jv=3xVvVlFWEl};PJPi3$5XK@}xe*u~U5lj2N;E z9|5-{{(*hKy|W|q7hgryS5dnP-OpQ@%F{y0aygg$ZI3Wi(CP2xf|D%wzxQlit#9{| z@{;lNH8PXJg$6gM9wRfDlLWfn6yVkR78m3EGiFUfnv7Ro$D?KoZ{z~A54W8I)M9=@ zFzY7>1o2Hj&1ET&p+x|_^vji+7nZi24x#>E;FMQ$M|obkh1c0!)rf0>@zV3o#d`RC zyBgdd0sKRi?y;2g%{RK1357puHO*}20{us%KL#f*L}pKj?}0dK^+!>_Nm*a5u(KX8 zZGFFzMB6s}a~Eg^#>V#u0jEfwHnkUrrR^?E9)~gm{{UvdB!WN5Ny}h8)<{($5e|zj zLEUY8M~C8djQn|7`^mrn?Y$7V#UyxZMJ#jQHu51wS>FwuI#M0qB@!^}%l5k4NruXE zuWSyC`3{lj)cLGBGKNd1IDuz!yGeRT@16W^HNpDBd&jG%bE)K@HnE^ewL)m~?JYtj zQ0aeNCSz>?--p~Q+~5c7$}}3+9?iPyn}m{*%G}8J-W_ zs(@&1TaE*o$LV#)i^|wV#6+eLka+8TaRE+sPxz;7e*C!VxYq{K@c=25 z9YpF~_Ich9f@lts)E}E)e(tC|9CvqX|0fHX0USH8p=~~h!ZEYm+(ElZCMWiy-fO$@ z%e41&M}d@#Z)6*n+ylY12_|w0cb47s2YRLU~GO%|GNZh~+cN;mC z@OxjXtvJTj<0L6{2|o2Bvyx4Aom^zToqg@lmB@^Njv0eGC)158c-D8OLFL8lWfe%{ z3&yNQLt%W=Q=N`HS5e9gZceWU)hN2x>6e#QRu2DZ^_D-KCmbVIFYj2*@Rqr-s#|R+ zz3ALM>X0_?|2Ae_(J^+eww7u_Qx$Nxjvm!T})+pLC zEnrNn4A5PK4|_E}KzutV|GkKXy8it%Ed_WwmiUbm!Q_xb(qFz4KHbITm5~eY_Ss)2 z2#Tdk!dtd!Q~Uc@8T6nLus5a-bbM-OF1 z8b4oFxjFYqSiItNpxqSBOt14G#T4Ajd-O~-&t7BfdhX6nw4>jx(1h->mh)kp$im#( z;KBV|Oh_&>T#;q_nHOnf&QEntnsQjKlas9TYc+~%j;aauSiYTJnL|;jem))vl-{Um zL0PJK9OPafnD%JzFQs6&osJuluAS+aO(7$2rt(TUo8F>PS9&h>%*w*9YekZk`?u{cLLJcgJr+%<*&`O79VE$2KDjY zU29z;CR_wC2)D)j_8~{pQ=&c7EVWe;ZbUD5?=g4cq}pPp@vvDJBD8PfIIZU~12Mda z%4NEC*b=+`8x-9XE?fR;aW?Z^6S&Zy=@*~Ec>aad;UwvF#k;SPHa|(Fztm3|Dpu+M z+l7hIQsaLiNWPyY5Gcq-J7i4<4KGB1m{XZbv4w2MforgmzdWCJx?uJv27PnwlDMm+L=t# zVQR7bt!V~HR$~-AH46^|Rv)VR{wK6NM!ba;IJXP2^9_}^pgcRjoQ))%()D;>AKWEx z|IDNoqQuS9=iw%8d6E8(>*{-KBFhOEZ^tWZ(qR2i3$n)I0eeGRzfm1eq_6bzsRDd& zktbj8mmrW%?|0Ac;H$pK5MX8%;ZvQ3TLXAu4=|ah!AJ=0nUjB`jvJTA;}#+yvdu3r zK^V*9{m8LF6^iz$2HtUBqfSU*mUO4+(dxRPIY_F|EJVV#`a#I7*E))X`u=73HF9{l zadIqOY@(|q{P~?7|LO%FE)k8hI^73_A3cfKYQy36worl2ViyH)s1U2-U{WlumphO~ zDSr`O2tAml8fZ^~GMJUWA>+n zur2tn3ScLrW4Z-842ok>pLT?$nyo4TVd%#fe1DE_up>-5T1Ny+WUxu<;Tv?=Xgvmi zr2v@yLM6(=gva4b>;sBImXdKlpp^PshJupmy9IqyH=KSrBxY!*9|Z{oC!&o@sXBsz zuuTH#`Q!{G54wze4v__%*+CEEt?D&INEjEddZq&DyIy80S64jOngV7QK@!qBVbQ`( zD^iOa!8=liXBBpjQ>;nh>dhXuEFK{R+7APF?^2s4B)a4(B|-^SnuA09UG7&x zrl}TM6m{*w9R>m1i^gD1Wdyo9Z8Y);c)dv>@-ILXinukQ9U1V`&zYdm>TNVeL3gZg zp{LKy89GhS9fb+M+jMu*YdTO`DTm6@yJvK_j~jX8tEyGl;yj=Eo+j2ybYwYQ~1D{gnBYBgcb5aW!@z1(n)NO-Kb}q~6@Twhm;}qi0ga<)uA`t~KVI1CCj4X*;57 zoh|rrKIoT!wyd9Iwq&<@t7B9*zXBqaOpB?sx+ZrxY$dP$R11SlT{8ph_ckH zw$|Lh+Bh45Wgl|hOw*io?auTL&ESKkIz0HCMp1)Gg7$i}S1mN=(WKJqz#tgv21A9|?(24?Djbo=m6)e!4B+d#X=io-;E!O5m{1(S!{fX%8o z;Mxh`ddz@aLJ&&_dtmfjdJPJLJU-q`{t1Bf)@@5XN+CQe;R!B|A+B#laH`Mmw7pa* z>+S3vCRxIngee?)?wq_Q4`C?pKEVpDf4n(zCjUj#Zo-ns6f$)wv!JYK_4d| zv!nf}EEqlXkRiQbU1>jA%b>i-M|G%B1#Pl#S_i(K_5#+s$3Vvu6u)I_RpTBBW`+9! z@7`_KU;%`#x+Cvw>^+NR6l=kUqKQ`j>ORH6Q7D#=ZZ@NwMBgbue}vG7QE4lGac9Z- z0D*%I8wVEI5f%CAB}du0SZzWh*N2Vy+->_>NHWFCmYLR_nmwNZ;1lUO$SkIFq#m#x zGFA*;XiR&1_?h#VK1chJ@~(!jNwKzvv3nGK1xy%=X7bJxRs9KpqH+v<9qxp3-Ge8Z zHp#Kx(f^J|)#?#@Ch>l~H7B|WD{$kl1KLsw9};umi}~lZY3hPFfT_RBFTygZ9kN8B zhvjYcq1r^Xcqcs_86+Lj&w9ssa-zq1lAK+6Ne(e={+oTD7Im%DeLXU;&^O|UtG>@- z$&X%xtQ=R=KhXiP1_Gz{n6iam{$HsA77qaK0W;pRX6nxf%Knf;JQ0=%F<9`f%3VUD ziPGPT<#$-Ub1KWpOEvr0Lgi!pEK(`VBXCXo06Fgfs$hw$z<1a-^v-Es znQe8o3gXr12QPzOc;WT|{T}n%)XMEXBsULtTgOtG)yb)aTqD93tiQ~s!oHoq#vhnv zE&B8!0E*5*I+@YU%);7RPV0H9N9|D?(!J(8&CYt56m~J?EL^lgNki~)z(Sgbr2UW?_q(LZH`bbw8s1HQxkak7uel$vUY;AG@8fQ` zNcpQ;bMR}W(ZRQcXvsJ{chwIRt?y}#!b~0sfU(vK)r$xN%7;n%qL(4MS9Irkh%mO@ z7^PR{DBZBQ#c_c4i^pHyE@kTXzg`)N9O@!sm17GW`VXHqh@wu|i)=UcCegHQJ0Bp{ z^tZE+#g;yi4`8r6ZVx)h0$VtVAi6Q(uP5d4q8cKs-Le^)cT0A=YQ4)s)6K<5Ef>&C^clzw;(d&&iK%H;gZ7 zW@ZxwUGM3;k`{D)t}BFo49D;)hb)NeiW?E48hkorJ-IQ7wQHrlv(?$u!nmw|{iD)P zaJ!M}ef@CYUNdMPbS3G^v&(vU-WuRMrAwdvB1W=AYJsZM(yD-AF^Up*0}Ga~bI>?u zFT>UJ|2GX;2w%JGk~Lsq11wGGg4N!VuHM6|lzz%C$j-;1d%IPoXZ zj|kq!Y;H1YuQVHz(awdue_ysKAQn&QsnHsv-zG3?G><0Q24ZL~U2KGIN;f9bElXvqhfvXxPO|VzaZSA_}vsK1fpCKN^ zhUgN{o%`!;af~K+TH0>n@!z|v%&E<`I+0U$XX<>y>?({Za`7xboCuwv(}L2jR@OM0 zVWP&$E`IQtMoY(H{a^upCcbb_^5)vuc3m{T%s&J_AneAHn=UKZHyq!$RtT+*MAm*_ zXk*ALQ-K*9wJ4c8@lb4x09cg-bH3oBsv(YahNoTbb$4OcH*8gs8;uu_;?A z)1|w)a-|CU6_CqbJGZ1>Og*WJF92;NK#oPO@lYG{rW~|3@^eH62 z&3#qOwEh{AcOg8nO7)o+nzZ32<%u7=z;%v?Wj1K?Va8)jum~;Iu|@1Ms&3ZD2An!;0d9X;Jh6orD1 z+1lmQLqB{URh6jA=cJ8pjA!efn$~vaaR~ii`J%pbKm^gG8e+duCW`(xa+-pE5UBo> z?yVt)FJ_2VkDFho3oiv_9`6hW;&##ZC)v`nDOp2>e0`zExeJ+31phE{p;fdy3ex{ zCpTy8tAA0b5`P@=an5pLdWqm&$^Kz&i6bn+vtz9SzkpLlsMh|d-1Vum$99F3tD$kb~AW|l76@TypVNJDhPnbks>!hzayR){>UHRd6Sk9qt}UNBQV zMx2t;(_!!`qlN!fa+Q3ycSU5P35pFi=?4-h1%b`t8bbcVC-t${VaMT(5epm!SEqb( zW?ZsWCVGv+ib{(Tpfyosha`KjrHUSBICEG$TYjmQX+rG6wkq`7Bdw}eZJ?UK?me$8 z?aSayK^}~>&vLW4n_-@l8HXVy|LjuGjs}Ea^26RI?%WpVQqQlG zyyzZQg-C<7*xn8NHvxb7P70csmJ=pZx6h;Qchp?}}|;PB%@7{?kXapE|Zr-rqL zwJ1YLi=E|b#lUUdzTzgCGqcLK&qd>*H$@XT&dSf{7uC#IPD<`!4KQ1t)m0hz%?{Dc zG4wnZzHjQnn5s|Oyg zUf-VK%MEmz=!zDIw10?sYW>8&n)+t94U(M%Dwnc!U1#}={vbr-Vu5=#PA1{7ZPuKtu5y* z{&Azj(Z~=9ndhUh!GK@XS37z*?X?|E%tK5P8v(;d-B3-=P)C={;#D%mE-6Mnskf^S zfZ5fm$NgSGY|@u(J<=Ys$u>;7VO9_op7F(kzSOCy1rEWMnYoO zQp-R8O^{o5$0?3+f3(hO69EpaW?f>6hbCQHt{374ay$P~5FpXoAD#X^3NHQf;Ltm* zn&&eGsPn!dzZMnApofOCHWCT&^vXna?mKR8@{4CMwY7V+r^nJb8NuU_Euv%aF% zb+Qdc3-ZZs&$oy4?KLZR<$q$rC(>)W@6smdX<`Nw%2k5@$jJHSWeA{__@F#rV zJ{5(vyn8M;8%%L)_!jy8&B*snFO=qTC)`kWh7zYW-W9{$k(ZUb2P9wXgTqf`EXt;2gZhk!34m5LU+x%LyM~Yx#GSt2vsaB1 zl^>yw*=Id48V^R#eI}KW`{0QMQu|f;$tL1WvsZ~0NTULW03S=_^qbnG zX%~KqB*|Djpd0;P3VZ-WBO`e}k($z(rFp-B-@d+J=6@ap_64Y4l;=v`RYPNG49{aOB{kG1cPrdBaL2kOvVOaFt1AH7(V>M201D;>g zi;A?f@TZd57JNU-pDP7Wsn|QK{&s1h$AM^Z^+?6pZ`cI_10<4SkJjXost00 z(t-hkxG@}DH`w0wNFq?*n$IKJ^dy-zyEUfzp)y<`+kAhL6p zA4#fec@a6_u;BZ-n_A`$^XyMim1~($?rFiB^(n3b04#HCoAbBL1G=H#MDxnz3>Gjl9|6)Dk*sP0^k*YUc{Lc@UJZX8@vIJ2>EFf zs%*uPNtUb`a^B1qrwe94mi+9kqr+aBe;U%9V13AV&WqJhrcEIn!IOR!x&bb=E8&N# z`x4_Fe+(&0p^HwXT*i+zor(>^PU8W|oL4RowF+YQy-QN)QW3<{%)1s0nf~`W9ol^2 zk!^MBv}{~BP%$*JyT9{0RJc$_3j#5;cm9N^-z@g|gD;1Ski&3zepNnUzEgF8qK*hr z9Q%)yp&T*4IRAYtYW!A)2-Lus&HMeU^_q+b!8!-yLPNE{A}B%UWj9#k^jz8|skx*_ zgl9b2i0ayP4~f$U1x&)uXT#B|a?d0XGw5qdWwM+&qEUx8z|Wf0Fxtlr_R(6RyPHnrZZQG4)yRmKCb{gB5V1l{R z@4NT@3GZ5Go%cNZ`R%>Uf2@i1Bu0YS@+8PpWl9UQ7)U9R7eVDY7LRmAJ!E%(-qnl+ zO;~_ir2#s`iF9|rly=~iehl-RZc(VMww*)(n4GNny+8Q3q|VEZJsIy8`~mBLe6P>` zZb!eQir(tHa(hvE5fDyBeSE6bI4l$Oc}^r+29pSDy$GJM`M!m{YfU7(zxWEUSnxZq zdVT8tKzYm5T52elKP=;e<)M_76VNm93Gm;H zT8ItnDi6}z#Xy0r&-6DD*U23%=tp_QWe8&XnL((@AHAP5vW56DxVJhb_Q*VF<;%2E zmigCmGV`1V^$NXuQb`mE+M#pX+n2eMUEf9Kq(d=fbgB8g{-R|4Jb7m?WQH#rxTzO< zEA}OaY{J)hpK-^V-o~rPHJ!Jh+NsG5dH7KIc3ppX7}ui>Sf^WbeXNcf+r}Rs zx7j9mg~NUJk+GV%5s>l+rbBJ*ZrD@-^d~py`|2oXZ1T<~C__(DPOzARBwC;Ej3k9U zBy|$m94x^?{Ks;-D9q}mubIbpr(lk4u0vs53XoI75Os9UMIRV{b+SMvto{K^l*wec zh@flp#ptWvp9n4bP>8TRTul(f&TLQOSSrX@TA>5kBvHHxeFZb>I<_8MwaC23tyVT_ z&u}zzTtXsTVYban=e&y1lV-vSC5t%?m~9P)Nd|f_+mEH9QkR_^VJgS+dlDaQlx1N~ zoadrJIURPHL47BU{dgbKe5|Y%T28sb{p1HKt$5LU*w+KWkbgP0b+fta2|RD5f*aZy zwN{h__$zf3>YTFP`o8OlFU&9h=MqvBO<+!A42SGX5$I~h9*80aenw!kB6OIlfF0HT zU0FzlSog&pauF+B_Y=qRFAW_dSjS4#mfc1g-| z?Rk9PaJ!0)dTnC!8s*7m&d-LwmARNpQdW@zxN)xjZ6>G_axQFj-Jsgc{LQovJ3o3~ z8zr#St?yYx8PImViSeo2W@<>y5ie+mVBxSGWb(yxwq`rs@(r7>8^ySShfuiRUQXtX zeE)3-)EKLGAG9IFxGTK^tua6RykFe;)6jj4(+KHv8oY+HKVy&zZ;9480Ti*W$LCo- zRZ&c4-WfkUpS|2afg+j)O~RN908{4UdaNJE8EmVVukGP+d$6wXiwfo105x zoG@S>K?LXM2n;v&Sg6jitS!|zWH}PVjPHSV(7SjC)6(%JB}HG^QyLBMB(=Jk~lHu)c@=GLODU^=sA z#Iw_sO8ib|yMN>9Iw+8^V#o~Lom~NN7vEta6lkxltlq7zCyrcpXvB_0=C^SUB zAW~%fDlhZmyClDD3KvJ&my6^Cmln?bs+YV>p!`FcmA`GPsLnj+CeB$?AN+`VXd@d# z@udujTE!!P?vq{g5xl5qVVj#coIr3y&KrX#l5zL@&c)c|ITwWC{F~=>dzu6v(c6vd z(mN|gwYc#czQf-BryU%<7*r#bTQB~~sME1br^AxXnN3r#r2JYmAhCUoC=SRsF}Lu7 z?L{BUV1H=tlfdABtrj5UUhOqccp6Jog2J_VKEOXA=@(VoQ{GFL`T0SznrzFqQ%OFj z&+p>6;b_sP3_@*%6okm?8qBDoo|fG$l)j)6eX|P#Vs#VS1u~Q%SA|?N-Dh)cot4+{ z9Th-ppiIzHAY>P7gFNRPG!-`1zTnzN1AhVYokZ)TtH;@7OYHl^@y%_ z1hzyTa9iUlLFQ2Zd*984)dQ-;_8cn~nM>-IGs3j;W_j=Uyk@ zI9*8F$EiPqVl?O3d&sOLQzI4bq%eOQs)oq>{iX`$U)-_j50*6uthV3r$K_iuC-aT8 zrX*IT%>DUNkJlAW9{c*w{0d5wef30Vm+uX;Uj*a zO7u&;Q38dZBHC|oz$7x38gV7kx~K8b2BhbX@LATXVa6Y zr|Y=$<%bgys^0eCGVi5FSqPodm~hsIrV5PsQQEhL1Qw$u&xKHg(dN=A$eDn@8TutdM;h>h(#p2pbrn`5p%#`bi~Ul#a!$TL@dtvp zZ_K~SLZi(vu?lPSvY8f#ida_c+lNlrw^EZ{LkDn3>u*ENWYj`0Pr@^u!n!W-oPM%) z$6nqY1M5!kWi(VZpbi_w#Dze!H%0GuMWSSfGKR#SoNYm#AI0FamUgcohx+fZwfspN zqGMiy)~1*_pgBv^;e-gBz#G#&Uz}eTHaC>9z6p%3QmuH)E@InCDKziXd;qZqi$_(? zE#R?Q>Ntr3`rkVgIN9C8B9?oil3{Z}wpGZ6@LZ!?M4bugZw7AVhK5v;WdV_avb98Dc-2gx}T}%Id*cD(K-5s&+i=kOZapr~8i_ zlpDhYK&;0p|D7b)|LvfF$e~{xzwOiOl}DhqFI!@1#iO4l7i>ORF2tf|GY||5z;43j z%STv=7G}eK^7y2zu1+r>xN(*xJ|r$OG+(6V zm-m3wQ|IQaq82!W<#9#;?Na@ovj+%DVEpdZx0#I7Q}-ADo%~K2tPA}etlOZVk;NWm zHFoe-4+5R00>*UWG!QtJ|;va+EoLZ4`yuRey;7R`0 zoF(IR?ofY2H5%`i?6cP+DPw-xEtBt%n)5A-4+z#;Gr4yS@tP=4Tfmpk%MjK;sP;cm za;;p3a2pL`lN6Uc@m|Nix{fe@Fwj~U9jG2(nskOP zy(iF_UN@guRZoNniQ58k90cUR=G0TKBW$gg%qd7EM#a*1y-K_IYxuA5e$CvoXH||A z1W>=qBhxd=3TfJH6_MYTZH{&WqO0>7aG5&#BNEY=uxx*^)SujHo#@&&xjQTIq|$N+ zd(&;@U%||jUh%RQFDA(1&0D^B37!7~!3ZEj;5H;Y91;%KG`_d|frLo!!%uP~b;c35 zuK}aTVHJE^X~bupVrCRr%wL8Q@Z@IV?P^kGx2W zg-fjes&?SG3%OvBiWQ0+TO)J(}VXdbFc4NNIV0`1o6ZCbu*`U>bjP0t++#VBJB@Um4$ zT$;Nuu%RJL;jsnz+@v$Jfb$Z3^`!T4hN2R8%n_n#il}K^0*k`Xkud-!PeB#Rbwjpb zZPFuY>ki2mFNDi}nHJ_MZv%f7s^eXbov>`J)I7r$!S~-h9AFRl?ZE3Xqjz2wd%jbjnK&NtsAKl4zu&QY|4Rv+@ve?tz-AHIakT2ZNG86(i~QBuYp9}WXWV%Gg=%z!+cPRDwe&9P|L1C z_CY+VFZ_%_rp0Bu`9~Gnu3%5Len~*n0dkv{++_I3_<^ zy$35hT#On1dtxp zr@_9fjY`kX)2{HeCB$$H$?(3tyuIz&UMXkqpDzDT%6x|1gRFOA0IqwXKpiM=7}kmNKR?&WK!pwUkPE1;o0k+)Y}gKh zxoGH(`F%b#kE^2W>eUJiLl_8Ss~LM}c)R!}S|B)#p}dfZ#Lwexb6c$;bL)>TyOd9* z5@`bPD&SHa^)iGtmLvUWIdl#wdwjHR%RBPS1de-w3|Qwz5p+yCIX!?r+!R&359t zee@%{bf=W=BQ_l_V!Va#rtEMbXy^|jf=cYAt~LK_nLkyuUnfHISTsG#x%#1>4un5* zRW9#WWB55wJat5|$}@NB-|hBKpy+OYzhdoMh78*teZ7e{@Sg}@9b1F+!VJCPY7okBN)=lk0Cpi#kBM^yruoPJ}U+icl@4QVIYXq3qP0;{tKl;LyVc)j-Ly^t;i+qIp8tT?WO}W zg!s-UUX@U?E3;63pb>ztO2-IqTP(y%{o%w-WN##3#It|JnP{mZ0rS!2cWPilQ+$*b z+Ul1|S;VUs2ODa9;j+6(f^psQq*qm89ivan1E5D(f>Q)c5y>|qG)*&-9hqu$-z&}@ ztJa}~D8II-63uUSMU6zRe6~dX@4Fsx^p6H6n2>yw(D(KW$SirW_*L?ioYPpcVbfZW zQzIWE(0QXZiaeP`N^bSya<0+#2vG2;oB5qd;L4+G0Y!r$0VWXEEY&xbUyD?FLFc4L+?R(LQ9GJ&{w0M8 zv%MA)fgi@UB(5{Uf3|RNb5FOb4@)-&H8UY86n9#8C~x=0PLKZSgVeZ!QdIF*El&PL z*qik09?!5bkl9<{gtH;x{clFCg@&|y?vmHYg&JiMn3la#G#x#GdMEhRrjFr z(=5gmJ+e6Ib2rbekJ7fqKl=aQnfv|92uUS+?D9?~hFz^?yH)2Gn1#A|JP`lMVI+VL z}(gXO?ceqUAkI{}*zE+@kvSBS9QE*@n&C07H? zSCg`rRD9GwGV#X-+}su}!hAtza+=#oc%6>7gXC{J+p{@`w{F0G3@*Uy)Iq&k^+OD# zEOTjaSkm(48*G#Yg6@18FSN8Tf9;IEWri}5_;Bew%k_=z@U|=32BsEe&v(Vo@siwk z(C7RMk!<4jq+yzGxS|pgs@$xEsBPW@XhmeB2S`ns@7ny(ZUtS@o#KI#=yXfW1t5#rg{pzG> zK|K^Y<{SL}Var=~wNeDUFGJ&|g^@yEa_lU^<;I;%3Q-=X_!=1eA1&jmX?&RR zvAxoLpb{$bXG>FBvMWhg$+P+?qO?V);hmYLHP!ngo_n!Zfv+-Sf=aquoqJ)PyyvLl z=%Fr@s|G8dnGj7_{OCuz zP3_T~uf38_ie4XcuzFzDi%Cpl`kIPVL_ zJS3c!{Z>O_>PdXg!hIu&^ftxSFa7B+=+?0zlYMlisw&bGQGP5R$|5C+jjW`ZN&7AX zB5iBVX=rn2R}mU}+y#^&*_e*%(gTK5g~G0u*N>&A_|+HhcPWmbN6!}^#+8cA!>I1R zH(bQ6kpb_(9XdL-l)m>Ky`r0 zRk5_izG0KOTyQS zfKAk78tBJfUrfX8IHpwun9}q(t5mvUya0{|*~vD6VQf=Ve_`4DpqWD*`3=?y^eH|C zT~TyU+z_<3C7B8KMz7(^#}D)1Jw159CXh z=sZ(`EF-WB>O`rXAhvB|P+FrvaWz*>9l&q8(xB;6dZeY@llUIma3Hq0Du8VIE~M|07lKdt(&~EV=&wPi{@o1SZGw{`K||SK-jzwz((FuV?A3ySnObU?EJ5z2@>>s z3F?l>1WXC3N4{PK7c39S4wSGX=9b%xf0kca(r^T(-*sqwh z#FF>n$uV$S`HXmL)a?~V!gSxL^Jj(p2TvD}bWmA*;;xKx9nqh>MWJ{sp-#~~Jt-Fg zrL>trZV_DF*C*W-na^7HI&i)Oax@#;{W7~$x4Vy*VI+12Z=g=_XVt#{m zOo0QK#1SkRp)$;aI14+={4}GWB|6d%N&;5rqzazONDKXsbbx!7zi&`Msw;rD{clpv z=jnz^xR{Rd6(V0r#O&tTD&9W2d=}H9h-H?B=BM73>=~F`z;a{L@Zslme&ub5N<*EJBFt7nUq8AL98WrB*B_EXq^L_?dDZS?qcZ=SMWM-Oe ze}YP}k(@bq2xC3RKKAfGB+ZuGzG-Spu1?T+6M8l%s_Q5C4QsSb6k#*;y*@#nU(|g* z;S*(2LCzNo!p!+i5cm>A-pp~ec3_yO73mkr3sk)z(aE6-`zVZyWn2)J6-+x3+wJ5V z3EoWISa#Nd@uoS#B-^ZHt1a(mEZ>Yy>zMCCi5iJ}x~HW(C?Rp8sA}Rl75MV8YmZ$A ziu#%tA5ST!SL8~QF7M|b7K1vydD){ZN0uy&7x^8z#q!o7(s;RL0D*W7)ILff#jE!{ ze1YpV@foSXCnd1{Q5L-M6y=#dqt#58v@lIB4sc3=r;^|lY;L$-jk`HS=N!yV;B|fv z)^Wh=yCP6XAo()q=5KhqR*ug)!*kI@70wb`3^Zrl@6kWS<}O|mBkAA`bYt}WuWTly z-UI|++=B=4-ErZaTo_Aw3n`dj%`^@v_pQRH)vZivVE?#3OJzrJY^So5vlF=mVR^Gq z-q(uN6QmSWvT1$0ewPZTnJj`Vloh7lBqnIBJRBsrQ2M~$AjEBrg zSqjyv>7{apZnVb!XWo{W{)eC1h_sXgOV8YHg`^~7rTQI8j|$HjT4Y*|G~xa* z{oB!lcLS#RCd-7wZw~l=9M6+lfoo()IDbTfRxak#%FsM9;;MU3d&~w3@ERcMP0;V8 zrxI22ZrnX%8Ll9Cmg*X7=|Q*AGg?Tu`z4~=p89`8MziZOSR0-HHdwoIPZT+HR?o=p z!aB49?YEceo>*=pEOW|AWkQYyrE7Lc-Yoy=4Qvfz(Bz9aW0))Thh#cm%ft`dnM^o{pxor;kop)Uv3WNq%UX5L#9bCSf=oW-qarA#{}PA^v906 zK@2Y(nC%@(quZ4C;z1ZQbb%`g`N^h|3{3SJf_Z;|u&%^Q!bxmqJz+@Yf@a7GjAyxh zd~O8(U)T7Js&kya37NdN_yCNE+}fA%fg*xW2k@TNBHtQ+L^kAd zWm2=GwEh_u%l#G`-K(3$A4cN^M`|-SGyv|)A@#K-C46XE8Fo$4cGKkWmy8tLEi6XfHa-8yr(A0qdgi zUVWdNV4G^8MPF0$>uLoLzU3RjaTo~4u zE3NX6c{`8r#tvv&&pWU}hogMZ&NK?n*yv{~%e7r2xMw7~GcDiNm5Qy2-vCCaBN)T+ z^P#DlkG2lg>f$kp-cbpeo$z@Zr$EX%0_68U?m(ysATLl$WhPOF&U(LGzw@NsLTAym z#BxF+vDi(naC;vzdH!!g>GN|XgytSb+UBj)SO0(kKhw%>5z(TG+j4d!F&bj!clK>@ zJ!*RLYs3$xlFNjj9;XEe?CF+&2dYLBuFZ<=z3_L+mz1Rtw|_Jz6*(b}H6vyNGe<{? zd9Z@A;TP}gt0kM-UUrX!ZeEytY?w;Dd|`UXOT2FX^T$-$K#WX9ily??=23=Kfim6p zLonqZdP4P2Q?sM7Zr}}w+|jcu1Jq2+PGaX97}jM_ZrhP|uX`Bz>vQOMNl#Tm5{{goD2*Ac)wkaDT&emHm3_^c`B2PCj9e?47S-Sym zU-i(O&b&168W{t2GF1jo{@&)Xnwf%g-l%G~`_y`fum716i)r?(l=fI}rIw7D$!?|e zfnP23mhL#Z)635!`~G8e((Vd#m=0=Hh;@CvLT++n9#Zq@?j1u5vjv!1Zhm zjbj+*wqx{gr~dNI<`HfdQwO!ry?hm$2I^=JfLDU1(9u`9r36w)SDKHP)8mud6^{OD z=!0?<-|(qD?f@m)l6C$@NTj78?9gD&=G8e9VnvUcOGF$W9@;&Xc{_kCjL*VX3QV6X z1&+5YEg<(ek`1j0MGiyQ5A_7~x|F5HTa1UDWFN&PFP@-;nhGERQFI z<$`6{_yl1T zKh=aqC;L2GvFX!cahvq>e(imqFed(sl_?vj8@f2##5MCphze6*J3tL}3=_gYAQGY8 z-JvUX(jKs;-P3R%#MR#r>56=Nl9(XVvwH3~!{jpc^veq^u|J)O{emfQs`Pu?VDo52 zK6VN(MJIfgc(#TW;#^E4^t&RZf4Z8%mv!%(5JSfEWLw!B|&2i|sn=H%G@;%U=yU7{cCfFLBMl7or)vI>w}E8 ztzF^RePOm_?+ z!LsCxlrXV7n5qswr6I2R9ifBg*?8?r(RUUc{tECynqxu@WKv9r7eb2XIf-*mR!}!W zIzzQBplv)qn^`RT-!OwpaLau%h1|PXs8@+;tZ4pvDFiMZ#P4oMQTBnX1d3hP55y8{Y{5~!_X^;62;-whp966=_3QQT zAc*0K_3ZlfDNbSz4IuKf(w5_tVhiUYLx~{`c?C^+-JiDj<#Hg0itCL66s%aS&*cJ9 z5}uN4`>9wL+kx-wuivZPaIza@{qW}%ebp*TW6NLDCu(WSL@fQ)PaG=`5Bk&}31MTj zA5gn8>2QacqtE{YHqZbJD?)CB-8uMPy91XwT#>BG377hX@#8U-z_vzhjEK^S={i&V zy<(PN^2`S)^!O{dB6Qa%4#&u~T;qY*ep#38#FKS*Ji011s=QVlmD<0XXOwptv}7W`??^6~kb zf`y1Tyj09r==$HW;|6J0;ujD%~Srd1`L$RDgxUb$cglV|E1(ku>=Tbm9UgF@JiudJPfda5- zAtW(tpVIwP#%Tf`<2z<+S=#pza~~4c=_8d2Ov%**_r*{h9(}6cKKANk#$Pm_s=KDw z1zXcFNEN?#a;2ItYY5`$jTdaHe~RII6S_3MB)6i{a^{;AeCtjEUx8e1!NwW?i}>_G zbTivxa61W|A79&5!LmhKjj%ImFatgh(>*#I?!fAyS@3c9htJi#Tjnr>+J(Rt>hE&? zX4sqDWG7inUM_dp@za}_$ewZ)I2sQ+ctdh%oF`^JA~Oyf(DUO+3nzHUWb=*vrycL3 z>>8;ID{X22?9YTqptu*{6mALWJErz!vlVlgj>yJNbNIp|^8__TdMN6<3SFNM-;j8`GX z`yWeXIHbzAn9>!ObDFHY&~T|s)ucW2v*O3nB;h05wVvOu;w*p9x9d|Sn?rD&a*jPp zTu6KoNhIbr%seF%Z`6A?*KZhJlcDXuqkLnnza4iO16INYMfxkHT-_a_m2&PD!_-*E z1R-b{!CN=l$=bmlUPU1Q8V+0eCwbS3+9G(box0t*mzR#<_?yaijsWZ>4kkZn&=?&l zGA1&0%hU%`g8BYK9;aSnzC5{L!O(Z58aBt$^YpMaW`K=1?|0yqdBz%7OQv9?zHuMI zbXZ2K8!EYBKFiRYPr=2HWl|8i7}yvsbGh!0prh};cUVVXkm|B1(xBS}_Hv;b9tbw8 zw%j|_ogVU2cw|1y6e4heIt-P_d4$CF(G$qgxlfo1%^ik})I8~o?AE{g-e;Wcd=!KK zMxWtBt0({R#Zuwq6nrrWF+_MeVp9-)I@J1qLtXhPxNMoJkzbKpXvUcZ5itxZ*kCjU z*MW$wJn8nkO|(X9-V6+Y3aAtI>Vsq0NWn?C*MK)cxl6NdZje`xb%k_TQa=pw-PAQKEyj5CY`sxhjNWQ*5J&CU@scnB6j)r3U%x@Ty~!))yrh&l;7IA)T}r1Dhrm_bbA*uaHR#AQA6R*pk#Nxw0> z+lE6X@BKfw_WpYEy~2v+<$HJSI1}O_HdV!50#<^$aPXm+n8Fk82v7p^)Om)nHiG?4 zuqtvZDWUvcN%vxT=v6ofpTV)Hcf?}RKir=qp?Z@AIzBQ0aVSbw<1L$ag@%<$?my#sFVonp| z@+jMeNhCQS6VeV*rWfqDW{)!(uF^L1=)ovlOd-E?GaR|~RdmGD?K1Kf1RsAFhBt)n z2?k3Y{}BBYk#BGL?Eo1nTQ)drqM+1=&GQcQQ8*n896`;r%C_KVi5od?>Fd6bDa+1S zL3%z%ZI8b-c7krKhs3^8W*ITig7_F!FE6@~C_XgGs3~G4pR!f?d&!sUZU^;@8 zyX#ucq1CgF4dtrC4@P9z^!KjXOi#XJgoC5TyDSZnUjJ8c4t9lPr`~3b&fd8D7ZJt= znk#?2-K4&3;uNi8*cUS^e^h_=Q74urG@|QCi*4BbbG@lZ88F1~!s}DHI>Fmr%7e=y zg>GpSjdZ^Pg)cN@M}TN1JErR2JM_FJ@i*>1BaqB6WA5uU5U<+z^;RDIe%<(=ExDkc zdwi8{v$o4~*&l!USCoVc9D?$Is~^2qfia;BcDm>Ju1@LMAA4zoiC1U#Re1Nb<*>Ru zY~Xapu6lCkSBH_Og7gI4IASElmKrj$jwbc~cyFL`M?8Tta7Mf@(q-V@{h!H!b8#+4 z7ME-TpD3dDNV*R*U19E)yAT67gd%(-U+OOJ%NkYHn>Bm`#mc#nFYhfi@BlLtrY>XGCYNwvIHnU?t?4qwIKLX0TfPXbrqucFS(Ki+8-Cr2o@ z-h}(ThA%^-;w&`Y#cZx+wj7gkbslLn!9I4tAo;nFtcb3Fz)+CRfx**^Pm$okpgB&G zEi>W*W34^k2kMfr`YZY4xF&HVyNJR&JK0lTWShiK7H_VeI$+y;u)e5|l2r+Y?`~a~ z_;|9$A|Ou57xvYxtK~U-joS|I=x_nR&n$FoXXZQ6Y+*%xSJg2Le^3UtC=c|4$K1Ps zWzl4hDq7=>`658p;P_?s=+J-0#_}?pJX3T~NpoJ1#A|du7#DeAi=G+N(ViGEWpT>u zMa&`)K42J40&jE%xZr*zZ7wj}IA^{BCadIB#j= z^unbLA>gY)$@AUV%71aSzGp&i?Le?L5Nw>n52f|RzR~~5j^AOX?()yznhiBmgVa*f zZ@tO^HLinR0gBfBP=8WcJuVg+goa z03e1idLP`){$(Qye7GX}Y)XnRAiTDAuwBlwY_IXo5B6p;Z_U}Pun5`3BN8L)2=oRN zVBx{Q@F>>JI9gxyt{{vhveZ!JeNpto*=XWwnykxMD4UNt6dlv&FhcLe0%vtreBs$6 zjZ}u2wR4mz>G{3^yExrg>`hK%J2_?t=w9+NF;>Gq;*c&qE5F7*`l_RUR&lU)*Xr)A zKF>(LtJNv@B$YJ~b)DGl_`#9e3_}Mf`fKXpNudX(P}ot7wnktvIQKGibFoz2riX=x ziTgJlYMhtI71UC$<%MgFxQbeW^NkpMPnq{Z!G=~(T`%JtOpu7X8j|PaB1(q?o#Fu< zSxvQhdEFy3<8eNiVFga}MDmTxC{fU(`ZQ~JcIvZP(nUZA!#7xF#OOLA>=M7}t}wYO zPl@0=r-VBLe=?dZ<5{D(kSoOEv!iUaT13uY54ktK0fO+k5|&2oW*7?Jp;uC_XQF)c zSyD+#hFBg(1AmSRc2t!?Rj(om{x_cog7v6DKHA12aw63)nqZ|^)eY{H8;!y1(XX(T z-onULgkr_Bxj(N$61O3?FmZT+uVh#QMuChEQUUatfLXc=_Ti(K$nVb*x@X$BwCdZW zl^x+PipNatMq|3@k401)iaNI-IacYp2l*REOBp~OaYel6Q;4J&K5mld z^!n}31?QCc>Wy9-y`+oGWp8HMHI-{VFGY#qeWM%C+g3vJ@l;avk3k>aTVJ+g?B7?_ zfbR=(ULASFnVDrhk%ZG1TKLq89JyziyYb!R2Gy?>x$?I1 zFrPI8jOFJfcOGPn?4eoVt!a!v-^nSvmOd;gz!p(nLuDeg6t)qDUDt2gPuc7(Zf;Ed3 zC;KW6DUg2Vu4L#C;=?Y&Xxi-Z(cfeuF;YMxDyCrV->rFLpLdFP_f&Af1 zVk$^oYXC=P2(|>=M*+J37l^KAhqP@#O8450cy`s0cW*Ehk_wmLT+&d3p&9m)P+QO5 zIK3;8zj*$d|!sAA=jvLDsu>2WaO}a4Y@EIg!rzT@C_HFn!WpvGj0)CIP0oX!uK7 zUc-n4J#HQAq4<3VOJqTNIaEBb98|BXDQBT-5p@s>GpyrVBa=9LhP#;Aqs(HiW z!-jkL<-#J&cEfuvP7$exM?0+`CDT_OJr$+N>n8Sk~m~} zhsJ%f-p_$FE$Bjw;KcNyb{B&5?4U;|vBCiRNY+k#U z1IK8^Joseima{BWqeG8P=x+{y$3cZ?`)v|w3UQ?P!sAmN@P4>OXPi&Lpw#Am@c1eB zV@ZL_EHhKI=H4jLubk6;z3V$#3O$z!^oWbEaAS)}Hg87@P46-G*qH?YUF3% z-3~8YP`L_nM>^y)P?;G?DH-ncy%!O}M}ukLU)!?ri05o0Ejo245(VW7jly4|$r_g! z?fP0xU|~(w$qr}LjJ|+Atc8Gh?~p=`YufK)-jTl;R@?a&>Gx3-zc+LMB8eN+z*F4? zJoFdy1lSh`ECB&45{w}BQe0n_B}y5QZcADytFN25$1-HfbGz}V9B$^F!5FQT`(KGF z7I_?HCz|&u3RDK*>`fbR>hxoQ)Z&gdk>Bjb{p;wZ5mcPJh74vPNc)>BR1v9_DE))g_E(T7YjsNwq*x>7FJ|E!W0Es4$g|~JJMliOaV*AwHm^N9tu#dZ%Y%2BW zN9M$zD#_TK($q{}G$C6c2?cVW=LDgK7ZiSoF8VKl=ZSZ`SBRJULdQu;iXa(Y}q!cQ`w0N~F20zjEx`lS92E9M z-tq*&_rI0s=B8MlkTuF5GYWdCzp$F8G)w~80>9}u!k!ZLmmxUQNPS|Nh`I~NIUN98 zdSBD`w)8)K;;HLp=&hdd;`RBM69RU1)y&uME2d-#t?Z%Mml(eW^V%@$oUmN-gn)Wi zAoHAKd8)_|yk4l{Lex7Ly~}}-_BPg9BOB|=u6})}qiBQ2i4GO;3H0^3bVg!nx@f~i z*$Z>d5z?WM4eHi~zNsA#+-qxY7+(`2xTG^TQ6@h4T=eB@l|iT-vWFmIEps;k)~QfY`((JU$07n<;bUX z4dUYMJxa8iU<)2S2ziIP8at8>TFH@0nHQD`Bmm?(Ot}yV-?AYFS5Z}~Ivg5T14bHb zQD(tp2+w83Vp>|JH01#0 zGrVurAk=DC2gwu&ihlO^8MH#k?*gNZO-vjZ?9hW9dFvuUL>kYGP1~|dwQ>z_Jw)+P z(fts;sSfc17wH;`4^ud5r8LRBAQw*i>5nKf;yyQ^<+o$Z8c8S z8P`yU!lj-0&W%EkKrxi3O;6y(!L>$k2<)gA%QvW}F|Z7_lY+2{LFfsX3Gtj<%l+>l zg(4T!=TGy9m>1OLK%V1etd(HGt*^!VZl=%|V5SkmJ7TT|@ob}7Dx?mjFKBYm_{1LZ_Wc;aqjEH!_vry{5NRR$g`X6BHo1T!8Q`)R<<#iofM z=q25uWk`c6IKg>S9W8GV2dDoEgvIVMU=|ynLg;Kn;L7sw6j}=>Nc@JDR?^?O5 zD+AO4IVcFm`}aKgmy7MINW-;Lz7OKSA6M7#fPJ^=DgB7qN3`xaU`9nDkk*joQOgXi zl$ez%$69{N(u?lvTaNY<7~Vl-;}mTDE3jjWj%!ZHuuZCDgl;a){!1|Zb_xWQQkhAA z*NvwTm?*Pcv8Lsdm5zO{eiaf_Vr(beMGxEO3wDsVCakzjD`E}&TkobBsuMg$SzwTs za!e_remb)R7GYcK?tB;0k*XOVW-`_!0A~aMXn8Y_>Lp)oXAm@qio=Mk)2buhHBUzJ z=jpBoG{6z)X9|TX_v8(;OX=Zd$Fjhw3g`sDEA#o$h%2Pg#@wqQs>Ub1CyF8|LBztL zFy&BXOQVMZKq7!YPe&sGK5*Zvg93=AQ-(kQFn0Hyh9uSG{$l=>l42gL{T36{ugB%wmJ&nSC#Vr`#ruhu=k-P zQ`3g1YY*tHg=V2dvWx2EOJ3g#Iw?w4abMJ$_kz;{0af~;^O*RzQ<7nT{JIo;dxl-g zX3SJm=6%Dfod>`7fF8M_NoTzNh)R!vKVJ9dzPRcq3|OrS2gT3iIbBbG-fm5Wno=~n zz^hBGF^XO7{~(x*F}iA-p$2okcAIJHtact8RDG7*h3juGuxd}(fH{5cuE!Q%QlK7e>P#yeH2?e=Gq1w z{!JIUCM_)sug_Z?8rAr~#}Ok;G-}5KTg*%)`)CyT{vvh!t4mw9YO2<+)cvvBEZCf1&9k6Gz4lJ&Gn7wMp!r!F9QV0Sk}y_}Un^04{9zJl5Di*+Ws z_6j(UAbS9LwcvyX<*@z^WTgJsqQ3)a7pxMOjaYW>>~;pP^_9+p3- z^eFpC5Nzts^tGFA+Ou>_{9*6v`7}V?`eeHqg`Ct68GqQkxzu*>2rxo;D*&I9LX-cC zYecQumVL`e;NRV3it#Tb=ie)Fo#g#bvL=nVtWyWM<$!A-cH&Bs-TqN5V6(z8&dRd# z%d;)jg9+v-rJgpIS#(=YVR_H;jPNVF&g>(>UeORQE;RhBnFD|RuVv3y#)ZAPli{bN zjzp%}H_p%X>n$#s?~N&14;Ve(nYYi??_)k_1B}zjOgi0FEx7Vq`URMg$`p~qahNo$ zm(Vl$A~1e=YZXe&wO49j)xBC(#{is&9$_wv*Peou!g;*Zno9E}2zBONe2&L2YmF&6plLQx}! z{cWlPC66#l8l5v&6u&E);z{DU`X_LrzVzB@MB_tgW&qhSqMOB#UY3{OL9(DbI+61K zFm)DwQSEKCAG*66C8fKh5s?N_y1Tn;=uo7UZUvF-ut=#!?S<; ziM759I|EM-n7nIvidKI8bvuJMPVUvc|3$^snK1)uD^7<*pm)L-2lo)L^h{Uz4UHtx|kcMLY* zqg$=hn4;kK<{|L?v1WxD(x z08<}^GsC|6AEGgTrtW(Il7NMgf>16ezq7BveJob1x0Dllco4^set>PX38NLDYCUlD z`P07`rZJa)x~Ya4K*;9qD_j315)G4Lym_s&uqR$?A}OAsRmd+m4-OF4FJYuUsqI+JVpxAYC^dOp*|2;!=?1QV$LDO%%%{_AO+*|qe?KP5|muJ}= z=u6kWr39qg^O1Bna9IMeVVFX3`8JSnWk}%oP5T$UReJ5RF9KDP-UbDrQg>H~Z`iE%w*Cn?S~244&| z#~Z~lT>TgDRG{0wG!xJQ_D6PLCm9`pTL}@wdx?r2nEz1S3)s~P=POQM)~Kdw@Zs18 zEe#YjYvYsV!ILhx03cod;Sgad(;zB%TDy zOJIlL6uSY+5~<%J36>zgh@hFm*oKl|s$-zp;PH&St4JI7rm~uQGT*qL{4VSa6 zt}57b(=~|#YvlGI_8f)k-sWw1@8l~?_wk}<@DPHV_tDqeC7&kN2jC6nE-)$`=~llT zK_QD%Kc{f_EN~)dUI+P74AzHPn*O7XfW2PU|K1?Jy+RR`zhRDogwnm{`mKR+{J6~@ zDT%n8BF&5ULtqY#q5p4md;xU3)?t6ra_Rk29oqh20^yy##9r^^@jEOPLL73))2uhc zUo6H3B2FILwViEF=ta)5BFFmrIq+h=`-bV|pT(5b5UUJZG78>?@wC>F<2Mo;2BGbV1jA- z->?R6$;HOlO>Zx?9~Z5CV^li14N=B^YTW#(JJ8XYRqT^^z78F`HF0_VKxq-lu9#dgsqaO-jqsT!Ha+666NU#X>pelN!tx=nQ8XMF86E8nm}l-MsaH7`KZLv<;x{e zdv}K?2W}!gpR={AS{Hd~$(}NWkNFP?&)jQ~&JJ3pw>y6W9>>JF!L8kBK5KW7n2RbXgbuV~sYY8rOKkiiRJ8!~z|( z{e5J62E7cO02|Uj@I|EUMLkVN-cO4E&q$%jmb{Q_5d8X z-~Tntdq{*}Z4RY)8B*anKUe<;@c!dE;ezxf6{p2c2yXFx!9E>C)i0!_z4Y5!Dul*c zI+wtIKjL?>e-!ksA3Za%XC6R{aTBR3Q3?fiBy-Zv7lC`aCL{=VTEG~fnw|O5F}Ws1 zOqDTjO7api#vS|v&Tc>dcKo{i4saggkSuDX7akF+>m&XzQS9HXfguE#8XkR06-LA# zmaYPMQGt_JKUpnk+>Is?EjnSrF@Qz8wLn#Z>69K=9*ba#h#&2x#~xs7xJjb}uJAQD zm87Lg@vQ09&tQv~aGar5-&G{SlY`gs-zY6|psPjTj_9kOjQ`$$(RV2c-|KW>8W+{P zt6ZR_sHfqCq6{QU&`QNmGE5ktuRHyiNSS@B&QC1KRmN?#b_uye(x>b?0$~dK&rrho zdw}$~bY4}gvFVsLhZ?Tl-sdwUgLzYBxn`if$2Wr@!-B&*yjTQE?5P|XAyxUtmhs$@ z&|y)J;3kxPafI4C3-NJB_c1ub{>Du+q2Xs^WQ;13lr+5aDDsoE^m4$Y1x9!1ppl69#B}j%fTye)cDK_*Jbjn}CV%9}j2Iqu ze3RkmVX`Jk+=+v7-gZDH>1=pS{zmP;tEVm|HWWHWx&bqsA)@=N!(xD}g?lL1BE4GI ze8>qJeN{jN>+|GP#Mirhfp+ou5FgUUz|t73a;mgNMGA@37Z!_!Y2Ucyzvh z+fSB%1z`N7<5|3&1@6-dwmvyxXIAVPlZ2i8nbreve7JHGDui|^e_(hd| zLH<7YQzoefFMzS$J!bQt{|>$qoDMGyUXuWc5iE2mxSg8Bm4x;CfhViX$8OnawTQp{ z_nk$Jo2d_6ZaNBo0?_G0+>|5YmZabs0#i225O>Y(abAh^HJDho{l4cW_2RcIwAqnu z5KL;qpD6F`>FPmD$tnuUez@OKg%LquDJ-Z(ZsD?hs1;-BTtZN2FJX=2a~Q zx#mq#2cUWcoz@!6iyOmeO;0}eZ5#tKbqT^v_=f>m1;tIe-o z#z$`QJ6}cYE>2!^)4nJg_sjK$ahx|Ry3#?7;93XzH&FdOJ5Pj8;c_VOB}TS<^NGXg z$c3PB(`{&9NVpayYmE@2ouPBro{S`p>_&SUf8PXS1Qju2b_RRP5@4qq6!8|e0b1}^)uuKf5?tR&zn zW%oWpoPGg=tWYhp@VmEi@|@~kYAHaR9DoQ?nU^nOoYoq1PxPmnKS=4^-(rDp`m7~Kr1SmO2Quu6~3tit) z4P@b}c<#XKv;#Or|7b>~FjM^3Qm;e6*`r!>fC05OCqezEn}n!ddDKsr%L}!QQV-TU zgkKyiSb~LF)xhPFt$n$!uXCMbcxd9l<3xf0dyT>^r0A(F0haKi*bwH#c@{tzU@UDHUdn-ho&R2v& zX(_92j6+(~EAJ`1JWlxl$Qq^h<(4A71|b$s9_t~&=o?M1Ct??NbvOXxk54dNDIGj1$MO%FTtOCja37?E zWC5H!4)PvN=17Sd4JP!2C_e;Q<#9w~;n@C%SKb3*`vQ_EP@uQ=}aTtHm3(wiqm z_@4KuyzU&w98mDi|0c4OCYa&HYZ^!~bo|wXx>ANjCL&8#tAO75ur0w%PPFn-ZJ2h4 zcI6#;p9M(56DhjSZ=xu0q?Zs0yHf^a5l?1zpvd`Ep&QKfmfJT5=;1J5F+hLQ97 z&k{x?E{8zZ{VZUo4$!m}4~vIagpRHCe={841WvJ_>m1ME`(PiEO8*J^YMWG&sh&(X zeF%7{ZnRVH5!5+n)iNiOlGN1xp6AN3t0_8Y45#_LPBT+0P8qvubq@T53vp`kr~CE2 zQ8i2Z_%0vNAStbR+D1%N|F~aB=-w{T!}vj5%}fnYzU@$SH(fiG3}o2(C{gQk)Db!2 z5=5vOeI=Ia-BWJjY@L}&Ug9#EJqgaJ_X!ce?jV-U7^}N}wcyfI_-!eC3Os4##sZ@U zKUMWg=yQdpXBa#Php^_kMIkZs9F7b%^ts|Yse3XRt=6`iVw_zkr@LVz)2cpqC<8ep zn=k(Gq+et7DAYzg9>9>#J)exf<)IJ71*v?p5b>Lk189x_CeAuFPq!&bR{Mjhv|^Qn z{#J@+j(=2d|2EA3U_=*`f1<`HAURAb>Rez(*m18$qU-cc=bhytnN zDz9UEKy*uNTu-NP3w($SxiqL^ek_8s6J!UB-ob1Fl+%EnFTv>f)^|Hv7U=pxNEQ!~ zzEcJ_(?fQ92Aw9Gq}nuX$C%up0_7e=BhbGz%9V$t0OW3|DGVUCC*?hGDg{mN^stNc ze~MPn!Di&@+W7t8?Ejr6YubY)3p=D#NUYlhHjpvHbSY*je$X#IA(XM^5N42d1e8e| zzb?>1uI6hEw8FAVfhmDO-Id+hbj(;IR^fyH(|7kjK$78CIPoSiCd2HCRD?#CIpF!- z%ehiHf%TE`Kp4CLXX$uHR^&Jk(Z<+l;o#-eocFmo4x;FFmFF|vwmbt|DWvw!fCav~ zR6J!sz_J6r9y<41MV3LsUUE|-1nvPPf@Mkvdu>R#GEFYh*RaL&oZIZJXuIILa**77 z@Gn8Tac;*NWrV0{0D~%ybsETULC}jz5!ab74OX~29BT%Vhfe=PJYE<27ooQP5is%> zUW3!e^duqJVL<;XdBvI(t#_{UJ>ud9o#X+TcAnZP5Sv754C&OMOqWe2HqoKFLf1K! zip6ZtZ_b@dSUiz{COS^3_anE`Veo}SU+brkP-;2fAP)E&38*MsN0lmI`M8E0Bw_0V z>HxMRpsFV{z&Q}73c3KU->yT)y#C4QdVXr~{ngXWVa{?Pq_R0|uZ6EtTkFxm2B|PXZWrI~;mnEBMg@sl)^T(hvM{I~7-@ zl8O*L6|703BVRg~Q%)#JrIl zcBxi==Q`DBImY|_5&n1O3Zcj`Ft9JPPtRy^6qfVkr4rDzUv2YI@+0auhw(4--1|aL z)`6w>c8Ez&zW_WLz-$%_vQh3SPB!V2!~BED#wejOAN}@LUjpSKRmRR)4#lKgO(!;gO^2^IV@sc z)iH2hXcn}%UIa+m^s6c+4~eM^CW1HnHQWq~$}w`IU2ntNOmWWNlM#{bgwCnLHqm;` z*+c&XsNBGQcwtwdKwx+M@#zi)yf0D5nJupMIG5w|VntmM{NM*;BzzY4xn()KUty*q z=AgsI(uK@zr_2xMk<{LC1>V4{r?_h9O9~TYs9O5#{7%8&+Iq&;uilv-Wa}pb3AspX z@91bfwENffa*}INqt`I~Mx*Ac@T|$H^zJj>rq;y8`unbtIX9L>3ZKz3SEa|;P@3)8 zX@BW>CGL$ju;)%Dre%Lt!27yfRn$j7vOXJUW7s-}O{%Q))TOz>dw=U&(!~jbh`w{C zf0;mA0y))&#qy$1kR?bCBuVE<;feRfw`jBcnekh9iY*d*Q5G%k z*2}?5YS9hRu&x{SNvj3wvF7)2XqwSDq{6-5XA4HJ_b1Thp^+m#{$PMps`4d%i>oc1)Bgjol6MXC8` zBfvTYN6!RIn+G1){(5Rp3Of}(M!JnThTFF{o94H+U5J1<@#a*DdyUT z^t0fdax7JtpRQX@u;3}ntwNlsjQzI-5Ej8H4%l}*H4I5SpIEl|x9yT`r0mLT3xZmQ znT^c7)8Qi1f&>)*B6+*P)h$hJc{;pkVtBw4vET1wFBu-t$LRrQU=nDpT(?+@n>E?yoIoD2++To z@WEWC@0_px8HZHcFFyizFe-ws@aL!K-hhRLF|uwl3NLf7sIM}u;$&s|07|^_z%+&8 zWoxM70AHs?CUuv-G{_-gmROUKWhjn5gDicl**vKopb`3%oJk|D;!95Hxt)A ze}As4{e2bYL9riN;^VJOwSszRM+Fp|=6`mzIs9^a9Qp07cn%!Gwnu5ln~RA-=4(v$ z{2n>MfXCNRD}$(gvJtXcF^M0n&fHh|Dv}E$_B+fDMI*Yfi#(gi8c_w?mZBivd!r52 zWxZci@+5o3ZskW7!@XVxWxE5*m}6EKzVIyk5u6?>Id0fY?d2Q6lm0Fo$!Kj6urzYu z6@|{hzHbbxq3s6m5SpDYtQ?s4Yz+xi}MrZW_XeU0uZfG!{#1^8w$31tbAnwPt zAF-j8AV1+RoAgh#6O57F05v)SzH<7&FARP-#|;c=T0u!rG@RDPn zV(`cR$~i0!QN$$0Jq$L5DXu_{Q7xazvhI+%$%NgPYv^($nM@d`1wiZh0_AT_5g*`7 zj2uukk0!+7O^@$81{={6vBb?=k#nzvo+d!L_hoK|tx3zDCk#SUZ!D&(ZV%C?J7)|g zL<^S5U*>IaT2Rl>%f*5R(h+OHwSnKm>23tzYlP3aT5AUP(?bUOb#3Ue$oW5D(ka=y zCKv9poI{P~2W>6fNAUF5&Xoib<&p3K#c*4ybN@(kTb)4HltCR+ktmZ=aDjI{hfc$-ntz1Zfmq{#i}@i2_vlvs{Zm zA`YpDm!3q+OVoz@Iw6t$b|d(p7hy-BWc=#U6sh)83%5#6RF4{-29R~0LDShe=?KsJ za-&Eqs}J`zHvv@#T;-8Uyc{H$O0!$Unk4a;a>VTP)4n@eka4R|TcozRh|riUG)IX= z;)kTs_!H()>O{%)#ADU^u3Ya5;)4qfhsA|m+WCLG>+gZf5TF$L6uU~j`?>t05^3(3 z+JR}6w(#{8c90 z#v~HOWyvlk<`|L^y-}TTgxMjh4OcQGYPCSf^P?(I2fq9|ZckD}(=PCDMi>fP+;qEy zAABINasK?WeXhkK_{6_#LGnfv?wJ`RJ5~ADM08X-)R3fdk9ka}@LB4vhb9p9xIYo| zC3Zq&4yR{RQK%BxfLt_Q#Yd?(B?#r#9_=^M&X?ib{BD|F;asJ@0m&S~n?YHo@)D^J zcj_@;kt_ZL;)dPuqcZ&%IN#pL_jnytSIMCEx$ql7m8!>igj*-mxzWZI_ch~>K=LXC zczZpN~ISyIs_$Tc?Wt1%Z4&vVLB2_EV zR{^dE>9O4UKRjaLskp<>N-g)aihgzpe#aotUyLX9FmG;jTCtc9^dU}vre;-iA(HF^<}N!zcyvFb!@;#- zHHXMYI9ec{1_bs#GTq8=v)Z}z_U8>_hP7%p$ zRSafg0kh0;JOew>i%7&TrkOvIqQ~!Uln3yLW~7MpdF|Q@9Ny`jA}=k(=|yojC;pP6 z6I?A6qsoYHZzrE5d5ZpiH_az&pVHc>vwfoYqI8MOQ!}Ct`F$WQMXMJyhTMesPVX8( zeNivE+x9S+?e^;@n=j0dt9wt)mT4H{;y|N*+6EMeVWYMeA1Sn-RFD5)qDwjTzcT4%eB)KH z+iFGh=_?zZPOR9^r zs?QLSU0rr^DzgbpFa&r_0cocHBuKvm-e)W^o)=*v4{U^C7?a02P2TDX9zUanb;+Dc zv%4DhOEKf75_kbb>CKG<`KmaRaZ>^x=#Z zPT{uM3tsG0;|6)Fi!Vs1Odb{rMeUY)Ck0QeUz^8|oMY}ViufGd#>02A^XWk@8@US+ zX$JrI#u8==y>VDs5P2)z^JfFn_LvHccUt@^W5ohVuCd#a8VKCYT}Se!6*2H;ad!8K zW$2Xpls@n&-^13KpGL1UEkoZbWhMYL5+P@dB63TPyBFbytlrk$5=O*D^JKDD;F`l~ zSX=(jTV~*N3@pRo82zlYg_XA?Q1!Q3qTx`DMVrhMg>z?np_G$}5aQn-tMNaw{>{uP z)%@LuWo=(pjB{N`Wh_K;>V`L$X+=hORM*v+T*h3+zB+N&@o*UT0v$G5;?QZo|5|2z zt`T@y5oj&}0iO3&JJ0V=r@?oD6-1BU$HBYHs^GwWSOAW?p&hR8!fLD;^)C?iyhcWC z=w#RKHr0qOsS6#LJ8KO4SSbSZi6*Pj97p$@ zVcgJ&`1#kgo$P^)$X;C$+qHQ@TA%C1l4|Ox^RL~ zUf=NJp+XPg(dzom*hQtFGWbRUwTjQCIdq17OU9Ted}#qns0rMJ-DGUSPeZ!f$yLg~ z)U$-9c#q{2CM6`t%Yg0&*edW%YKwo&M<)Qwjj=oiU}$o))#8el(%t0po>AI@|NfQM zs_8N)#(pna%vM{*-uMp5&ssDkdsUN1-7_!A6PK70!8W>`GAj&{sZm_-uy(Z?k0j2V z3peR_D|@9cP=T0TL^XW`e;kE@uU2-VaLAn95#)e#DP`fjpyIB|u6&txt$WiUg~du< z7pF@bqpdk$|GPrc2HC(+8GSc<-`x&)TuI z$(pP>LJbo-!EL~vGjF6`CJQ?TB^xCbknDfA!||PaduZ_s-o=f$`=e01Rkw;YbD}3K^WLC z(Am(WW7YIC(sia;?!#1%g_0W(ZT0%*790oaOtLYP-}s_f3tPyU4^!Rv$c^s@$*JU9 zM%dJh>#8tDM)dwlM9rN@4!~27#8!BoW@hD5E^iyM;{vdx+)7o3%79LVXrMhIO}+ngiVQ*Q)}ai!j&95kuD+ z_^M0Fh&`|+0QNRn5OYcvITMV#xnNsef*C=6Q!HeG6eUtw!w6~Ah}xax-cxrQd4zv`yixMu zwRR*PqmT}Faq~M#@;tbo9NO0%@V$GBM|gg%xEE}ZpC_z;3{>sPd0a zw*m^y#n24yK|Z|Osp!^I4tP{ac%F0;l9%y6GNHc(EoBOcU!2NIkZ{Hm6$+JNCY_r!#ni~*m za0sq6}{Wv(?qc!z+Zl(V!ASZ zde4QEH(lC=8H46rH0X4VZDO6BLPPM!PaPNG25sIQH@JzizFCmbptC)7gg47BhFh1| z_gneS;l2;Cbe!}IimDPWdAzdl8CWY6I{Sx#= zQhDa-&+9`OXT4k%lo0$dV(OF>F;(Uu8WlB?xbT+TlCcfG^&`FDk?tIAQ}HBi0?~#w zfqU+v!r7M1R*9eq3;z7eaXe`oT&-*DO@ra#pZaYK1vLZ)1W|8yiu>H}GLB!>dYWzt zNVRge-!^~u-;`#;C%&0Qco;6Jf{)OYCwRz#M4MRcn+ld?5Mn?uzt4dHUjVaMs!H$wTT;}TAY(d&2$x-x(;W!n{( zi)%@jMr2t;3*z*XYv(LI;hAW#`+wn-HH0liE@X>Xf z1iw85PW!x8rr%2gvi_yn*+FTw)lM2fl4NMY2f#_+?W)e+vm$%VJu6&Q#5LPrt!Y>J ziMs6|Q}&D&p^luvU~Nz389nF&*ALH!XrH{GIP$yt@I}MRe{I}h6T~$T@@Mf+1nFWK};3p{2Qr@W+)}CAr z#j{w-3v^vayzkAr;E#-#^nb3pUFCl~)R>Eiq;pw?HV>i*Ko_03TPFR7OC}Aq%td zE`YzVV#AXUi)xwQJK7~c7|;1AG_K3%8vm6?==T`nq7@rr1=|Gfl8_A_p9^pgfuoAT`5m1wEvMQQsNAx6M-KokYpah zI$b5an$>)O7=)#^FI8&AZiyjr{vSd&rgQ$gD?mTmz z)5JUa_R2p}#QAePr49J}A1Abf9W`d+kOQ!cb%6OJ^vFmT!{oS=I&UXtOB9x&M8#CYH*Pl(eA{6XHa}l~|LWw4X z0)D{#m7ZWrlON??w&42CN5_0}N#1x;h?Sa^W!bWXIe_Vw7Mz<e6;}BfmNwjmoIJL8K9^OTo6Iej6M3M_`wHr{6eaQIrrj-1F`Hv-`y-d?vZr zSA*(d5!1?zwG0?Pa#y_3wUU)xB{NxrW6T>*x+`{+qM$b-nx?zS-~YvwJES<}emI+d zW0`%|oC3x9in5pki5pXp8=ApAbE#TI(B_h74-o%o?`BM%Xi+LEW&x7U5C0yJIeJGK zY3o65Wc?jlI)S9k)G^?&mxMbfZd%O54wA@QzcpXw!|_;B8riXZ&7@4=&cpGs(K|T* z$+|<}!xb_o;Ydif*0i4IN2YUhdqs-Z#z{B;%?7)DDQnr0R#H?AAXv4>B*2FYpFa@t zvo5^Bnnc*Z<|F-H?>t=Yo6g;9m(#7!4$pX`wz`&Ntww#>pn^rjH(Jmb?EfB+j#~iX z08r$BU>i5ozX57B&YL%*>=|}b+`UPf|7C7)&z$5e@x_exXr zxM!twq+EA(=?xT3uBh^ALPzc&P{w~SDMw6ufrevi=}EalQv@(}vBZcjj7mOlw3;=^ z8yqyF%m<6!{!*wD4F=3h%nVvocqV;O;=C`@j^DRG95f?G^+;MCyA(qhIn zwS=OPDJ3nUyFwLA6W$6rTlH%U%%Ajm=1jjW7(65MN2x+8k+H7C(kJu96db=K^wEx) z{u1d^#vsi@=6wDmQG@mllfK)=a9C@{`45mS@MEt_$nc&V{v^oB-9l3Z!4utlXQRA+ z#~#jillTeV&Su7wKvSnh9Merv9&TDOo^nIW@3j+piv$;(=@k5Qpv*k)3`*A5p~z3< zt|Tmq?7S>=t1C}86zwuP#zxD%_frpuP%h8qhdxOh-=W==Zl&Pg*P=GThpcUq>5)q7 zrEr=i3n1FTxbKeti>m#1iP2~npQ1VE1=_AD|7qlJbnLGaEqGI4Ryv*D9rnj9Ekgf|Lz1Gh^_(Z(G0Be+q5kp)}IxuGK~bLtW_I zvPBTti;|MlPM&xvee$HabLdFZA^%As_hI26DAnx!L@-qvzF|$21u@9}OTr3aNH#sF z5Mo5mgYOX8L_p!x96jKB8l@zKs|QCg3oaFcFg@UrqJUBou76V;DPg%Le`}UlB1kWs zjA$+9$1^lshCBqE=-b%3 zr^?66wg(@(DDB-e7Y~LjBz_buhx51ZSDtiR{%=Ny)zt(T9J`V7`38{-y}bfFzcqf- zG-o7XbXzpve$xK?90uHc(zxGGF zT=EY*sndD9N<3#D?OHb;xT6mRNPVanx}f% z`=500-}p(3iVgjE&w(V#SzlI_=p;&t5zmQS@MVK*!lFd5uPeFrZm#bX*U~SuIwPB3V)nw7bzodVEP#U4)@A=0{ z2W4`=)sFLvA8Vv%ur zCxXk<_bXZU+-yFasbp~2PIU3N#!nO6eWH2Hh_OqYG6G!Y$3XS(6YBRxnyQ$k_r(o= z$o4iJT09B_D=81r$dy8tNtuWafnk%N6br!~M)qQm*eOLU@1F#7;BlTpi4dYJS&pm1 zcd8#Y_@2zjTl+=@h~t;{aV|Qb|F+Z2(fdy)_4ywtA=nVOq@(0)-9U6^1D|eHthGQK z$8XG>7A>n(w>giDZg2Hzmijm#fz!7h9R2%7&o}-3PhhXKU7F{)bLt8i@8^3?U<^ET zj3fD=1w(l^NZd<6&S`RJIxn`*ONu(y-}!)Aak%bXzTCr|K(}y!+sjAqfS#fpCQmkF8F{_mvJB_>->{Cu%p06%j>Q1QTgJrs7+#I}O+neY&E-;x( z?DC@h&uC{;FJ>|=8WG&TJ?rfE+UM!!T@iaEMm0<4F5y0!QXfOyO?CJEUy;8$R`HDd zlL3S9fL~I$Js+)iEgR&TnVI4-Jx@SH^gcz+UeuWprN_+P>gZn*m(Y$qZ*X>WR9U#u z_HDQsUn5!4+IaAi)F5qTT3r|1cEs3)lBVX=@lD}IL(Q_KOM)%ymfsKCVGUe}3y>;~ z4X%T1q^qc9YwxJUz;?2E2tm=cd1YACXzPp><{Zc`oCOMc5ksk?p(oqlWeu$akmAXx zG0jP&+P(_~^Afxi=_d%e&}##e%?5NQd6LE}o%)JoZY1a!%yv$pvo6y`GPc_aMwc>7 z7F4WZgVAsCPeOM*Gu^4V=f>cS>Kz5Nh{Cwbi7bY*>YYV zfM83@DNi8cnYw0Sud8y$SCy-$S+S0TecO?`j*`HWv_NYo&hmiSD~lT{SaF>fNk9UY zclBW!^9uB}Z%;|U*3&iw0Tntc0qn zhewz5OEM2b{iel=MUEEH@7}HO5Bz4;v!2aimWSVQ_Joh5>0A&vM$@yUdIxN?asw{EwJow|* zEvxiZxHEvkjg{3>i>mr-jhAy`HFQpiyp6Ey>DM=2!^Dketv82PL^uaud^h(HwDqf+ZXNl@6)byX%m<(bk_%IG%NV6b4M2D zd_8U0<<}@lj%UK=6FRwGH5sxak>#fh7Rx$`)aMcNJIItbcY6Gh_j)RVp3QpxUsu$+ z9$@4Q2PzfeXm(`MF%69;if>U#rKVBNKkJDdIuE^!w zn>6kd&lHu2mYr!{wYpO25#r$J?su&COm1%$BBttphb|prugCP^ZLMx6-eO1G?ik`q zr)F&qKgQsT@{B0l8IQnvm5D5rv5`{Mt>_2kmwuu9{t`#xmj+^uZfcdLhJ+Dc-Ld*C zu_|~?^yHx;90lQTJ$&;c#2{G^$tFWGi6*meteNd_=2y=0d#te%8!!F0mx>S6+$#1e zEiCI!-oAZG^92xA34$HJC6yqJ!TI__(D}u5d^9BNDi4p0_iGJ5YNlzXqH`}|Blwsp z@VR#~H_sLV=`;?Nro_OW>G!XGdlj)UTa`zIB-n ze6G#m4?zOU&+<@Q&ri#nUxV+lMTXwd=T${Gr=6+@9yd;LUaKzEG27^V$+0VTu>wBP<4B@3SeF8${We(a$Q-D9JJ8iWIVe9z z*@%T;9-;nxe@Rbid6R44-OuZ6r+390Ly?)X?Y2g|BZfila)wx>M9W%Z_{tF8df`sn zg4lU3O0je4?#*0vxWfMI<=u48eiBANnIttqAm&A+L+BNywV?I=|Fezbzy!|BMt6)m z-g}(lEy`|?!e+Y;-%-vp39G_@;_DSsEq8;-%fhFEvGMy7nrwC;uHz|ZnFBmEd<-<5 zUTqCuqN5_d@sY18K|kihC8afKwhpG%lKDSOy@Ow#f7k|`mfaSXz1FgAEw`*Y+x8t- zE!%FjYK7YdG_t6CJe`%k1-n&s?x@Qo3f!wtCC8 zX!)+@iCfs;P${OUg1(JSDMGGjk9G$Kk%6AISJbP$h)4~BQT+JdTUv5pQws?LbSkAL zcBDDjnbWVdbL6n}n{$pR1z4bWSxfhgVnhj|DTLDKS|# zr50;Q?rzkpA^641Bs91Py?~P{_R^~szIrvL#X4SkK&9r=EBeT>GWK16Txo_%lU*y= z@XmG^F2&25eK5|}0fZ7E=TELi8K_nDfh~GWh!_V&K z3;b01^X2@jaBCi|M!g zECH_O@nnZxw$enRKYrBqtm@=Eir8Amx-s~{{VZIf+mQuTQ9m6rn^kE{wq9^m4;Q@F2fey6z0WcldBu3?_QHy>NY6A_ZG@y|n>-ZcjM+ zcJH<;d;KXsz(suy6r!G+0x31JN8&H+zQ-^>Ou5UhYxb|u3 z?4ff(-^ai7-%hu865P2x$(@fnZyn3w+M*uln1kH>mvv>gWM>+N3S_ca9`+OTf55YR zZQ9;bk%EM(Jpo+Qn7kzWwN&uNxzd;(wlQ}(EMe}i^)xY@2a%}5A=xL~p@vtd7AFAT zA&_C-FuI@|{UDK1G%2?|imI@Nt4aH{AQTzXd)NfWj5%Qu3IfP9E{{=6v%YRReM zSIERRG;M2H^6vPD)y`u6A?ZQ{N>CrE`rp`v^$?a_Ji`6eNX+;`n-pG=z6JO_vc>c( zNS=VB(BDztK>w~kZL-;p*v$CIaEVl6w0)}E;9gO<)#;9e)-7o`an-vMQV{&HFtY#0 z;$rtVBy*yVJOh5H>5){I?}?sR<}qi}@FJ;)Mj;1{04*E8VaE40L{64}3rUG%Vi+A7 zJcjrYLcAgk;pYnU*{is#gW=Yf{vpmWe& z4K8@U6D&hY{*ZGbl@b|-lD^P4G4hIYvp5FAYe{A?S4l76VkGNvz}$9$=KFP`FB(^wHRmiX^?l#)y~Q4 zFE80qcY}Kq^&(G>*(Hax7B)0ezHzqACx@m-aKHQWz?O~1y40Jk;%B_v3%D@8prdZD zMv+;`PFMefpqvKv23$FQ-ex^96LZqU-_C)PF(_Y&N37A5l1TH&YSZq6x*w*C2R$R7 zcd%!3mi?186VSZPzGc}UY!wp7ENt4N=1#ke7l23NR&oiTYa1bi21Lm|D)nv9@|l?? zObiHurw6Qaw-<*r?>5Rx6??SfUvE=kgD{Z1@5S)>6)9oNkf8(wC@y(a_ko39g#`YeL=3tZD!@mT{LbY8X3x+Er z#UkSw1p5Q{H>+@qVXD27D0kQoW`CXSMm@qXV$6(i4A%xKe4L=oHqD(Zv$MacdkX#3 z%bloESQOsjopZ;Ivu|+;0ufu4lYi;tsisNIfy#fjgL8`roQha104SF9j6ah8kr7#MOdFC#GcU zM|9ifubn>goD+B6YL&;2{T&|r%Nfg^|C$FMAS*fOg4EAj?CGWJ4ib%%^LkCS2oOW0 ziXWR*p+O^t=uq;+Hw9$dk#3cPrfd=PxucprioO(w?57_y7|7&#T`LHu?q1thY&716 zWNVrI;8i#S-4U3g8%cgiTlqVs?_fu={5ka>kTOzw%j;Al+m$7g*H*^hTT|ouO0Ptd zA^6#>frdo{lovuP$!`-_WL77SV98HDS!?9M8`(~i#ao5m?Lw@|nAn-j1Ldd{!aCJ$ zT6GtK`je@4`Si0>*6tWjMuboL%T1oFZeV+n*Y*^a)j#!XY1&DTDJc-?4tL7Z*!WFd zHil{KryNxXUZVjKCx=1igWvV_3U5N)uzV-r(!tfC$?{xiWWwwHP!`)au7x-?Pv=Yp zee=8Ii%pcSUaJRkafBt2Z|qKDgGCHg-%09U=C}?`qJ@~rrxFdF^6&U8E%iQ$&E4Q+ z(HjhmV)@&gSgN*dCxt7_%x~-CJ-uqitR9wx@FpW9-1B1L8@P?a9qH91!I)-qetNzo zI8$&cLe&|8?)hqHthLAcb@3M9I(?g%F_m#54r}Qev4SC!hJg)dACK(Ir(*kTOGOwd zw`?I{dw@Z5CTVv12|i-krHTw@8wNHP_0W!kP)|>7DTjW;RcJ6~u!D(>o~>;8YggEL z`9;SI<=@_3h`b%^K``pPUO6gdlF5pkMYV0?Yf9x4;AU)h{<^_4Wjq^_vl-`6cA6FGPYtxUgzE;+vm?aE*XHu<>rc zmU9N!-vWBItL{)`D(i)0NQA}4SDUTw%B{f#qt4o0>ER4Hq;u9)kW)BdpyZedd>?Xl z-TeAE;b+zM3N>PT0kuvY@p5h9+ml42I-oEy)HiOeB^88XG%@NHCb}?7w3x{wZ0mpf zt7(L!<$IOzU=?KtY#Fzka_YM#lqoNip@+d0*B zJ-~IVz0XtbaWikJJk34sOmPz)Fbl5XEjTv|7Ww|1-I?roL{)AYrK%m&h0D5Yj$c}f zUAYW!jkIc)cMmprMS#|>;~#2z19~3;>#2Rl4H=&M^V=`Z+{{=)6Vj`}0kMBWSlcWk zzb;gHQSy)l?;6;i2`#?u$q&V<_Na2Ww1J!vOe45X-;bA^%jF)qw(Usjgg!6?6Oz&I1)*T(*E>R-w$NF%u&0+oDqzx=L?Qx`{|$OkkLZ*?YmzJN6v z-oP)wJz&2FEbL#sj$}cp>rIL$PtYt>j33!IyK@wm@t$sft}ySoP|mu_&E{&TYaG1J z$N}Eg-(J$4z;C@(es90eu3^6z=J?(h16wgRDdu|m?H=Uf>*C}nQygJz)M=^8jvTS6 zu(x^3moVW)o8|s;0%o(eG+L&W;(r3avH9{71@7)R2yPW)azyd-_xRoY0G7yxY83;{ zKG31Pa6F&;W>Fu~t%-K|ZcuZ(`lpw0;Z1WxGlp>!5Du$BJ+_C6lewW*+oMH_zSwa< z`$n+dd6otWgvWGduezxP@zT;l+VuUUGS z4rwsUM5OnQvom@Q<43C+HhH@x0jGC@**JKoqCNP#&1v$aXO6+P!V8b*Mz_lwiKBG| zE0FMU;3fOJ4?w*EZ4>iKinFDWps4BE@^A}Ig?H0VGwcQF%LXMN)ujN=3N4RaOz&X0 z&1`>B3%Ti;0{QH6{I+FC6wy%pC(?r$nR`lrsYQfHB939v?)QLBUYn0vk@jfo+$C6G z2i~om<}e;X>=nG~camk6xNT8?T=QABtiSafA+!}2?zcRvs&gzpp8nijVjudpKa*3^ zx;T2uns))=U0Bm9<=eSqi8C&z82s`AzD7^IP2Ny}al774m*?2wj%9)D`$I;b<}UbN zHk=ld^Dd3bwr=xN%&n z{dJN4R;>k-Ala$Z76e{?=Va06Kp-MUI+~M}B&dT;~|2 z&=5pMrQ`3Pb+?EVd_3L{qZKW@6H} zRIsHp5=Llhf&D8>V>zb9bR2(vECKzJ-IraHQ;I-jpNkwqWWw6h5=mT{aZ@~_6GRA3F)J-xIZb3{Nq**t{U!J zx$eSd(|w<#{$4n=GtC;1{T>tUcnc@!P@$1n+Ydx&I*}WUtaXECgY{oGHgViDytfN^ z$;{`Ets+~LrV9Nny9R^PNw#+E^)!4BIEW2?VPY3`=YFn0p@NbQNU%->>Nd=3zo&D~fznzyFgC9^z>=vmJOKXz**RSCuPj0gJPVVZiz z4c$w0(6&0EA{-i|?gIYziPQzH02}kbj^*N*Gs81-*xf}FL-AoX(L$HKRqw`jbJsrq zGRV}+WkXHiWe&q$`F#hdMcO1)dFne=v`sMwNuRS+j9+f_Eh7G=vaJ6KD~=T(yo(fp zf|P&;V__~za@P{02Oiwo=?p=o)@5*_U8UurS%}sPZ&pC;hLLZQ){>R?h>Y$_EsDeU zJxSLEG#@mc`JHlg7kA4S6r@vHr#23s3G1B^N({ds|G2rZ_;E|rx?-|b|54y5JXeNY zE7Z^UG;k0aF+wu}n#4B*QBOmz{@kcoa1YtQ1v6~bbmcAT@6dAkruf0bYE(wxLuH1Q z;wk?!qs;p9=>`!W0!k*>5HFw0TIQZ^1=4TAC+~R+J>}84U_+UxdOwovyi1D+qtR(tdFDk3O+)VEb5V4@|VC zPqMU;xoblg*hSx%zCTa{KPuv$if;UD>2B)T_6yq)rve21+H<5UaJPOGG|o^%WLT~Eth?|V!(DT90VosVg6XLv$QdVbt{ zb8zlmFh(if!`#Qj?^!YUS2au^QA^(`mnm*n^6LB{Su^u%F*BQa;_lPtBD@OYJyj%r z5%eXw58-q*D|1ry=2nzY*tJSwTq&O%4E&1iPRoTb8=vswOLQ$_QWnnjVf*L}4k!#^ zzscJ!gAVp;&a(|b-n0n*C9+`b6rLjb20o}wR%rVePetA$U9u4iE~<4eT!?sKCYaEK zuMFp*6*2){JPK-VmgMj!_O(F$tBtaw9VEVCPH3F8TLNEVu}`_4jp<)voPMr)P6{|) zhOH}rb=k1{?LN-==Obp;Of>Ckz(p9nsM}IN50deV`B`HPn8AVXLLI=Le#03ay6kuRqJ%}eE~gG#n=%|lBjtyg1o2FS)NxRCbn4CWUmDoKfqC* zwS{ruJ_gvcg3K4$^M*#*yI2RMK6MY@Y7m>8r9=b@!x9a#sX6d}5qU8Zi#~N{Yw`9~r`cn1d zP;7~g*5dJGMYus8$Ys0F?%l~SgiuR|bhzFNryIu5T0W401x)wfBg#0wVt56P_Yfwk zgi*x6*Arv&;ph=UkE@Lyf^M#FO?2cBgA#-q3mqkYepGJ&dsV=Qo2T!R(EEKaeO074 zWV2>tVghwiRSr{rz{nR4Nc=wQ_^H$JTyEaQCOXwtI!qq9HZ1iIoRD;ZcyPmSjvEi7 z0~*V7aVn8lUAh>Vk7@DwCiECx{(Fm8{%@5s=AJkJ{hBJt4FUy1C z{X33N9MMwqXON4klHN~Ib$ni3rAV7kK0I%Mh}hI7;UE$M$2;#wh}5(rh1T2YK!K(A zQgWq|@}qe@CYS~qi@43|*O>p0ne$is&qOo{SF>#g#ExHtaq~La50z3=c<>~ByfNsxI(!6<0-}ud^ei2^1ju?l|l+ULBc*TD%x2ug&Os;eU-7l zL!pWwP8yOMX+UW{gmOIfK5EhLMbDk`4!JcK81^xG#f1r`w}ip4p=n^RDIZ$^!?Dh1mLe)1sP*zRAi7n3iJ8c48zUgB9`yHD5MAF zs%(DbN1#A+RX;e1Ylachw3&oEx0SyEyPjRnYD$KPHJ`3B@#O z`EBoifuhMy5Hv4103X$RZzqGDkFMdJ3vDEaOv_81=4Q$%Qs%GaZcdvZ?YbBl#?Mze z*?Oyq{%IN4MrEMOjYccr?6de)WWDvd$I)7I0821FWZsPgF0Or(c4{Q9jIrSaI4iFn z2ST89S2j*0o2lPO-$_Qtp#3Is=Dj}7MV&45t;@f5og9aJQ%C4!qA=FeRDv9dVO1vO z`Qr>vyY2}dD1nHqw2V)_`?GIRJQM~FCg8R*U}|65blCjWm>ZSe3Y@p~dH?fbb51c1lb~-7>?iFsM)>^&7t>Ku_#h)z&e|n9g-cHo~St#X6c>#i@kHWFv2~ zU;G|MCOi65;&#MI#y+2t%IqF3z3+U$ION4Y>V1k!rnWgGhA>O0zYkRssAIiU*oGNf zo*bFkfZXANrt5q7xz9uhL95L(XnVK$iwfCA>OFR86OkAJiZQXg-@-XokS)7(Ieg{? zI?7zZad;o!Jv=0wVH_uHFzx4XWk@Wb4ZAL0FlX-0@|;JRJ!lf-*0o7;4q-|jA)Q-^ zNet8~J?Xph4v@b>pv$a8s`sFGCaiLwNqIaI=EqODSTpzs%$+n-d=`F;H*hhISSv}* zQ+Nrg-P_ak^Y>ubr#^{vOwUr>l*P0;?>E|NhcG=;?3MEHU$KYC`NKNeY&ZgB&E{*L zR%ErLBCWCuOdNC8IHScDx9_nE{@sK5;y?@|s{u@N{}8)L;HPOkBID{sojBocL-;pi zt<2lDmJJc(nFg2kw->H91eK`Lr~*ql#5ZaMQ8WG!ozQ0Ki+87WC4GszO%K8?GA4;4 zl}kb?>=6v%INA?EQxS$uQx9)jPXE0wtF18G<{)1gGi|-wT*ZJwS7;Fi_Qe+p+ zbKZ`?ix<#-1AF}ucn|enzXnC)*)1$S9u3UxQwRl5s{H)mzBQ>yhcG@#-zy1kb-7I$ z5nQRu=UG(HxI*uAoV^l3(rR404iztQ`>G@pQRs*2nc&|FdGp8p%xW2-~osUSK-D|WFCUKT2?`zNfm+R1M` zA{SWJ-sW42zO3@LPt#w0NptUqH5|wcW|or|@4K^Ts7fC;*TZF2X*o0U0+ktST$Id(6Qch&HkXHTxTWJ_KCG|k5Y5C(d#0uH1(wRI>u*2rlsc=-S+FK)$aB)2b1l93 zztwsri4<76@p}{Fe}e>i+`NF^db+ChvTcXmq1^Rt3e73C=VMfNQ-0=#EJvRTVKe@+ z-j#aOn93pjz;v~yTuv*Qi+kEli9`;CTb)Ce8t}OU2dd)wv4H)fuoU@Yp`#p*$ty{- z2~0eH@!hO7igfJ0@2ig-`d8Ujy}e->Q69wF=Q~p#4X4#I5}{Q8q7zFd(4|&`qiT8= zvk$ez!PR>eotC+EMRsG7kUm!D;o+lq0`a$3j-%fL6lrsTEce_9Ys0CSwm)A~ir1UI z|3gw+SH9%3s4H-17<8m3J2$FpKmT5F*ycTP|)`tLC#YhHOp+g#V;IN14`)#RVPe8pwm)VhG_ zE8Hl|`8e(~G~t)pI)++zTZd>9&?hiON23YrN+26dH~sUOIoj~{3B6s+jW4wBi@>%Z zPFB>aVq0C&mv;9M^?LM*!RlBu!Ro-#AM6q)&2)6VS9IGol-dlPyq97%F~kNbulou( zUput+hC6ee4j3#*St^kh@o{@0r_fp0l2JF+az-f%f2teMW_Fv){Ldu(AE*oHL;jrh zd#Ozuo`ca2^1%gXuYU#3+UD(hzA+}=s_y)cKAsme;EhiHhXtX>v(Q)cv=kud?0QvJ zpwyU!)xmdQJWTK-n#bq0*3ln(D(3q8QF827q*R4B0!6UF6f(4)A^i3*hp$d7%OdzN z^@D*N(7C#ZO1c+s`YO5wt}$L#X2P-Fe*-&8+^M-tVGJ0>=^9FfX{_)VZgC=r2HYr% z5h$nDnpiF)~ED6FIbFnkoI#9*bG^*ITywC ze9?{#aa>HCGMc1KE4`A-s98DuP)cNCnZuBwK|r>1=GLna+NjKTv|ZZKK0ib2Q9h9S z3TMT0vM3Yz1Jt5J(O#^;@Aub!1vu+?0}#+){ko|`^FU|Yyw(-625gd}%%}V3%|D0h zP37QgYUHqacsP}WF)1IZq<)C4oBX4w4M4p{mkSkGcM?VIiD|t~{k>T0jI!2l=r}Hb z>wTdqoL{&jc7*({=c#Xno5c$6PWh89miz z1pjM+3^Tru&nb}7v92o!9D!>=Z_l#c<9mCfRi_9#cJFCt*EauY6GlI2le1u8pFN)3 z5Lc^P;s@(Nb9AHWYeCuc*}?F_N}s5mEc1wvg*BphXnql97Ue+*5O1-jUai9rUM$)~ z0oB@KKyN}}GnNfdQ|nG@m*$F&yoiaKf{7C=(obkNH>e7LMSYq@kEp)yI8;$ zr?D|-@SohL2LFNhU)|aRDbFHJT2YJ6g?kEbd@t+QJ$TFm&Q7te97v-z&iw)`0Zlri za-=K;X9f>km5^EH{l8{(v1cYq7IxOlQb7<~OZtpLn^(=^SB147yq?8(V6`8IDrNAH z`4CKq^A>66OBxPWHC(3Q{nSy(s7`5;qdp=ER6YM5wrO0;z64%O)56B~ou-}f%9cgjLB zp?=LIxJTE#7Gn+l|IoMc^i9#hIz=?M(Ki2e)bBKXL$54#6=DAsJn?5IUT}Q74=W zt&mnYoteX-NE(OK{|hu+k1(u_NDe&@XOENk7qfDAr6mqNSd%IGWBGUj|1PZ#JVr7p zI0L1=#Li{h+6wX-Z`v%^lmLQBnKKJ!c4(;ci1rl0ZB-7aav#2KPFpqPDljg!LndaW_SNwqxFR}JK(ms+HwZExyRNHO{8$OVB1h`uCY|wMku8$Bi zzax2`M=JRiH(UuX!Tx7!VLC?Vey?$};EU9XvYmZe8-C391r8ciDEyaJq1=Z<8w1`9 zxM60h3PHn2{_nWXggXowTrn#!OPvF_Ru%0i#H5bMZI_71L?;HZqf|h`(q{9*x$2aw zR9!t=FbAqd_~x8jKX@Of3;)zb2w4fxLIu!h`_7= z#9{1*I)^*yQExb*vllCn;3DTOduI<<=MFv-j{`|U!Ly?rUMw%9D?iq$9U$UeJ(J#$NPhev1mjHM(zs0d+&> z1x$V>^*B~n`!gQZ+w$#3D782icAd6t92i+voe=*ttdB%{{879+$N|jW>V)?mmjr{@QTD zas|Gv3gg8oLNL}I6Ggac?X0>v<$o=_39b{ip`}xq*Lq~oPqnx~gf<)TzJbgy^bHrIu zK(MqDh_Fwg=tG*gB?+?4VsHPUegDlkAlHuH08`i9mE33+RFSew3$Gi~%*_5BUu2eYV3O3KDb{UoteS#=-D&_I?ifQ zlx*|Ku|3i}VhT6JbD5<>{Nvt;sZ`9s7$P;52CQMR8Qe1$e`HnohyFq=M)7ni<>v?Y z6EHrE6gtCI-MG13Nj3>Mg^0EpPB$LCZvRWe;ed$s=-u`fLr{4%PMS{ z(q1tx=Rl(_oDPmT~Y>A_6&0^L4TX2+vh95zD%Eo9h zi`K&*w6G=qzx+N|uZN6cWzKtOI38n9S#2j|ZW7S39CY!q-`VWL?Dzy)j)(Y)>a&ej zXKMskWV@{|8M?lPV6su#bzdF?{XjHi_;eV)?X zT@X2QUEBJa6r_ZD$g39jI4rsJ{~~`6kOjRG3^%Ut{B3<(8}$BDFGW+Zzz%YqGyP@3 zP42t~0o>5J)5!#EMRdG8=p;@+=AR@iq1!=(zwbkCo{f7R2oCu_gUG1Ny2pp|2}Ax2 z6UO!6=wb6q;iQRBU>}xP(K;{$;#mBxEi|^}Y^mT_kQn$&u}x zOYIJQziv`qPruN-u1JOlR~r1K3I4}U_O$&m$3C^X$y&t=MQ%a@(ms#KF3KMvF&{Sm zB1zvm`4jk6N!Xh*=*{9&zkpm_m;5u8re)~CE1TCx4BO&v_IFN)i*T6b5|arQnYG_* z>*L~gX+E4aJ={^w?2HV%D<)sg?E^n{24{V;AQUte;5#{z@`VlPj3#TqnH;`iY@&@8 zQOq5aQGJNkcvL--d9{22LLvRD^WpmT8i~Ny!V!!+?PcnGF(|;+4Qa4V}IY3{wx98J8jpVWjp~Y*d{{eTXF4-77K8UBF=lv=dPDGp>`C&ISkUY35 zoqP9$zvX_u$oA7PHUn!>!9a8%axmM0-|N6)9}&~GPJ`dh8hw~^l_po35$)_|og!4c zXy-!S?c@Bo1_Jb#+T~0Gd_;XrHL`y7zpVSl+6`hmB43G2GETbYGv3)KEDw*G8zm>L z_#>|`JImy$oN4XiEW^V({8?t<9QPcXO?6>9N(Q`YZ=gDOi>ctp&_cNA4o%s3NwLqg zfVJY=yrXY=fdUVRUZ)6gJ4b2(ODbM>Vv`usBhhP525Fa@(3TLYS$2 zNVd0A%0=a>{%ZQSKg3cesQTHGLlh`KQaxrW#c0|*`QeXx2wy%I2o*|9+_7iIpaAxC zDTuKNrsK;?>YXvyNQxg_zQ?%|sOFFc_My5MM(n1j>l|M$VPH@XZ?>WuPxeqWW(C^L zPOsA4G8?U4G`s43^7er%K8~S(3hHuLJJeJ?V49bCF$_LOXh|<6oKo2?pKC4xekkLw z95zaR!FZ*8^nqCsI&Yif(_0e>4(aRL>DoGXOF~|_jk!8%wfa_2l@fO~RYj-s6!^!^ za>W<(+aQR(?7{WHn$jQnEX7qMR8!gYcEt$G|FEn&`nd{S&7*Ij0Xmr_a-zugtvP(En*6JRAE7 z;ak&Ce0HP;jrl`#`B{<>V&zOXMN!n4)DL2OAha=~^fwE_-F@M2Aua_yI@upe;OcvI z1Bl}V>qO2nZ^cJp#^!HhVHU7mTyl^@H}iGQl5b(0T1*SV$NOSA0~E@J5;a{AHXkVD z8oJs?i%|n!()+GSxVY+ExAVp8V;gL$Y=8mAP9NUMk5}F^wzc_;T2kf!UfF-Til&QNY3;Dh;39?QiZN zi3!Mt%eUK?1apjWN53iAhG9$MXBcI=EjJdENw%vaTVse!;?_%z1{C88n$XtR! zSn|79%=Kzf#Ecf;!e*xe5wXO%4<^!f5x4z01RRhKb`CY_gcsJ_INfS~bLo^%d=G7m zF<;?nJewkOSp>&*7&n|Os=oenoNZgU?gpk}zO|HnLqb|B8C z=Cz|$<7BTUrRyom_iYrk$Y>9OEaMOcs>A2zU&{S3ZO$@Ai;vMg#86VllufWAk7L0; z2x~O(*@9cW%b9EY3N=k;n$b(r*}FmQNE3%gSf2xH9G|!-$J@N`NT9ssTmf@&Qlb%w zI}W=NN{eO=HQ$azaVrcXqyBHfi!{$4Hl$e}4O16zVYN`crhnBjRwc4^x6EWA;x}-X z1`QecU&7?}sW<3CBMCQ4bh&0H#am5oP3ED$Wf&@_nA~TDKj&f=hOa)saEv?s*Y^XNT4%IIPr15RBId?O6>q(o-h$4hpp;z8FC@<09yT%vXpY*>!*9p2R z?R3l3$M~QJI+|dHg@mRHP#{6o&zDs0!9X$D7u19&iw#G#(DFdfSLHi5f8~$iZ`* zYhF>lK2YW`GTEebHNs!uUMQ?!K$AsxJF-8dh?}L`Ra*GMU=U##Q?d_q!eg~l=;(%V z8|BA4U^iv>Pemwdl|GX9=}J8l2aGo`iT#+gO5FuUBo&8V&h!~=|GsSYBJ=P9FIu4g ztuI`*DH=9FaaeC7W6k;veM}?E&sX1se50qb{=H15!Ey5Qt2eKXjx9~y`k*eG8x8PF z4&>a2hTp6C%N@qU_4VGuy%WMfy~gh7&rb|6 zjF?b8DC<0TJ_oA*!&En7hhh-@)*rU)`k7Ot@aD}zQ9hz!_k*`dvEiH^S!0jxL0J4w z6z-?XnN2Te*ukq}?)_B!o`8K(qp$yFh627iAbB651E!;>L;$OT} z;@S5jhPhD&%dgN8Mtvr|cn@{Vk8Pa7MvRi1IkAgB2>#b(iV2ae??Khns`VR;PIb2p zjli@GE*i^eic02-xEav8OztzR#H`2bzSsYc$dj=vL&fiSM_IRy=c%DK?Rot@$3*^# zS(fY>j`rIV{&{&uQ}b!06(1Y?k1Ojd@QgnS22#?DR)AsNUv*aTQlwi3m}{v~BNvY- zyxE9|uB&FIsM{qdB-I7=yZP)-`6$$glHe`CMa>!%fdW){#e6)W9e(A+&A}%XHcTu? zK-_6aD^7H|CRz7rHfGNKF%q4@2awA1XDyVn|9w>Lc-Yp;;l6d5SxcAA;;Bq9TR3HDq|w*^DCjSO|#d4xK-OxDOL-IVVHxq{gjEF%SN}Q(qRUhpW*bY7 zfhPT`4E}R9tP$7_$)SUV_Os_VkZS-74`ZBlDj@ZidF>!8?C(#bRl@EK+?h7Pj^B-c z=)smJQ@m7;`Nw0cSY#qb(|BTQ4BLNuBBDBe$eGc-S14tZcgx5}t2+Q;^Io1I>o&Nh zA>x)YcN^gF>;T(<>aM}xh89_V9>{#pTqW&XzWC(AOxAlUCTQ}SC}XzH3<(N-e2#f; zd;~L9Pil}y){|%VEl&eazJ1%2iyQos<&&K=Kt(-nfh@KxU;fT(RJg?z4!plM?I~h< zA?k|YZU{hX%im9w&8$On!y_%)872t=Mt+mbtxR5wm z*<)DI6$w@C*ygiJ}WuO_Uq5}B|${Y zX+M%)TF`h#8y9ZiSBNx}BoMPp9KvKI`n-D?iQ zo|&)Dpja+Ko2NmSR%Y60@aak;t>#<=w_Ji#t|rkNfU3UuqiCrMKRGZ=nKH%N%DBcg z^Z2tZb&Az)Qgc4~*pRy3W7iygm>hn5>oSR4uwFjv&QndS3t>BvEn?8QUR9mY!Ltr= z+Doo-e4rW+ZoVgjP4rXOj&{BTNDr+oUYf*~Z+BZm6i@`hj*=5(0T*<~) z!bLl;_I_6njqZToODzb9-FtuE@NRkQ2E&~v9RLsiJsSj>S!GSE%*_odZ}e$u86v4| zu7NqI8p-bmWTw}@ps)cn<%fIS8m}7p|oNI(<9E5|88UELm0Ot&|B)q}sN>u=xA0L{&$VPoQ`LDou z@hCTq1%8~O+9)R%(f+n4mU=pnOArz~A&N#|!p_H1 zdYwtL+ZGy2o}MeV)Q*)V-5vA7GQnN9#vW5m$iyy>+cl<%QGT9`i* zp$-GADpWwdyuOX8d-=>+-#girBwvNOkk9Oyv`W6L%vovk|3_(q0Py;UZ}SeE8J}CH z7b(#y?-s4kou3|Bz3c64#e59i8kk#(4h)(6(^PZlyM|CnQTwh zG5Hs$h}?D63D?`Gvda4W(rBS}OEp|eUrI)oN#JmoU!F6es*tum>=r5H*qpTupNnIg zeZRKaCq(1hjTjIf6t>J!VEah0BROM>k{L@>0G3!M*3%gyTfwjzpJG;D(=r|v_Jyhc z_fCvA*UTqe%w-tuc)gx@w7f!Nr}qI5n|l`5837i$3xjAmxLWa)h2g82^>mpb5~I8G zX1TQb`Uf4t!9Cpv8O1_{7viRQ&avU>{(JC?@H>EI5I|}az8rq5Bi{JV*N+eY)zfMHai)_TIn#xv+t0Z_Dd z*LyWck>AGfv51mbx3U13D5OkM{v@-GdmsW2%r{YzjCRQx%J-< zvDWyU(|-fWEc5#oqes2cBq<+KBMLO0z(?FKg>S=PfyxD_+yosQLaAK+({&A~N#ij} zt}Xwc9Y`#tQFY_%dzN%{A<-BwAuo>`RKF$PyS{vvQ|~2(9?uoJ@N**z@yO)OdH z`BV{-h8d7!>=_4^E*Iay$7Vo(#nIGNAXAHL4I616wECnoBu!mOQ5In{C@LcXxyjew zM~0Qc@UuSRSq|EgT`P@_MD1(99+_p$=Tpgi>DbIW+J7e5XE$ZYXC)JuV=50}?cscD z@~%x#{mZKHZN%Z;DSjy=0=R*kPHtp77WrWN4uV|eW7mFYL7+8jQt``m+VaV}GwQ0vMuT_p=KzD}(J_cB&mRb7K;dok zIoLarDJZ_95=08!v(lQx0wySrflV4*K+#ML3BD$5{plySQj*Jw-3(yc=N0a~+QMF# z^Ts3Jr?}94LCuv2AgqW9_@L^#X;heqAd(ldD&)fouGKhVYWQ}zgS^M&-0Qc#ypcXv zitknq7+4~G9!I1dEmHHnuri^T~mV?uoe6aY@5h@9GXobw6%U6 zq@{rM>?s!Rfdt4*!W7fUG#Pv9l&d&s#3L!?;{d2#Eevhp4bGqFYuNkzr_@~NdWE>u z&PHQ^)8fX6cHm+Eo+VMS>;0B(Wp61dg$aaQqnxS`UiYi0cO-%CY9#l=-$V|i{#fW+ zPBNKzTK&}er4)YO*N0dND20T7W1ImhLAv^+#s$%(h(pAMXhVPgP`jNsa!Z$KOWuEq z4M;898CZ*wao(PRIjumdrCM9;QLBS~Uep<6?NahM;)OpH8_oP=JP5n-X)|b{!3#~D zR5Q;Q$w62s0>>bdoU9D#xQ*S(e+ye?$hLT28tly%_bJ=_;{PvY^vnU($lt(%c9 zr7z3Xr~)o+I5{|$%hF5`>f(y@J-u3o+761EdVSF%p(t9<8{U7IDhG|Ej|RpY87n=d zG?~gbS|dn+`blm0{~_uvAENxDt?!{rLJ(29J4L#?LjmaqLFsOW6p#k#7LjhGVNijg zyIZ=uhv9mL-#O=g-oPKg=6mh6_gbI5YE0SW##>|g?d3kTmCGf`4Kf(XyE!<|-s1E6 ziz$@r@gns}+OWJ5sG_J#=mzqBLQjYO2LtBF)vM za_|-rnXcdmaN4RI(rY&^is%JLX|GQ$x9X<6Or!fi=!=1n{zK`&F)M{ES6s$FBt#>c z@B3qu?dCkQ{KAqnqn%_M*}A2!%gbz~QJaS%bX@1QRE6cueZb8*1aF=MJ#%rPs* zT03<#;mH2xo^>$|I1PV_UN@bWgC8cufqrnE@v%q{*zKVs;QWvHSJw-KqhUv%yry_9 z3^@Uv1ucwY4-e&(u8bgPF8+M2)t*`&*=a2WRHc|INm%{OWbL@Qu&>|9yc6gM&04HP z5?qseu7zI5{mdbMgx!32_Xo4mODXk%Es(<6dlfaD^iew_Pqx;jCPrOCE%ar^1bVXq zaUCl9F-+eW>bb3Pfyo@aBG>6X(4Xe;)=#dr`!!i1m%1Fw_qypScP(^Yo(*6n#Kg8) zB_qa(>CU!J-H8@9ZuwjMR@EGub98=@CezZH{-pF;&T1FL;hhJ4 zTr9148lZ@y5l{Q@@e&|4$r#9ckTBT*sKphl=#dDiZ7P^rn$@lTZDyNz(LcLSz`E-e za)MzUSi{rVFQD=MSAZ=bFzNGFd!5>ydtSk1X+l=-9(=>bG?%XW_pk3PC5)05jQ(+- z`ew|gqM!;T;G=kYYn#{J2cE9X{NRx6agZ!&Z?xqe-^lp5aHe9&2uASqolgu?*+r`L zHjw`5x$qn4x@m0mHhAjDM2O#(?Kv&)=9dckjb~p@`ecx3xm{^UJZ8P!JH)AeQ{I^# za^$ZjHGyAL{vs?BF=*F)WAJh{&hblG=~nrHjK=?abs%}bNfK&JnKbkr(A#sTS5?2| zZ8SyfbY{F*FZZRn*`~I`XO(Sz7JLy6X)<1^^naXGd;D(p)Vw5$UhiEaW-EsS(Ii|U zLGnJ-1hF7&C~^C6&XD%+W%O92%`;i**(SD9TO4{?eQl^Ca*!n9bc!RY%pb&+I(kfe zWFb(fBb)y*@}aDBg&DHo@H5H9qFi*oidPU5RcB^1wJUmo=c*YXP8$iLUHS1{C~EJffx){xJoicM|gD$#1XH?Aif&2{e!w~ zA1r>Wa`jx@tu|i+ZT~7<#QNi$)i1@08&;BMtVu`^C)ps^V48ph@#t@*8y_pP$u^>L z;H&Rb-GOiMJb8(^wbEBpt^N5@6Ge~b?SH{DpZt@#Dqx#{@Cbtf_Zq`LOUC;F8ZiSq zS5||xg@+!SIH`cbKw~%+4L$6VeiQ9Nf;I=nLTQ+Xqt?$EpnO-UBsHg#_)XkBD+mcy zf5l7a%e8@7)@)y6ZX96NiOfynP1qWT2e#BX+yW9&FJQKQK)-1rATxbFc9|+U@S* z!HuSXGnY4T(&5i85@g!*7i``p+UDAhf;d}t4RTMFtQU{j{Msg&pzXTNumcJ-+Pxp{ z@WS)tKX%3=C|EtKE=r{Yg?S?#1@5n)nGsXAA_pT+R5?pMZ~v0=S(mmhYQCU}hN^}@ z()K5$HYAUt^7Hu;DDiz$+_#Z8dNvo9^e;Q4Qrx~o9N6G^ypLm&yk14$W0hu^|^cX^9bh`2*#Q)vf z0r*#2G)+l*zRe-HSZOW+{igj@l=xMHVQa5_zs5B^b0?PF_4qct2!y-4)C(5Hf z);ts#&Vi>mzxXM%!b_0DJ>>rRCi&y)4@DRlUDMyjR28$}aAzGT(8nsyBX9LId{|uoQ1%anrK1u= zw~ZzWlT_vQ&!*70V%><%3LnAOzy#I3%|)1!m~CO&IqS#$Ds=_6*_+*9qC8$`VoP@QRd5WSJOTdjx4H`@DH^}{)7QT|0zdYLu{rb2kjAo5q z^IIW!$llR_c?`2l^Y+I@JH0=NG=^j$EESqzCyk}4RX6E>jnbNqnyx|7H}V@<_n71B zl*kS)?u&QDTtql*-<<~{+;L_IESDvhil|Bqv23Q5uEN2kK5f~kzjHw(SXC(TvOlB3 zW-tsJcA>kH%JmyKXCzC_hYr;i62WL}GY#&8wb5g2WL{s}e_l@q@s1{Q&n#D| zNq*UHLa$;%7Cw6ubpGnTr<>R@H9+Fq;hQte83D7GnFxb>=c7|?9w)3b`a9Q+&{=2) z-Xe2d0j^uNwxJzRJ>a7jz)E-MyW{is?rY^O<+M0v^fmaeh^CRl?I93~dfI46wK+Yf zW1Zsk838N}7&B(PvW2iZ85`e$Jwd^gvdF!Xjvgs~`+FXbc^koTnVaIK{@O72YjA9M zIiQ;xdORoaNySYw_rT767%@IBmLn*QZ7zB287*RykWQ*QeB=Sk0) z-kl+qHt$R-mCxaj8&{a3CkS$0^VFOgjDW0>wTAZ9Mko;g6GN^c-y z7TU)z)s>3+fFo4srTGe?3;m{wva4rZaZkkkqJhAyjD)d9Eqez??>)6`?IB(by5LYP zOEOZ!MH_K;(h075TWnWW?MpGDw@h8i&Odygi?Qs^)>8N$myuQI7P^oge8L&QipuFK zDm?ipP5*MPTlQHpks;pL0%3nh-RA_T3|9&laDjt&G3OimIN7Ih;( zdSook22YA^762PBiNGaFyk%sMrf2X(U@;t6qyy6KMk}$x5SEiVY$E@}ek(#zI8{I< z{Wt6t*_0Qia4H;$nKqCLrs3c|;0iy>TU-a)k3F?~RPPraS2x10VH2(D=bA8J28pSI!J*7Zmzn(56iq;RlP{==ldCO&IcT1`}V$JP|IISsZh@2N%EZf%K~^+ zP~AZk)?XahJT~!9EoK5bscZPva+IYH#n&cbX8fY2pK6}I4NrglYdnPSJbTPe^!Ax$ z0=2tOY`+Ih9{l@?-eaZ5z3Z}JT5;NHcbWuDWN`~VfQbCO40!4h-bx_fls&+}fW#x& z;+B5OhQiuM)lL#*9^S|Oid-h;GXq?Ks1us<-uJ65fuQhRFSCpgI>bMUPN6(DIReW_#)V}oFdc}t$BBto&po%Gs2|yb;wL1gMfLsSAyBaM+~Xa0^Uh2DC* zsvF5lXeI6TN2$KICG#}#AG4cXu!jLn*Ff~U`7II78}BYbvoslQ#=@D$&RYo#2;B4_ zXjEMy{Thb%2$t|{x0mSggC<;_Qkt%Fnvt7%e>O;n(K7`3|F;=a4?j z$1e}@_g3U(P8$YdQ>{18Hg!=WAvC~-f07{7EulP5hi~N$Op{i14te|%VnJdQfw(^p zmFUp4{-3xhB0%UDitw5tGpbN9aEdRw=FG1*47zlza>dyNIPQ1`e6mcD3stSy354T= zcMud6SPJBB-R7DEd<9wH{Ae05eFDJs0zr6NMc@l)L!Bi4W*(hj4 zPj{N=0e6fUzKh;|7UNISv7*~)iL6OR1ge+gnucyv9|~cCbPhh-D@AvI8*gL(yk0;Q zNxqJB{7Zu8{*OyJ1sdb4jQzhX4ub}(oWlDLtIH_)x~HEArtFVrf{dQGzLSJRzfQdrQmT=TRA}cW|Ulxtmy-XZ_i_w1~lsM^9pKXuuxK+YkO#O>aB-HvWW)Ojv zl=e{I1P)mR`@HG&+?W6y)E(Wj>2@Qz=S5Zhj_t}n-?{DqkExH*P`z+9TJG5uQDu@e! z;mE5Ml5a6=37B5e`g+vk0QjOlW+ZnKZ_zy;XX%3;oKzl19sA0Ye+*yDaR~h!3>8hd z5)&JKSf!<*5E}t%H-Ur)`oGgwWjA`C3^`cfN{g;a)pS6;&ab^AK2qrM(>0`3Br82wpXd6CF8uY>pNid-}UfQw-xz_~EQT1D?RKJ?iBhSG& zz4-6OAgn~K4`BiJ3nf(9Yxtk!_;%`Z(Q83(K6<7Utv`sNALw6&|EQECgU_N7Qi@2& zEu+r8{+?fjC7i~|#~llL<@B)lNpQ;IOphRZX#{UZrIrb3%z`mgjN9Q@;>VerfK2$C; zB8jMC{0A_3iLoCZFxy&rgnzaO!$P|Uqy64kC~}kqBonT$2OFU>U$1o`r(ncGzuXp+ z_^*JUgFfNFLQ(inIFNSY-SHW7+ynI_aQbV%KLMf&uucY-ttNrx8H#uxw)SKz$$qkE zpjf`G)o7|r4+of)>p5obxrPc^kbBv|%oYjQK0cD5yy+i(wxR&3;dSqyG#^~@-UPf8 zfY{Bs<-iBNyHz{p4W)C)@HsO8vpbh?Q_H@9VAXDI;QI-lLxM`S`2T-C!8NdBP{q$3 zBUw*=vsK;yE6}BKUVmQq%7o$uBk%9WuCc}qD&V-28ZYe!p_?7U}_HIjmT2P zdYu~?iFUd>79vGlW8Io_(iduU=`Tx26crs#8jVxt)05#MnPb;`tA{g|%=nR3->?y5 z4lV0uyreNc?cA|rO^yDdZe`DP&NGB+27g7hpngO;ErjCr4>|9EQ4daMdGYd2q9l4t zoFxAUR4tZEet6naUIaRvs6qJ~@>X=u$YBtB?+b2LHBLw`53aU7sI{(WbYHher!o>kjoY@UA(LNXDwZ>#p{ZMaT!OGadC7isSsxJ z<~*ia1PkR+0_)|t{+_Su-0;c(kfB%h^=z5Igk$6pf=*`p1Jbwxrw5Ux%1i=RxB8xh zVJS-w?$)lto!Y^Uu`czD)4iO(MpkQy5|P%%~OD2myR+ghnzUV_=Mq&zjutW3++@d{SKav&{+ zI5On7BHYyA8QW@OF8Az`Z@0@O4wM#FG9n4!drn>`FkX!>5W4i*K`9~tGLqI-&a4pj zM=Heeqri)oyF+c*6cUEap#yJ?fh60sIY|o|`WM(z1ims?qf&3Q2gocZ#{BvSKzGaDXzJ=MU3pCVd~?}>_|R3W+f zo~hZA;DZWJkD#@RoKF6JnKZO(s2N@>s117zvts)y6REoMPowNgQEm&HXE>Jh<-D}J zYdbY~o>9k)q^RHF0OL6Ip2lWIw@uGyWc(T=VCzw+a_xDEEThHLA0*h+xC9Cv;6 z;uDi(wQATp?WAtAF=YwsSZ{e>pt1yKv$U3AQrvtCfXY?m?4;eFW@v%G#C|;!3RegS z{!}&Fo$)A9#%@@aFTnUt>^BP#pOmqqQ693f!hHok*5gf)^IRSF%&MT>doC)6QNA4Q znPJoe8)zt~ux6 zt-&##we-7~;$P+U@i3|GP1tlHY#DK3r!dEs{COX+T%E38YgzDcnuKrsmIiY(D1GDs ztaW~>eoCRc?L^u$4Q6wzlkK1hj`iz?g=j{<>+_#6f+FbO>DG)7ZY2aeqUD}zi;8b_9_ z)!B9k2rVxgmq|OwMb1Ko$TQKUy|ce=Ba47$$$B9}!mVvjWbjSKqV$9_Q-RKe0;R+j zIRg>aWRlSUM^%*wHw%@Lwq%#+_{mRed>ow>joElDNeL^*S>yKbs_ZMdL8eV+Pl6;_ zj_*qE4BpnFQG~54iCT=-aub^9R}vT@Iueg#<-V=3ZeOFn;jenasCO`wpUuA1VtO|i zXwgnX7W6rJVkO@4pOc!Ta_Rt3knfk1KZlkYj`wWS!s{2KL3X-Slk6qEi>0<7NO@A9 z^m2nE-0k5z6GlR^EYCtP;a6wA1L&m1eE%Z++QW@NoVX&9f+hrU(@=yABJ?mmC{c|G^zTkOv_ znRB`_G1Ca+)2z)@4dReu>Rb|+Z0uL(WPT$jymLlIiETkR&~Bh*HE;LfhFrHd`^o(&N?-reim#>spYT z-&Z*?7T7m*D|k8O`HDaC#jMM-DeR1;mr48CgFiHUN^b<4=g`%#rCJXUyjQ^(W6or3 z#X0mMCVx7EP%tS^S*c>aS~?vxj628iPj??b<-nh;pqnr$cb}JI4$0qD{*HXm zrHPG6%(Q6*RuTvv_Ar1*lt96VZWEz4FxYP>y4unM;KM#74d8Q^N{WuJQ9!S!&xfr? zJTp|6m1h{8?r-medVkkUIDVe1{X6#+)Kj$5ZOa;ZuZw(MqQL&?p^UE>)p12W z<~mraCKQ%L7r_cv}>M zu1TZ?WD7rdpA9W^*e72fZd?i5qg<0MMMYlUld6b=Oo;DD-z6HYqb!hhkJ}khNAZ;m zFK^T5JdU=G^iT~w3jgp-5{=^pH&h8yWU9$Q6}V zjsVKI1t@%s(m&jpelUFPrwBODE5*?jD#u&s(I-*Rk8IU?bb441#gZ1q4`wveE7O7L9vMIB6bLg7QsM-h*w^kmCpKr_KM4-c+5kn!SxN`SrvI*Y z5cuBIH9_5gIGye3FLBMd zi139=E$(y%T|`-&2!8G`(LL7jb#!B*q{ZjCx`eEcj3Ojy=$h5|=dKQZ|8JVTy4nxq z`5_^R{xm&bru2{75{xr89Pl`chFzUZdlVWJ36xEJ0oqNee@eT7QdAb&c&zHLIfLN6=od($KgmL9EpJtDx&wZ6Z7e^nS~N zoHR17F($>AhfN1#A|AHmo7-=YaqaPwpHaNFgxcm+c^W_~rzgc2mgk%g@!2Y&>3j5ZyBQR*nzgzgY%g?;dkVlmRW3F%@p!rF1pJxqH(+?=aGpk?Wxuo#I=ojvs-rJ1rN z_^8Ln^+Z{OqfvRJV4c5;OMekybD7>;{?eKBBN!s^i95|p+T&NBpgVPK2B|UA3Dkq< zfV^CYxW56|ul|gYVzaKy#bNJ;Cw?E;NePda+Me&fsXyW|VG{Y&Q9==-SAkZQ`X{rQ z%ySqX@}`l$=rtmi@j)b+In#>1ubJ`7x%%sL5SGUu3VsKAhiE~R&6I(D9?kV$xYT2O z{gD%p=kV0YR=XbjL+rjt59gKg%zujnP5aEARBKJm|N1C)w$_;dvn(A<8@-lHMMQ7^ z3v5Rqo*>{R@M)@fag_$e$N7A>nGCj|vb?(i9>EU+je{2~P)1LXVLKg`M)qu+C{A>= z&X)32kOXq(DYJmN{VO8Zgtv!_2_5=PJA5QvEWF5+YW3dqDK;J}=8i zu`pEp>BNgMqaS1z8IKMRxoHh02E7dz{bMcNCGFXgcEr|V0Bp!;4es+HWpSCg_q|mw z$e2-a7WM1t@Mzk;r4)F*IA6sTe?1*Ar#u1b2y(3m@;KB>Y@I#%I6Ip{FwVXq6`1Fq z`{tDAkx^y1nnv-@O*EE?{tveK&l?Lf?=scm^!pib1#Q4K!x7bigIM8x-===BQ<^b- z`E7gAJW~$`DBxfqv+pE-X=d)t10-g7BDIn+e^w-l-8Vu@ox8>PkHjatRP!+LSu`Fb znpNAsN2#~bJ*cB{5`#*gVG>+1`rxmmZ|+Vg{B4Vwy0_IRuPobq)Xo@-edCx9n<;TD z#bJs7*HJcn)z8FfMug$YM0Lf+*+n5vHsIr+;+49;jDHB8wi;v1bHyN9{fdLQU)NP( zb-(#*2$XX&`##l^RgBI&oE#Kh5(#I!zEUJ&u%bmLn!Pg(IU9~B49dkKWx>qm~=ks5Z__LxYV^64SYe=RC|x?k7}qB z|Ka&n2U4+io(M-P{`4!o&dX2gV_##$C#Z6kW91rZdjaxjio>wn!XlpHx^LhGAkM8(bRA9Db ztp~gOOoWXuiUSv4YB!m5b6BBtVFbxzG&oY&>=l+*lBAOhn~p{&RQzyIGgnVqO;@U7 z9`O5F3a>Q>wwWMD-~V!@6>#RsUOeRqy)M9uTV9&EMh{un!&shbj)R`wB!}||%yfHN zt~M3=2RDTUA6aA5FV9d;x8RX{cUN^nQx4gJmPwS6NQ^{fsl29tH|8ApHpKs+vo*as zI(0VItv3BK@!F8Lmik7b0G3k-+)Ed}f)pJFay1Fy34BR$0)cg6kY8NPZt|{?Dn;;g!wq zKV|`vd9uYzi3rF0himZSqp85t+X6ViS2?#|kJkEU!ErRxvy4YXANX$W$*N2xpk!7x ztAQ84P7r~ExjOJe<)8ow;y!Ob^!h%6HE&6L9s%7`-;xVeX5*e{Lq+HLphSM!+@Fn# zT-O%VCGeZA%CLWsHVeIg!SKeFjq1Z?N8AT8H0>5;;~yUy^{p6w&oIyJDZ37+pGNnU zy1hebTCp~4)5GdR(v%foyrOhqwdJIKMSri%8C;LLiJfU(p&Z^Je8QHlv_vG1rJRio zawe%Ec2RGcCvZYN{mv=b_1&~XtZr(zEb#EdKS9B&C?x6Ft7_Ng!`2VyxYy=^6LN|W zNxUzFA)gn`(}eTEn0FYHVd_x&(*ABCbg@HCO_Vd45oYApoiFo>->SX$dW$;Fnc|{u zIJXh_yX+Z+krw~S_jd9#jN{Ri2)yuGT~48hnG?eJ4KpyEpo*tvXp~2YvLbFgPX1YR zE8fv6eeX-y#)>vF)6Kl+0;x^4NBphoea4-%dqR@!X8 zSxr*XOL>zMJsAaOyGeik&|Q8;W`|sJZlJxD8pfA4o?Vu*g~L1**>bb$c$fznVf@z2DX<{-a94!I*M&^CW@`I2#SLXxluX%0&!T z-5;*|p;su*>>3aRu-=Cs0m4c{<&zVAPObl3PkAmQNfM-jru|NVhz`UNhKx(AX-b&x zQKCfc)HSQv3mZQ&L_yIF;U?RgKBcik{wR$}KHC@`6oc%|e~=eMEZNpI_O8cPV=>?R zLqN0K8V_uZ&Zr$Ej22`O5b9svjx|I&E8?ma#CA!zRI)DC!t%ZWYB-+37bLAvxG?MKH%H#Yd8fv`SNMI~n=t#i)OR9R!e=BBENyA!f8XBD zuOg!TC%_X3%d^cR=BOu0n&$+(H91*>$WgNa z#JpND+?+KOH~NuO7MUhzw3VE2+H88+8M~Qi{VgzKSZEka_uI=fUo6qgkvTg;D7T8+ zG_I8_g^yZ4Wi)II9Pe2(X1N|p`>L;IrisplTZ3A=uTr{Zcka&LA@()V7_~LBaHJyg z=h&kOd9-L|+9QH+nF4sCobrsv#mw{EW*44j=8QD|jW^;95%J;}GFpU+9@*C@$h<8K zH;jfu2~zYxQ=>)M@L08hEjdquFWvmiwaT{LCOG+Fl>W;raf&HPffc1HQ0KC4+#*kJ^_umUfoCd`J5$oqRhb? z5n+`=S1_6^Lm-4G3Hp0&1SL7lNPmHq3xymJ{G)wNMvg7b?i@{QdSD#)!Ax%fZH;%H z*sh~~^lJng=mld~9{nS&o*GD2WeJsH@#XunNNRzVB1r>D_fVst)zd-0?^hsvn5|xrr(EBXg23aAb4yJcEn{E?H9Aucr2MD#KpC0s%gmC0*pIf67 zlHJ+J6`+JX~2;}(XyKTo|w(Y6l z^Vsv~20zu2wr_d*5~NjU2(+#(FTT9#i^x*y?{#1Sebha1+&_g@xSSv7rxKOGh-_=Q z+dY`mNKWD(_hPIgl$>Urfb=yp!K_s3?-P&bb(k+>j?S2_2tQIUZvJ{Z#B(lI(H}yZ zT)2<-^;e(Hodn6>itnw2gz{OI%NlAm#J_bn$iA)0?aY9Xed435jM(`%l_qcd{r@}w zQ*fD>%aOa_Q46D=*Ano;m$g^q=g-t$3gx-1CXy&C;OVOkKvqO_}?_gvMBi2UupLDPq6)5ZUMK3n&Q z{PudDe>UXyob{U%^6l%CwCkkWdv)wg0^y9ed2v6MUsatKgS4tC@F{xQ2Fftmx{ZRb z40;@g)|U9pv0^gt%M6g;`Zp$xA`XWxN|V1nWw55zbkx*F#gmL@FHqS_xsv9c2T8rT z)D+>xGd4MtX67jzkzq=IOYlh9$|X6IU#-}ujqTMwVD@Tp^B6g_tZ)$$3!{}EsPr7h z{Pzu>VyAjZ?ZrYi(`bGJrQTA=0@=8A;V*}#w+qEYSz5lycARq*bI@eTG9cD5C)vxKCJlu3!}$b0W-GZ?c@JwvB=-eQRX8k zD(+HwT;FBu^T8k{<;aTJy9RD95Lg<()z4+a>a+&gCqmG(vG`rn!9P;fd^gdaUvwv1 z$8@FfvwEc1j5Y6m$hSfMQtf%HM6(F#R#NzWD|bVAq&IwzW0)-~5*hK*p#K#ofk8*| zqE$id57rJr=90hA+~&e(=j2d&fnEAl_ryLOt?zG6E}mb4H&z`7M5^^+jAhc<**w#k zvib{@S9E?qa;3FM6-y=*5_XgEM2K{_Ri-3Sqp%wEeZDJ3n=tb(sN{nyqv;!@FThtE zx7;!k*1_H+(%edP${{TTvMD=d@WpngVSr}yqfIPh7DD!m^Lw%w3@yi56hZmh^)Ad3 z6^Nr3bA{ovw0Zr>Dk%^KzyF)%J$WFw$#TF|*6`=ezq-$LqfLztTsb%EP00-pPG_e^ z{r*D^KefzUdB7%@14;dA=fnQ_6B(dip%vv;ha8U3Q@pJHDN2|vq4dVx>f1h854@Cv zWo=l&+B>Xft1TslLEoZV3P;#K9wBL_BctsnHU^7FYqIJekeZ36tSX*PeeMA1@eKt25NR~{BRWX#2U*pZ&Sd0EjEupAJ)@^x8 zc^LAFN%btNCGP_K)@NAeJ#K!sQrkxQ<59o5@s_x(VB8WXW>Y@9s4VPXXKaN=P=)3D z7d2cB`au4?mfx{0pCDs%HDd^3 z47Ty)IC!E;K%#-R%Fa_!922Ah2F|LBrglaXx6x@n-K~FjPc1Win*@wtU*4W?NUWX! z9cc>HVDFUv<;A5NmIlGKY`<*Gt0NmF$dUSYm&WBe@-ex}sO+S#o7ffG)xh-1djMUDO5d1eQ> zT{%VR@{ZPS)|6VI@9(epO6k(S0dcr})%QEMb}}0DdoQ?KE*Yfr{9|aaV8$DAU94eC z>4&ydvkxn-F^^~B8obl>`PaI6aUkQ>}Up_1KNH2Ngg(fDp zMcZZX7el;IfJc%Qd7UcQzgxN5F47YjZq_)~vJ^0JK2GA;lD)AvDZ!SCQ@|PF0xs2N zM@E)wTz z9(wS3EO&pMvm=$BSGPnz6EacEv$SZ;j)v#mUWX zEmF?<8jCOX>_prwBfKcnn**MAHCwvCZBf8uG8_@;zS}Pcw~Ge01$?G*aDkB^f>kVt z{SqdPd07~eOS{3ZCix!K*^%;W*+Q$chgZ^58TlFvS{37YZw%)aBFV6FS>`jeFQqr$ z&7lO89R;AJe*X8xS^C4tEWa#g*O%5gCFiq+1vJA|na5w8QO(h#t|9%r!P*}0t_5YZ z8i>7P-YJ$Qh$97s?@s*4J9aY)k8Ge-pEs?y#&J%L4=Gb?HnVGRLS}6D!crAO8uFAV zqMhvQ7h9RW#ma=*RggOtJjljo=^ z)0M$p&7;ql*F;=D;B_GHy@eE2nbOxQ@Z>l*vI{lW}2@6{9p zV^eGU+jLR21rjShoV_?bbS#8M-wBi?_fZkQ`Nu5z#-lj7OG-MmHm$b*0o-OJ`FY;1 z0@w1uKI_CXHZFkp+<-;}97Fr^Y|@v?lIvP7Tbl3HdjhAK5~V!%{;hB3n_wcbchH|6 zQQ#R)^(?$6S@oZ7@njchTN-Rdd4;lB-NMwlC4^N)fyB9BBw=?}jd0Z=yzHy*5Z6~y zx2_P6iTP7;AQaU{h89JVSKk2~*=keYUQ?#Fq$LGg}<)YOjzMFn_z6@xowy|KmiK@;#&djXY^- zifw|at9bB`g$^ebsnbSnjTWyqil;+1q7BbYUr%{IzT%dDViAG){sT?Q`@(R*m9lvbX5_P|Ks$mNBUggat=S~ zc;na9WWg9Y601c^Jj*?KE*|OK0;gRo>W?S{CJMo{u4WF`nhBq4^FH~mvhV$MG!X`jU z=chv8Z~X>L#4>G*zh}3?$d5iA(6-m}%dZwn1i26Oj^KEnKKG~WE*jnbAwKC#PuGK{ z*}v@Dt1`GUzD?~VeN`#G?23u>zt;s3^6?O8s~Bx?3sS9=4b3g~0wM-0Y6B;|?UNAF?@ zq<{K`Z}nIlYNh&|@D-+Tg|fzZYhS*G0)ysj`t;aV=ImMZaDy0)AnyZRjNMpC0F8FD zqmH^{ZZAA&*cdrhpyXfy*I*}z2(5)c#mCc=xrnOAa6hMG7@9l8^lwM(T{DaMuGaWF zz0%9&jmn!K@-HJi&$|?}J^7~S&CJvf`V$Vd8(Zo@ku_~Q!_*sXeJddmiOfZ6h9}q@ z%l#abtT)u({`PvG`}W0Bw0{4csro4#<*g5naUk^%--Ji)EW@rO(Z|>SL~ZNMvMYKi zueK5M@oU8C4Bg6;^PDu_rq;ZVP$kB0YGvE$Pp8zX%?J1zqKfQ3$WbA!{)A{o)aU*$ z$adI*uH)*;oCKx8;xA9>x4(C6B&Vf7!vz!tpa0o>;Z;DF=63vZC^Z_UrAtk$ETj{E zv(Znhb=0o)I|Rp?fBnO&R_*xg!tEIiMdsj6o^HpvvzHW1pHVqR?x!7Ps)IWdH%V*T zPU2@M?CF%UTITxhSpl2lv#ccgQpySeo#P6f>OBY^n2P?hmlR8Dp^-+$-=#tkaV zMe}VdJZ!@@3aq-9Y%vQ0*#((l21L0Z3M768)m-c)cS05e#`YG+%W7s$rv5+Su) z0)|9_{)*Qd=jvbuJr7a+VKcimgWhJ2;;X+CAr9If$fQ=$JcLu$OB2w$D!y3&vC9)q zWgQ7AX0K%ELnFu^GrQGe{EVc=rafN&ZXnrq6`F}eiGN= zwDpw^zlde6VU^gH+oghXg(+A`Oy3iZ7F51XlU{(%ZK;1uPEy`?!Qbs{d(lzYGqRyS z8(DD8sXOO=EU(zcAvDeC^h)4UwUvWdzR!FIZqDnl>cN-a>{o~zz?z&Z2vI4KkBDA& zq!t$!$2fd)4bHJAK5>0tCX%5?P98ojp{mEj!4BM*Yr_Q{rh`hkK9@(iU8*-V&%M)K zz4G8yv+YjryI6@_>99`E7I>X6Qan_E(x)$P^ys(_bgc zMccZx@Ba)bzbSY6?gd5b)j;o2wFTW!&WcV7J-4Kckuk20v=N&zS@5t`?foXftqlzW z9k83J*}aCLwHR=ja}>G^!R#@mrW}5~K>==NQ0a@qm)KZbzowDPv$mCdozMundaof_9UEM3 zVw4<&oxst{1;dLnY9Orh*hK&H;tHp0KaTyo2-xV)i@aG34YEX@?oaLSf8*fBVQK$* z9qXm$+)Cj8)5=-wjSc+|H39uL^|gUivxq_b0|r;!kU9g645{?Aih|bNYg_!rT^#<^ zxe^;s>7U#5QAFt}iZ38;2c;@^iWQbtb)a{;#IHO0K43eam|8X>-sL02SP!!0xr#)d z&0^Vo%;1ZWfS-g$q{``!szA_b@Cf{28>eB)_h5 zK%MyRj4DiaFO27nuYG~JR!Bjw-WP0rq_FvC4!z1f@ zO|FEtu+eONIY9|;-GmO#xBPA*1PR(cBdw80JJGZ?yE|~MvHq-5>fGitTb75Y?_KcC zzxLRJfCM8rV*=<;UEgF<79KHYFlbp0bwojEFn$MIzWTc`fM=yjs(7w9pR+H}_8f|U z@w!NoB;R^0O=#XfC$FnHjLpz$D4J2Hq4@WCvEZHi+M8B(=1(&wF!P1 zzWWySnFQ|ERMiygqS{vYzYh)kWq=b!WQK{+CybV5rfrjGVQav;y{0xgp%jIkGE}K* z()^#m&*at2pgLCdpbLMPglLjmz^qP^RM4%vzbPd8bPe;XYQG(8WYtt0i_aLUF3}st zX!iC-A1sAO?)v8%xHvk4^ss$}`2Ac0Fw=7@<*8Til}$jdv93%sIz;f9L1jQ6-4Sp;x~4`+fa2hr6VmU4Glk-w${?V2-Ub5qf7^&F7jr@j}F8CiDcc?CSU_$ z()aU05J)COf)+n)n(kwcfV4CSh)BoKNOyNhcjr(FNSA=50Z4bZ zv>@F`mr?^m3=A;m8{hZd`~465JbRz@to2(V6kLjtY}vupsEXCH;td(XK`T~7S<_v=%q_{JjD54Cp$-5*li6^ z)hJ)um_#=66lAts)Aj{Zs1s&W@8YsOikyk^@AxQTX(!*F~7Z~kN_+R23DY7%&+{KP3kOoJ31+}=7jZG?iKf2 zyLkg?0>UJW5|1Kb)~Fo9vqMM*9LMW`>KSbe#-%jlNwo~)bbXy))tklZoa-p_4c%9{ z_g^@fCaXqy=q}StzYH&S@5|gPka~~mufY#}N6TksEzKTYEbhtz4*ANQF22-_+2k0O<5=di%uqF6zbqUlJcyR%sn1w>GJdl;Q+7?}Z zsNyPhnK`1#67n!*f*Mj6GSzM#5n5GO+gJl0p_i+o#_Vlqm@GcY%?W zY;>Hqil#r7psePj=?$TfEulFg8wX>NR&d7O%u5-I%o;@hx)?rVK%{_VTB?-7%aYTpTMy z!bGMC8}&20J7WCj)V{ssDiK`H*l@1_o!H z4WW}OaAm>Y?&A%r&tfQB@!DU3*pmaU49sThU^=`-C$sqMuepDLAh*t568zweEzf4F z=y(r;_C=?R7dtCCtIqfBUm*yPTA!&zJjrzj{h^)7swbA+pDMW|nz3i|f0lXT6^bhP zNi3U#5yIb>9Bqmzwi|*M`Soh7Q`8qvUc|?;-A-?3w!MkeTIcF77IXVS%&%*b*^8ZK zz(20$$G$yXF14)r23x|-Y=ldntD!3RB!sSlNYS{m$J;uga~IzIxKOXP&2mwHm^r`= z8$t(pNEjNParAH8*+iescw8j^ej=t6{B%gWXNWwl~ z)nUdQ*s8{uF?rzhDbL7#CMfoNQ}O|i%rej{K4oTqCgSX1P+FnXJ=#`IYYu!oktOZW%Ucxq-1S;u4Pf~LL1OQ~-_%`r8Q8GjGklp&sWNp5a(+Ypa) zkwTI28bF)u%x$4!NWs`KTHgo*!N<(|{TM7bwK_5k1lVm z{(k3m;<+$}eeIgV?-^?EpK(o~DfCyAX8h7twhq~?{Qw40UOi^-()HzEA7cC#SM+fJMAC6QDeghk}n>$I(V1Qayg+8u-LTXA z7oClK3s}L9hL{gJnbpKLGO}~$;Bg_-Jg#*7u?6wV&#gE|llm_P_2#aKBB);&N-42KWA`8q+&_qqH__Zw?t)3xn~jOMj`{I+w{oTmN*3#Ny$x)issui;5AU9@P$o7f zpUxJQlbam>6L00R{~-iGa958jz}(>B+4!dLU(Sy%VeNdpN1=M5<%TIE?7e`dTQ;%j z{{n#j^U^H?!6omP$15}IaJL+cU(I)*Ffc(p8^~HNT!18&=eBhs?@FY<)DwPlu64o7 zoYznV3G-*jqVPOX_D|px4?v;io)Fgjaj<-mYKWGzyPDI+#-JT=D!!VW;qGZk5Ko9< zvK*t@{P;!ct5Q-?-V^RCOiU}7g9Pcf9d~A@yf5o`81x1J zW_%kP%;u&!{uzmUm?k;Ze0NK3i?DLVR`Vf>DJ-A3^GH#dKYt|HC6O-MI5v7>{75oW z&FdmION-pnDr{s@dh`d}Epr~dq&WGjTdKch^cz6=QOij8VeW>)(0`;LdSp&ld!XU5 zi0i-kGBE7a?GZr!D4|m+oN~K1&-!?YQc}X&=J$!uTKB^{+ZMrBvB)&xT^(|lEp!jB z1c#pf6J#>h!m+P;88m|~b}$#4xw%!^PWOr!4{vi)P8jn$?<1lE6TjD+zx*VQNC8#l zRgv_eST%E^3|t45U-k;uTGFvam~5E;REr8Q``nCI32NlO@x z2=MNWc2`Y&mp%}lv`go~!{)%GfnwS5y^z7}K2^a_=QT6Kra&XA_e)T`VrY)Cr??$S z8+G4vw{O^*0JpdVQGpl^sJ6v9s^@O7gKlw)bpn3lH)vQ($#M!TMoK9sJ|5E!(iJ|h ztcA>&>^>0c^i!H2ViHs=WD>60E?V-m-GVc)6mtuL^&A#@RK=SAjvy0~HBWbryd74v z@@*DbrfJF3HBbRV9-%Vp4egZRS3b(^O`;^;SpnsTi(;;M_36V45-WA>b^W!?bWsm+ zADf4l0?j!GnN9fEDDaqAZO0UJj*5h+ZLv8haj-wLJXT9#`9$6w$x#G&7*VhP$2fz` zrpeuJP6AUcP+I&A)KLA0{`R(8TJLJh{6_4N9l_InSc*$H^631&abcADA2axcAyA3@ z)n4F6yH(%68N>fKfciTAc_N~|;m@-cEAp2W(}c2D8%R4mM~|wkFwnwn?Cyj)`+ugb znqATtve&_&Mjt?XLheb$>qhV5E5;hYnwV_)g91e+pZNLf6#ZEZtDeK5JUQId6H>udtRq1ZCjrKlsslB*b ztl^FjUP(H!jrFo3!|1-k!Pw->`{sbpYKm^c!k4}PAKx<~LT4#E!9-b-5E`}A(bYX)C!d41NZVw;GO z##vzM=}60n>RXhTUog0PHQyt)D1YTwy6fHqbM*U8p~OfSgE76$O_+$M@=qTI}i7#xUrMj0!U0DP!R}Wmk@W66-kIQfWxR zPwk3t`w)*SJK*K!2*tMYjC%3`YgxMwUrS*hjcUqYcFIW+pP9APszgk}^CM}FpFPo| z->;guO&lvTONWZlkERNtE2v(7qwWys zSo*dmj~th~iZOL9X-#=(?QWH>t@m$R7=5!vF|jgtYX!b*MQ62hvg57+n@fO4!Z-vf znOXM1Qrj;6TK36{lIY*oZ4|w?qc3d_Ufpv5#3O@rBfkQ}MqU(zW7kTDi18OR#ie4# z0-Mg+9h0HX>D=yLzyq1f-*<%}ur4_%h_B8^GY4__E}G$7?I_X5cjWH6&nu#M*q12O z%r4Ug%Mqqhocb{ZkGCHo#rrZ(@#9=u#lvjtJ|0a_4;H}DlJ89EO{dfw zkC0_eyH&6r{J?Bt-J5&xraKIRl<^++AiPucBsdnk5oi*Onw}#U*<&rK`J}W|0xxSY zMD-l^oMNY=pp%ax_nG$mCk=Md6)S>QnCHS{wW+YNj~Jgb$Xn-X60ES;zAMCj z@e}ZG(7F$MfpQ*Sh})vN#JhW7AddT`$m~T|(D6gjV*^{_FH_!FNAIJJJzdQ|M?YSV zu&43eFDug2;T-!1N&S37XVn-`bEEbCWc5Aqm}l^*N*g4&`6N{1tuvd=a(jeE78TR* ztoJ?jNp{8?F$UXgk_-rGn$Gb{`HkL=CICMwgJDS6kv7D~QGK9A zey&X+mQxLGX)6YgxrwA}o-e3)uJ?f*7Cw6#3}e3`aS-FPF_ujwk%ZY`{q<|x2{GDt zD~x-AN<|~}6M)}ToH^|Xz3|jSf)`nyu4KMn0Y#e+`4>La*|)tPVA4fjDRpuI^R*u$ zhV*X>-a3~VBqm(V?Ry)aSX{9QMSiFVx=p_=bVAf#5T?~b|FdHJk9DCH09`_b#3MvG z{E5if4r?ZRlS=u!yu6AQ-T1>v7fPOvxfn7Pq9c z<7rN=*rx067o>j%FP&hBZb(0kp=GiqNL&d1fVCd9S^Z|VhsqRZhf%gDzisFv-o?5p zlK_9Ilxnw^t7N%^I zWFu6VUtQKfnWGsV{%J286)tGKx}a;1bPEre6T=(TfUk1TzU)a zj((?OU=YVzOzT2x!b!2~}7Y zZBzO430ygq@r~aFXl0BqhW`o|yG)SFe)(w|5OmiX){!>i^wO#SlzlsGJi%UjWVB@X zisz2=+uiF=R>2NyQZ)fgd!N2l+z0{#*dL_lC+m5o3bccd`1+-y`b;ZuDDn#~6k;`5 z9N|5)Nqlswrd0vI{{^W3vy&D_mN=-R)DC=O{n%@G*rOi5-$*o{)t(5&21EIf@C0rc z1NeTSwzuif>a7&>Av$kdpWr<+ChyE!Wnc;A__mo?JY5^iwne~?^RfiM~Wxxy1a#}Vs}nOT1_*k z+0{~1jU;+&Y|}^D?u*^u^wF%ek~|db;BrttN-tonkv4EE#mWBOZq1XO`%|H^zOjib zuX5<8fy#B95}sX9Tl#jfv#vz5Rz8ic$K24jv1cO&!Yl8$vQX_&i6sQ;90q16^+)h7Rj$@0W_zfRG`%|@MuTfj4y}qHV7>hs@MtF+4&iyBzE@)g-suo8U z?%8_bQTP>@VLb7BpOEhQ65E*1Ecg~|R7ZB~u3h-GQuvOaw>P!($f}!vm((tEJ2iN3 z=3xln_pVT3DPikNT=(r}SV;*c^-?8mNhHPPGrjEft7|&$!%F9>x^7}Ix*F2Fc0$B< zw@AK;lZ+imqx{wbmDxR$P$JT>VKKg?;|5=3BlVUZ#K9@f`QbTY)4b3S`2+Oo=2OZ@86DrUhwIR3 z2y@SP6fE+4B$fr`JxwLaNXMmOx4N4Jgn#qBCQPr0H%T6!FA0GRb{*-xHZf!j$xvb_;a&2%^pdg| z{KOac24q;y=zDZfH)DGItKw9oaSlHjN7pNuNDu|lbW*WqDCgK6^C?&TzEIe&yV96} zMdYCPOVQ^ZoORm<_-ZQkp^XMh3t(y1`>_=Y2+!A#2WYzs4@{PYVsx_mDxE|E*llR( ze2D~Ze_qQlk=6Kz4V{CVBJM*-PtUc~8t*^?({gldvWst}GpPcy_Az=_FG%^1+VLjC zLX@ajxew8tA{Z^C%rT7W+!iqv*15YV{!WX1ICI&87AAx=AC3xNaNzvmjxf^X#dyCm zp%8up#xa)b^YBWhDG5kt;H_;m{&7#%=62QH_>@AN_d3Dz`HGtp*M#cC|@quF9>_K+{qM&9Trbrel*eE(q%Qu?cZ-b3N1q$KX0KUeqBGOB2s zLZ*5JXm%>}zZ+)cTWSrNPn zEENxl3|(=vX6A(t2~!>BHA@dOBhA%5UZ(b5Om6oV64fx$4KJryQW+6%Rx|rKQyPgNTu(c5*VDtzR+h4==f6h%q2%MKzZS%i zg1-$LESY=|nV0mHUt2_&A3yqr|5eTG<5qK{m>W}k|%SC84oM$>~|#K{*WZJCn^cO4>_tLB5wu5@is z{idpIu33ca_T*_Ep*tGqfnJ)PwoR&%SEs5^U^V0oe~EebjS)7T-PM4cUnPk6!cz<$ zVo4kunpLEADWfQ@L84!&cF?hPm`)UvPsXH@rPr9$7Jblo(NS^}>57k2U!(U24Ih~c)shVFk_GI#O# z4jhHgLs~V#PkI5%Q$v|9)w=~y_}$4SfXusF($_`=>b8R{LOQ#Dxikc~UP)Yiw)F-ZSHNU4a1OVGqG zhXTVvD20g5Y|V=PBFPaGjhFefs*DQX58P(tEJ260b_e#Gavaa!PQ)d^`zecs_oC6lbcW_>1rfw z^zOlya#8Z{8NMaOyYe47ZOC4N;-&r9*#0)nWA3EDs}R!~35mwgH$78*od7%CM?c4c zMg~~NCz5$_nQ%IA_MD#KA>gj$%bi_>r##5AYV(WryX9*ADKNc$1I|CV{?C)}9RPxO z54mSWCt1sCy$w{W|h2>`l5h>W%{csa5i;HTvS7>10eU*-t|w`<+V z1q}0=eRfK9SLoer!XJ?|?HSF3Wi(fFTse}LDnF{Wrbfh#D|awoKIL@g8jyWup6dEp z7S)IX2aTWEam-xE=zVRjJ=0gS0A&>hiYDEjj|&(vt%c6Ht4W|mFB4n_Mx*{JvqLW7 ztL=0h-4q_%9@FuV<5=pr)sDeay!`8AlLQ5TC@ME@SyQWz=FbRoI?w9jPkNly#d@5K zmY)_*$o^<=v!Oy++zb45G3nE3e~!`Klil;IEWI1AXv@SyuQE^t`3-G%-X}5GyYB|~ zF4xz|Pp)&DY1ROxk)|CaLB>$pKO52}k;UU3m0=gv%a2BbiAN}?iEhJP)U}OR$KC@ z5)p~1OBZufR^mYKy&Q1NzB-F`{fkzo{)1uhCg;uZCFn%XFZ3tipEf+9DHRjUl(#v* zD5gf^_rWwc|97zVld%7a3CO4@SP5t~=f$YLeJRi_C|^zR4mjx9X3**|$Ll^(1Sr>d!Ir4KrW+35Ub>e;`D-#$S3wr)JY%v~6tL}Uk| zB+6E)G`$yd-}S}^WC1$&&2Mc47?!+#JB{R%T8?F<*lp>viOOV!Xr%|1D>n~+U?Xx? z>?L91(nUzmz5_uD+=owx1I|WJM&9s$8OJHT@fhwEXo&NhSiXb4I!(NyY*ydj)??c%XvIh}-H3f!L zTOfhjAovx`E!$jbBP#3Cj}j$3bE3|JkJJnuH(e}p!Nv?29LdlESnM!fZfP#)pQ2>u zMdCE3QSQh;Q%9RV@}8%dpdmeJ{Hi%sd7Q(8l4u57F$_wnJXuln9A zw-TE2kugmUYFLp)p3lik?@fN*xX$z&)#&17;Y$t~=WDRYy_Gk8j=?QD5cNtg%!1q} zR^shGAhZk5sd8DD)OS}PI2i0w#$b~0<|?394Wqh`#qACvHB@+BOsqnr=Q_A&4ws`w zA5<=6k3=OUF5nZ8tyn03L7Z4(p31{m1~t2`$F40Jz92fG)w~Aan`XbiNGdeZa~7|r zebt=xzuwF`v6{5)6nJXti-_$ZiSku*<=0CB=mt)@)V^P|LooS8k1hm(49UhB19LS% zY#(r+%4PYv(OoSU|EY!r$EF1cC~E~&dt3jxdyv)*=q&|F#np8_-{GQ*O?$ZH8SzdmoBUdhY{(*w&64q?2xFO6S` zc==?i5gr^xrTRvReOW{0_(+HK^p;5wg~k!*`f@|xQf@19$YhCdG{GZd;Xd^jj^px3 zCL_e{hd!=e_Tpuw!J=(IQ!tj+<4O}>$8Nv*$QL0~ocM|xyU>_~Z?sYg78PFx_hmom zO!ZtYv5>W@!0y$Ii^`KH+p^~g9MEA5z#ncK`86{|%8PmyYw zkTPu6aLHl#KFLkH_RFD@hmCD25>Ac%FJT3N+G%=@r=HqSzw8<=XS)hmI}j%nh%ljl zzs|7fsP()3iBr>Q-UxUBAA_+m+> zzk5L6I;)k~6QS0i%x3&X49De#^{6qKrJT1Rd4>dgC&M;fRv20k>$9&hU+|X8r=(O6 zhpF#l{Kkl{-jKQfdr$n65CC^XZ-ONJ9k*g^g00EUjucp~;P~-2V4=m5R^0r43ULh} z^amdY{e%9E7_ie+_d_T6-f|7N+k9l$3|xQ2-m(boutcpNA2EqgHFp}`wL;~KqCWsw z76UtD9E#h~y8L`s>;pFGmhC8*-i!pX+0#O@U_|%InNL6KO~3v25p7dR9OcuS`x++& zPp2@x*=mDQb$UW_9f6Rygq&v#A2`HO6MAZS9l%Wx!XwX`k-nL7WO}Bn^`7G7&u0c2 zm|l_j>NaP&Lw_z$mlcQ2rBuO^)`)r>8qa$(Rq8i=g1I@JpJaZNPI73zI8q2xc*rIB zwUWGCy(YczK)aA^MD{7_v^w?s(H@S-TW14~O;e(U`s}y{nlh%>GVL@D;pn!0u^|Gd z^YLUwGe3o>nG-jWw+~XS4V`+I@zf7hhlX;~-W5B)P-)bn>{FqGhb8kA+{M)ToVM}Ol{qyVC|0)T#@+|;^ zQg6~ff-8onLi+{vA~_}O==x?Wv}?O-#TjhA*b;U(9_(I(7)AW;g?qSWFJ(`Gp+Nni z1!4;pZU?}C?cR`GzkBR0|GQgNGP>~RYE@E)f{YEJeHg5|zSt2bo+SBx^BJ93E7I=* z9M~-5>3iStv2d;t4b`ED>7Ncpe|&@4N%c%?e5diCqeHpBwWiG05Dh^iv3Qz`t|xfCj9A#qIll8jlzAo_CstQ5 z>m4*2{H|VIcrBVF6@V_;&9VD(&U~`VH&J^EbGkHKF;8ktTYx6Q-v64folY7nnxEQZjXs+^*gL|y*US{2|^= z`^YI6m9lg8(Q;SZUN zh?MW{=Ap*4Hc#j>JgtkMj`4EAhM@Yu+bjvcWBTFi0 zd)=7O3!koOk!J2XDCme?M&COy<^DYO%s#diMMlrR6y2WD3?AAH;_3A#P=RuRqv$9j zso7GJo1_v=ctfb~dcy?PcpouF`;j!*f3xLq`9GFrt475M?7d?ziR@8D%J^tf+ZX%YzHpoRRtoGCr;eohqUOHunSlhSd z`N!|GdcJ}~Hq;LNRO0;y^*N1}@9o({l3hN<`dA*D5krb;O%_uB!PBIKu zl3u|mZE4O^n)|sVtI3!{i7 zH5!_Rc&CgXvwwr6zkHXuSAP<|;gi6mH2&U@Y2K=OZ$;mvcI-W=LFr2V2}`Xw&S|h~ zr z8KIf!Jx^N(jXb|eniK9zpXhKeqlb5!SghLA9_K5DK#)q=pY;}`Cp8tY4En*lsU)h& zFo`IVGelK`F|3>eIY__-!UY%+ou4JGIcY4E9}TPs$DlbWF#BE^$HW?!PY#72?7TjG zf*+|RwRH}TmdZzvo`VHaUzkjl03jeY^TDB@Cn|@hfPw|nuztZQ;B^B=D%-&BH0l0% zvY!KRSl6`z)c-tc7%f3~u$ZQ1PRBnJXEH^?aNhI#&4sK8&?@qJNGd{N5`#1m`;y^l zKywVQiq6`I;l|faT5Gd?xr20IW!U7q_1>#hkg^=h`ZLnK7Don01|)w#tV52h^S{@S zWh*j8kNvMBamxrH1wVm4`aKI>3r23=1J%P^tm%4TmXE5y3$xo)Uj>n#@t z74+Zr%8#!(T5ziCJ`z%~!n$e_7E~CGTkTOY`f5*i)G!E~;PCnRx z+V%%m=V_vsdlw4rp6=rI95B9_FZmbc6S*BNt=DhXmiBqvjUUqvcZ0WFLEo;ZJ{755 zBD)&8dtF+1+G_^-L=D&BD0uoPs6x_Dq;VpsFdT&yxLAr!AFY&6!&{=69wTmu{~$;o z8CIwC@EhX#O54o^KB>ieX6^s9xF`S zV0LJ&lN&DkKl4R>!V_t^msUmi+_bk@7M#Di>Ru-7Q5_Aivhk-#>)WFO&J|xpNfA-V&>#|MNvaM9-oRNf4Bl(cMptMM&V)PIzN-z;hJ;2{NZA7~ez4e%j5 zN_rmv(FZUENnfMb)@JX0>O+kz{>jyPOswjn1J#d&+1?oNgG#Z5%&Bcq#0B{G3&V`ZGT1 zZ6s?d9|_2nZG?oB31!(^?eRj}d_JB|3|_?+dMn3N_xrhk@0PhxbZ5M(LpWGf+1SO zykP)n|IP~tLnS#YOC*E%UP=6OfIaVC zhyq{U1Hj>tC!M5k;9dZd%8i;tq_lksTQFnvz!cO%Ak`v*5?(|~yAoF|WQ8}Xbv)1s zJE&?0Gp<`Ne$+*`pHSl0;VXt2-yE^&`ei2sAI<)<(!$#_r|AGGSr&6bVV{E2V}%lQ zCG$qPGi%B$K;8cP1K-jfER~7(KL=#&y1hm`Nx z!fusAh{r^T+&zZ&m9|@2H(T^89u9${-i8s29$-fJ?oJj3d|i1cj7Psq+_xUP2x`=) zSH7EIL4{o0@IH_4(EeJi7deB)Mu1x+L5ov1u~kK-tTHS_zv<53i7H8!&>h%~ShTqk z-Xr?5R3#)OFeaW;| zQ`4G5qy2DtRBl zYs+3PWh~=N*JE;yGa~u;_h&$rrErW%{>uWT+uq2kf#x{FLxg3J_fKG>^QcK{UF2gZTptwuP&6^-&yYX)z9^+c`2%+1kieiy!8(*%JAeH_p{ntCky z8Fr`LM%)YR8nJk0d4xY!-Yk#T{v_H`ZNGUIH*$;a36r)W?Mo?VxyTaTc!QA~H4;K5 zXs1I@+8QS#puRypI1odi5Vfhf$?Ax|#YZB}GAa=>(S(8H6~l`=jXL~g%%YF7cmZ}X z6lxfhc*z^jcW9JH;8R|ukebd&e#pGGJXZ5#&Xox#RqiT#x45Qk2n%G}=CGp0;zKr) zjG1&1Vk2ZcKfi01H3P$MSsmKiz!rc$OlDbAzVBC2fwcFeZ=3RFNH|~g72*!tm&uRD z`HlQR-1ZJ7YCUN^fo_tgP{pPnFSkb}qX9U>3eG5jt2Rd-Eu4u?mW*e1o;Z5KFG$DN z*uI3mz~c4xz_jcBZ1IAu`{_%;8x%DE_AYbX@R-U3>FX6vm+`SRsZ*2iuGlr*$^ z(Q8+2mBu_#E=q>*qu))<3U0sGgLpTXNY$hs!E^pc0s%jiS+Z{@mbVvoWD&n;LL)I> z?ijYDGqkuMh_?w7qg#-#(IDYrg6+Iu^&iflJt;^j-VC5<$HEEMKcWJw12|| zHHhYOzjffo7Iov|h*7kit3y5r4!)LrhAjSs>)uZQi(|j zzfyD#RrMFm9Z0v2@i7>2IO@I+_9v)O^TTJTaHY($>Jo!>e3m!_no^n$QtRIx1^xHb zv^?}CA<7>&4OVciIQUP@INg;J=6r5LZrY6x$NU`J3df*Yk9S6{nj0;(kE@#{QT1kPGlVZgxVBTVzS`*D&v1b~#ddW1PwN_=PlaFD0}AZr4KPSO16 z{9}Hkg6ta37Er51BTn@r3#A#wUipR7fv1XeW?BGTQZuC&Zxt54qC(>4MDL6<@h)9X zoKv+;kSAvxD-BnItPTg|(6LQUMy60%{EKb!KnSy}N>Z8<+I)I#TFk4-!hl+P%^5@s z=;vW<7v4*5bp@9o-$U7`C5`0zy!37s+Sg3sK0oOa>h-jEhcy@<-z(4@i>;QfpZdoQ zjnxS(e~LA$5W;~6v**hsR&L}s%-sAUmP#W_9QMm+Tiu{!&MP|8lO`3dHsNW9$&qp; z-N^0}hH0;)I^6-Pmq0V-?Kp>E{c9#N%mF|k{FPDRZEs1t(fd@_Bz)U=eS!<>h+gFryd;0Aa!l_;Ino{E)&bH~Hm_>o ze+3ZA$HHo!Uxk&NvKgn*Qasu?NAKDxl_*h);~y`})gC7aj>(i~njcj9eR2Iek3|6A zUh*Q_qrW;Te_4_>EUla#oY8s+?uue0V$Qkzp8<1v(y?Kb5qj54*9_$tPqe7z9MY5` z9-w0_-03hKD!Y03*&MzrQ4@P{p8?xQAnt`RuhEO*K0pxbmdh{@TtDPw-*odtJfgN6 zYe$=`uTtVuLofQWqKii!=p z;u~-|Y_^-GDEin@)IMN9{6~~DAH0&h?kQ*-INiSm1ot|BQkoJWKu;^q?s(Oghu6(lW|xgI z(iw@~+P81f)z^#R@DH>d08*+Mk;@&x()0G_t>7MbLc{S>=izf{7QN$pc8A2)D{$uy zP^u@N_F`AtO_xD6pb!>629DuCwoJ+Oz5YA$`X&poB-&h=7ivA^FWCz1E13hjub!}n zag?LyX_48S1rRJL8?^bKK{uA4s9IpA-dT=v)*3y1{{Ugl`*jC;a~3p4ncecOVE|3< zHj?Ih5s56p-K`>`HGOP+_Dr=?vsMO_H&BNXr`uzSMFTEMJ?Z7AQnR)D~90HkeeJNx@+HZ)o?RpB>Yl| zVa1kr^OFUt7pFsQWZ-f2$Teb9^A-j| zQ-wBa*m`wL=YU3wQ}-qIZqQSCgBo|ibJs(g6Gimn$y1ar)QZ1oZrrgZDdp;er;d0u zm`Bgj-^S~UY=q9or+ms4%vDyTp2;U)`53x5+9<>xs8`{;UA{}3z3*f4JJ~x;@S5qe zub@tdTjxN1hJm5~6ON+H#&d7d?b!y3ADM;%v_07Nd)L~XDtpg)ofX5Fire3OM=IGU z48ikJ%pp`1A0%EhLEH$2DW0sU&?wi#3DI9yRxsWyY9ZF}15U7)$yJoUEIum)Mx z2EHjjecTj>fE_LGn<1d26A!y~WOYNPCGf}e#%R123=74+dUzIxf7j`j0;!+u4TbR` zej5a_>?>o=#=p@;>9<887vbe$jkpkXOc^;Fu~a^jUaW~wP#wV9?fWi7FL)_CjNy*) zW@CSo$!4!PwfnjRLr1b@K0`mVP@Xs>YuZZ*o0&ZU#bDh3JwaZ8F`g&Z+VjF1^XlsH z-wNCvFV7-=G2=$m#ebpJW!ZS_I2$CbxKLFH^z?144=)3Ivs&TL!WoTz3t1*hs zi1P^X$3CRF?3eQkS4s4UV;ep6`F0>h0bt>Z%U`7sxdWQn$_lipFR9sw+cQ15$tv%_ zgfB|Z5=rU2%n)g$%kw~qTlB`{1L%W`jj8v*`2--!*wJHrAk(VsKN%pnwGJCu;F+A< zlRvPYXf$qW*MI!I7PC6d4@~Vw{Lc7A1qC0C@VOAy=2fk|H~V_G*=G~9(sxTUvAPKD z%^ke!%JsXef|PjhOWLpU{cdTX7GMqMg0NZdlgo@5RgS#s9p@+U*(ZM1q5BrX<#q@D z-#6{4=;J12$MuNbynWdBSLA5zyeK#SWA|cV5iRK0r=?8PJ%1=QnxXfyU-*GPy)PTN zx(*knufF}o0NSAI+k|J;7SIFRwcu9dl{2=M0>R$m-JjExvOu-~I{tKE6u^6Fyjfxu zSAcsC4QxXQ;x_rk(r;d%qrJuC{ff$@`h+CAmFD#9grfvb@A2a#7Z>wWFG>rm$X7})HM$RWVlrY|wy~dQ zk8+`PcyvssA+mv93;^sK2hIMT*q+Vl&pUA$D(;5t9j{8kms{QP(ranV(>-4i42LuEg0Flt0-=|(unI}}gDm??d$Een3zOpJl5AW>kitTD8&0uK~kDsx3 zp!k}z8#-7c@cbRW?<9~zy!r)J=2v{5@MQ+}T6;(&Rdq37`9@il{%??N9u9Qj~rzh9H z)4qJX;H`l7uy2W{TC+vGiswL=R>`5jV@YolIAjilzA!ocluxFHNR&^Dk%i|cJFDC- z4u9S1$FLHM^ov-=cr#@ljt(y7to7Hy7T0Ww%%|Oj>{6fR;6~b!ANVhn6pkwmzOh;1 z|J)&dSfxi*it)VPda`xg=7;*BZi;uPARCh!`RIGUs2~*n<6woxyyKL2>f&#%Xb-H- zbZtxW=dEcOQ3CR)2-uxTpEfb4p}t(Ok1WM=-z!USHEa7^G;6j&o1@MT;2~EG?f8)l zU+_jv@QY0_r2W&>!^RGSj1Yj%16We|7Ky2Xy*F1Kn|qx-gx1{NpVJ-jYoFRY&oFFw zaK^;cr73Ve{zHTPR9T3d$Lx?yu)p%a53t_vXi*9=gt#5#QO_i{cJ z`_a<2Hw!S`wZbyoZA@W)T^Y9y_#{r=7P3228g)L4cErfIzOYvP(n*Uhrv;bkc|&TK zT#SC~lL#&hi+K8pS#ITXfTZ%foTI`l`mNIP8XtSRx7Vs4tCJ4^oj55}8bv)SfA$ z+|4sxe{+6rv}5`xvu1_>q7Yz*%B~}Ct~qR8M+14Qzy;sZl@!b)co);{xo|s7%S&PL43gpg9wJ&x^SPbpkMR`rodo;d zeEH;Rw(C+i3kBI<&&H9jkUw)?Ex%u2ev2eAqR#kc4$++Ze?+}yTO3`WC5k%)clY2B z+}$Nekl+r%f;){%aCZn2G`Kqig1b8ecX#QUe$Tlx_Yd@keyVn@y);Iwx|thXDPW7= z_v}M{q@;FWqx4%(xtwH}{=DWCBQ;z?-GL_Dpbx*e0_- zh|Y?(I7#010{@{^r*sww-R3mpasog$HHvb&V5ra9p=T9}pHkbuZmG~uO)}W??qpO8 zB;VSON^G`l`a31`I`ud>`FP(f)EI$3Z-D@7(4p=9gKR3~8hrmq0lawv@9#XAYYzjP zKBp5cQElra1Jr>O>fSed3P`5((&|_t>LyHR24j?VG5Lr*)ITW)$xNF+hH6+sL7l)p z^L8t>k|WLH$iplKQr$!8I@?OEdK_--%}C#EfTBbT`)bmT2fb*XMuR1Az0s?`7beN= ziltMCy2h~ot%v?o7<9L;epH^@m(o^IaEIkLh37^yV;GRjkIZrlH>!U5J{mPv&SMC_ zT)nv3WJ;U+m#rSwE*ni;fI(egSPOhL=yfL=CE9HI#)eu&i(;1^m|ecjrG01sX@HE! z%gmwp_UInuz1kWbd;JoKZheZefd07cm{E>#$H#){@eSuSpX-+h?dm;79vR~@ho@>6 zZRUCu_>Eou{HJZ(arGXAhWiiXzPM0rc;b}F2uzvQZB~^{?jLZ%v0Ve&YEp$$Lnj8s zr|>m))&7o@*5~}UeT}Y0OikA&siMgk-w`jmKOLZL5(ei~MDxlfNc7jJEt#+_F@8)a z&NvVnSm}SVjOlAWD5g4Z`s>4{fo1NbED0Oh6~MK zn)_YN6-|hR?7<^TG<;mOP==1;nc1P?YA|7{3(Jr*R!2U~=6%v*#(iNhmh+dfg;5A( z+hOK_CiJMW-sz0V9z6DJ1Yz_4Ln)C@uo{4frb(XQJx8E@U|#f1c=*J9*n!xa{wZN z^N97z8k=&Oo`HSK(js)KNPcoON@z)JrPo9_N^NPv5qX+p+TvNZu%N(TMW!xvN_~$0 z$_?rz`N%YlB1%`|(C?)8M_O8nv8^O8yx(V0VyNLPQJ~T&qCJlItOYOrSjWhBrT95? z?rLFIAYh(yg-YZI5E#e(gZw8V>8I5z4&g7v5sZ2~NV1ZN&vd1#H}!Vhq^eD?kW z>f)vM*Olb3=4#hP#~)=>HxAZQV(qVzZBTlHrO-0xkh9JToj=yRN|&edJm0MJJ; z@D#xIkX{UD^@$*Xp9OqrO^`Yz4~0jO9Q;?vPtF|DTWYc}9qHUD>o=(S*7k^p#p#q; zA=7QgLI#pSXr$=evRG6=cK^Cg$TGu3zK?~C*3Y*Rub^M(n%=DWWe0fgJoS>R=61U8 zG-`nDn)Hv#!-Nx7AUibB@?}LdxA*;wb!}@>E?^}r^-7dp=!RRC-d?uCNMifE z<@R-lQfi4PV0(Dsfab(1H~YX{&X1u_>Z9QZulAnwPoqzALUo`R0#Jlrd*VG&6V~a( zZ?`DUW5U-AA*?j%98)9+^|sgeA8(ruh&2H%_a}Fzcp_% z>TaN%e)HF_VkNgrCl`YaUGH&SBeYk^o?Aksug_DUA#(F)uqWvL;Cak9aLfDE8N2t9 z^Lol5Rqo4bt~HZiF;&dneX5E#1~Z&^we5glhLswJM^3n1%q8a z^I}TERpxESh1!{6oPDk8*!GuBTb_cWI`l@QI1tGefR>N5ZgiTdmhBM5R<9zfC+IS~ zNXYJBsQ(%V3RIM+R!{y8`i6SKBoSLTRaOO^rzyCtH6MeJz>J0G#^D}b`SI@=6i zsNQbuoh=qUNL%_Ryjqxp@fzKnfV-VrU$O|NHO+>+!s|bw}dD-MaE9!g0dR)|p&A@|Ba}Ui)7|`f&ygW z=}0Pgj`-Ync&r*3;55D$)CkbHJ5YvvGqNMeL?iyTcqE$}o58VKXg{ydt+T(LDx6h( zj-nt3M0~Ayw|5=*kjXqR9jN8su`4#4Ki>5!9FY-@1g}zgWzdyN6io^7{OQv;S?4Li1<$O55 zgaU7e4BbmvLvBwW$ba9)18Sft(YLG92f{IbEdz-4--7Nkv>jVxxAh}e4E5BFd;lrj zUYS%O!ZC5WlXr`cg;CPCGZ0j0sA(YPQLnN*Kg@x%3uQ7Z^wB=E4Gm2=-qm(0spKEA zz#IZDD)C!kHn_3{!^?ql-eInE1Dt89VM7UiZ?YF=qOLMtJ`@bI`1-Tmi5a@GM(IG) z90vT0Udo4-gu~zb&4N3UDdF^UgdCfpEaa|V&%O3RWO8NI5pVTJnaTd#hNpfp0$Kx% zt(*#L;;d?aI4kmr?@YQQp5b3pq0L69q^u~ZyUKM zy6W!Q(7I`E^-g4uoxlP!?)r(d5D{`6IJd<-VPfw}`G=aA&|M_Pb?i-pkp4_*_U(Gq z$^{u~C&H){qi=NKy*+v5${AemPfk*myuPhnX7~{4*g|zfA5A@wAWvmJhFUmi&Zjm6leq_XOAhLYoHo%lUjA~eTNaiUGCOSs1qzt7Nt zmXQAMXLNNzB=hd7=2-KDX-8}+YMMhWPcc}5jLO(j@z0qCdamj`M6azhbNZ8wr1=k* z)W+n+-7rP@@>Au;d+WsU>3_KNhYkC&p4W2X-%BHp)KTI`MlUP z)3DPm$=4qw*{6s3IX1N2FRpd%bnHUyO7X8gf`sH|LB4p!Lpm@RrXZLojf#_WMy~6$ zaueWO7{0E+tOo^WFY?ucDzUj%IPaX`&rcQ{ud(I>a{-eT@*u;QaG@vIyVis{Bf+br z{xX967v&Xx3@Uo~_19${tb37~zKjcGA)AG8jKGl6T!dNf!J!rTqc86rOd&cYRd<4c zF6)0O{g*i>G#}bj*(}!WlDP773XIqYi z8&AW#GEWk2MzEk?=`@FvXug~pq}PA=YeNO+UscX>Xa!LWu7NK`{wsr;P>HVesHe^W zU$4v(MT9l+e^}Lj?xn7ua!y2l8~nsZJC?|bGDrd2hC5eXE!VU(#pOK*KtoOJhqIdVlQEDtL7dPXZFAQ#J~62Z}0y!+z7k!A7E zbRos-+Pq%|isSlT`QwhcuFQ+>H(n2?*Cp2ec(boT7>`4n-xxGH;mImUgmt;wQ9t_5 zol?kGl&+W$&Wr!U*gbDO2(1v`!#hw1DgL@Bs3IuKJV^t&`injPc7HE^pCig!&5D0@ z6Qvh81fLHc8j5ah-qiRXzCJ({%C*f<7w@XS4;G-ybBQgn*A=HVbEf}@9g#0x5Y-8s z27yfZ9*Y>;a$0%I$(ZXFVJr=ySY>$EgiscbkEj<(@)~z=!j)cHI{^W!Nl3&d3{m;T zpu0M5`J{wGOAO3{PI_Ocgti1>MGX}GM^1z}p*xrqsxh1V4iq~$PMn|0vSgiqpVSgP zX}N>G;tYGE+hf`g+S$7Guqm)JZ#U^+EHZT8^2QHV@O<)A*i`VR>y%vklY_aQexZ5; zDo*qKJ-YdDTg`m}qWy_@hK8yd^fT*Kh-K@f-8Q|Q7(QK7 z?m%loYDxn;rAu60?Kf0}gkhi9v$A_$j~TDU{KG^+is)=&`PjZzVMA~}cDDR;47dlP zRSpXVXi>y^s!u$Mua?rl)y z#GrKGh*<%!Hvce@A6!rWF6LxZUY9QNGAX!>S)&r%eg?vbgSt&}Q}Y%F;P-IvBUigK0QRC`pPVhn}Om;lxL ztlRlPzWq$u)=2x+8X_mi#69kUJj!rDu!Bk5dRfam#ohs7(tK3edXycb9K*Pxla@u4 z1li}MOyr~iz5fqj1Bch3%ew6u{7zNWZ$pO};LNvsW>7~+j`1f@bGevM8~7_!i^4%e zv$cT#x6-hqv7j2i)3xh`SI|RNI>QhJ_pZU)9Rp~MT+=&CN8Dgk?8#TGZb)~h$^jyE zm-$)c+iH^``^F_Hyy$J>B0Ld(`Gjs9oz%GrCy&hl<%f}zExq;YStW?sBE$lFpNy6| zGRJvSpPoN?gdZV67=KY*r^AONzD)?)o#X>p@dasE+k5b|kwO~TM0ls+v$vZ%CZ!It zp_U4@nkD}ubqx|s1NljYd7fMs^l=QF)A^{IXm>v2EK2NwpDP<2(uW5^UO17Igp{$; zbx}c)1CRtRv_Ik^UenW&_JFHs+LxS`-a@GNC76%Ms;dU9%F_&kTB!8VqDwOfZcv+! zzl03~HOe7w*c2Rx#Dhj5Hzoe~zt9R^A!HDNMga1#RI+(`dbXvZ!+M9vxObRxp}bSb zvftvzdT|VD_=Q)QCyvORQgX_Y>9xwSUd)8dct{~d+eb($qAf~hA~**^dnY_`tmG2N zGmE4Rw?4$X{x*ebiXkxa4njSiC(jXeP5oiJT9WkbtuMD2+HHK;j&isCj3*SS4LDxb z)s6qk+*U}SG>-X;{vS8JB(*g+J>70vGU03ni5xHm{&ZU)F(&P2;|oW9V7B@*&iKws zS==PkRXbW;oVO%Gk&ys?3@9Nmj7_A`1KAIeDcXw$}$wKWq-g+;_hXnW+V}xF8FYVM5Kn-`J~>Bne20hQ2R(e}~l`2e0}`9KbZg zT(p%@Z_dl0^;yI&w0iaaq0ds>DDdQIBG#M0C~;yLD7!>zh%3e(ATIS}N_Kd)H*Yix zc4)5N&KetNJS>>_iWK^bOrxeLG8;@T3o!^fzVxu|=yem30JZ5y1z2FcBRW%lV zsx?`UZ~bSi`5!EO`vSaRwRUYoA~G@7Ut$Dn#XcWm8r0u@}*h42i9CGhNjwm zCms$bG0--!Ol44)ARJqoGcl8(b~}s(=l2qSja4no!~Dk-Il8zY@jODPZa4Lx0uuSr zab+(y?*z3vUD^(FL==B;SP23bUhdlhd3)rb1td0RYhYpM17j$m7@$?iWQkB_zFlBr zQqP+Z=z?OROB65#$~>9bGU*eR%#4(TWVR1EhlC4Q*=EEMtkx6_$a@6?t33{qk8Js- zSvf!5m7t=I>rcMg#PKfqFQ}kfaT(uyiW4>TNuc(DomRWU?Il znx+u3YuH9mQ-4yF z44Q6AlspTc(EqBRPGi7KtVlGF{Oq>}UlS;f+)x>*Jw=B08JuT$$>8uja^1iybz+=+ zsC`Xx=xEdf@UM#?zd^|9)l)4$-?2@f$FA&Ma8>@>GP%+-@J;}10Ec2vU7(v+pbvDX z7H|p92Z6ocHvPq)tRIs>UiW?Ge&_?G`F@>7(AOEG)|r3&=|8(L*kMkcEzd^bqXw*O zhswio_L=jQ6Upbj*(vcY691anN4!oW)spC}NNBN3@NYujIfbdfZE4aMKS zPqxj`mlE7yC2T#7+RJ=>~ zPdV(h>ZYG@-|Q8}u{_T$R>Fq}^=t#L(L1O$IK;UKVblu{V@vlaIo92q@ID?1J8DjF zR&RiL*{F-n`ea5|WDRaZE^{KXQa>ly@RNR_(56vTLQ_kkG3-&mF-0(0DJlpzkvrGO4vv?0fCzi*JNt@7+|LRuf?M6*C?iR7RU-JY+ma?^TOPzhB_~5i6iv+L2pUN!Y7`2^= zx*Aiff9xr0I2b`pUm|StL&`1Db+vh zkJUe)CVv`rs}y!hbLbMXalB(|N;~xJ?mlkMi|X;dowxv27z6Y%8=7gQ@84X7F<1EN z(x+3^&V6lfw_%{`)_=y?u#?tScjQQ$o>-D};0*9m78sB;f&x4%y*2#dqqb_P?`3j> z7j2<-?~zn*yzbbsu|hl}u5CsM6_Iq&Eg;BT@#0;y0a(JVz8M|eC+n@HVNuMD)=XJ< z_!Uo-9>R33aVRHb8xPGjZ1;t@DTl42kReiKFYaxI$yhHq?2@DD#h!J3FaIY+NwW3Z zFiMP&J+;sWHWxCfQAMgf*%zSfutcc;+e|EDQk+Q>4l1!T)>>C2#e;dhYO;ADXp8%z zMd9}m?||FggaJZVJbxyiC(L=gpZ2a~L&%kcCFyz4$nP3e!+J$*?_j8U#5$g~dLDdi zRL(~!@}|uB^X21}wRuWhJk(nzo#}#?6p}P^#S?tekX==9tgYMRG3E{1xB6Himi}?e zK!tgEUH41dNh=SYWdXIIixi zOE}$C^c6Lv&{@rV6@ESQV2j==+ln&`Aia3M^aH>bfAt^6jG85&jOQkd0>EBK+u0rZ zb)TMYr&=fshqqrT-$o$Go{k3_MHZN+y3{eDKpaYFSZM|q1j0m?JcX7GMzyCxlL2|! z&7eE%gxMc1>`k9~1v%xO9GsVlG6F4oNS9;dm9db5ra2dx^$;o512M(pUp>zRp}>h`m}c6=j}}W+cUgsT>WX^!6sMPXC!_-E)qHq`LU=)^TacQR6+JOGA^@D2?DWnII2{PJl>A7hd%g@#Z_aPcbU;5vX`NHidmzLkfgDxLM zyAt~T=X3)-ZoR329y}dVziduJG8p;jEZf2CcnPs@N?c(h3v>$l%Zt3zbo5c3{SNT0 zvemrwM{uew4ObX_L3*;cG$0`?ROpP`I=Un)zq^3OR2Lu9iO$Iv|L>m?g(Stv-RL~u zQT1gD>FAJn_Vt1&6TZk^O=6uoQvn8=8Lm2v_;@O|LDkE@a&igR%caxJk63DZd!4mS z=lZ;Bqe4G5P%r<`y{(f!&cF!?@xQy~*~_elOhHV!HpooYxtjiw!Svk4R4rN%#WR?9 z!#gCcP|4g!4>TpVWcNxZRyhsTb;oSIklpa6!SBKs`&y`AS&!83g?!OA?%v-q4GANV z0`d23Z8}DSzNeT{Ns(Iw9o(_+YT<`!VQ`0JgR=f=CIBE1s-M2|~f?IzG}Y3+1N~_<4rt z#<99`(zuIjScxmZlv`C@uP!B6BrQ%HyPh`8#SkfKUN$>~HkC_R^Y9~w-5@2bN`w_X zuL3Ex#pk#P_tVSiM*6AF6@)>T<>vi4TyvpHPO4$yKpS--IHQmG|Lnr~SrY}_ih5|9 zmaouHL(mMt5Ga=pxXz{lVqE~m^WKo2)f4f}R26)_6d7w7!5mM^YHfM0{wHjY#??wrtZcsfq%d=#WIQUpS)+pNpJ&jCiXr+ zK2nKgb`BNbwqFnXbmRH6-g$|%L;KdZFgVkMn~w@hYHDe7p%#t{1x;?CoI@4vQzRof zTx5bG84(KOu>Ky_!beP)pafK#d${Pbg?*G-T2WZGt!IwNsR+Mh*XUJ4bZB_QPk6@f zGFyV8i*k-CEi=eUm<|U+#o71YHs@tEwr1Fv32Az35`;X+KZI$Mq_bdRHB zxe#l;qNN@wTlAhYk|yiWzV3F1P>WOMl4HwF>DM9({LwcJ(afN)Prszxel*_Sxj*$R z9P;v3%hdLg2~AV#H;Q5I-1H0Ui#lwJL@uzk{irHHwMrbCp!K}-`n+^Si+^bJ)hU^4 za8tiLBfDZRc06Zi(Xy4iHHOnYGTSy&sdX*Zhcil=hRuTf`)c3Occq;_t-kf4b018- z5u^V7b&GS`mKV9;#?EAiTepYiV^$$fxz7GBqCg!a-$-lzP0kF>I8gwm-27(+M})v+ zU4!baSj~N2v=RjdpJHbM)qUKD2ywtOjoGy51LvT7MOPm^$OcjsH(twv6)gL)r3dE*5thL}oX! zu)@id|E^oCfF!^dK?S2qxi|bR&Xp}HfEtXAggF+5r_STkdjUuFS*lksJxY&?PB$rOSvL|e2pusIL>VrsG8jIzEKZ$7h)1R}(44+0oFyva zp4U4U4Y{XJ(|d5B#Si~74U zN3%J$yfQ%FaUuRSgH8fU5bfQbmKN=P#pwZ0aTY#zQ;9Tzd%i{UxB8I6&DBemP+Q50 zRw?oCLts;W*;a+Ic`3>kqk;Kkf53>D6i1T~IWu>>u5$*yNzEVcIrUqGAm;%pXRZ~K z1i$!8D)@F42YXEEfJy@qhj4Ji{)@S=1|)fK1JVcQ8}97v15-Odr5ntX$==+xo+al( z9rKcy+j$i>->RV9QZ?yZv){`j_fr1J!Hv=OnB%r_iH>9^&nDo@i?FaH3PJU6Se=MZ zZJw=;6l*k$kN<9_>>>IwTTS5SZCcu-YbR*hF5I8dwDOE~QHqITT>Env@>22lL>(;f zfeBZ09a9pm3PhgW-<+f=V-tM6g>h|&k;Wti%}LXQc-_(RJ~I{$v(JRUQ`8i#hm$qr zGBTSKTF_Y3*oFHL_i6j9mwFqXi{wRWF$|Gp?UK@drIlwlTyR8Y*Ve!LSyOy9Z+cAL zVQ5&*zG0^R8CH=<`K3goJfE|@%-ikgPgi37;$7HZ!WSJ$LwByVbY#w&D);)8Z$|Wn zAD~YgmU+Hn=MrcwlFh-@gw%@+AIshFG&()8tuhnli;5SnrU7e8H^4ngBzwX7zk3={ z_C1e|kJx`#R|O~f1}id}`BM9{K>1c%ad>l)v;A27kD}DynkK?pP|MAUnJ+%`oz+fb zOc@#sp3Z9eD3ko7hIhR7kfw-Ea&EM%AR0muT^O>_rdK2Xu`B0i8Pl}B!9SsR+%RO| z+D{r7G0Z*S>d5sWh|IHXECGj=%jgZn{H*Nwx#Tx1IhyOwZ(Y^NoC9xEdL-Bue=9ii zVwVu*1zBAxZU3$zsUneM`_HA)rOZkR_9H=#yE5nTmSisr$laFACB&J}9tYZUCg!0$ z^xKGYvueC@BtxkpBCk+sW7Gc_R)F8NZ#~2T2tdo18~3k8IVve?pqd4A0eps~@LcKD zW1sxhS>8#->6ZM@p524Ce_qoGdUmDf8yu)JgoNw* z5HHtA3@>&xedBJT#lS`Jm%9_$YH^~a0ovaFN?;^|R!j?eXUXBJRa0A8Gi%lM5c_)S zyf}2;yP)Q(zvWj)LPB<)fxa+v93oa}LW-yyr(0d>qhBaHM-u&+3J3%-Y=0LpmZMI~ z*JBqmy3q^L*57^f`~sxDQV&&1GvMea4f^`RX4?7n7~ahIoMF}_4c)Q{o_;@bl*yrc z63kSJ5cWs{$j~$Ck4(0_(e(9nRTQMh)14*0+#(8LVG^48IzHR%aBoS)hI#?F@8}`WT*P1+hUl7-Z8jtnr>rMKEr793u-?8v->*T7caw1 zF0Rm{E&>G-JTXS>Ezgg1LtW*XzG0V!7%x5QF=dg_lXAt8*niH&GgJzs-jsQ!-5g}_ zqpF#9E-hfpLo~tI*qWzQvVBodA%;LUv4r%c) zVf?}tBYZ0#RRzh$v-L2mXMjOruua9w1vXU&p5m)*kCgnQ2jEV9G1@Ks4oRO#M{k&4 zxH(QoJn5z@M#(fqpU~`m*m?NB_qv9K!#iNekPYs;=NprttpkkO$xE#3?X}mBQ)Ug) z({kmO7w^@VmX}s-j_|IF{jUGv64J@~9xT&aHs440r&bJhT1OqlfR)STY=fPu^EQR` zSB~qcGjw+L!u&5rr-jG{U~oq6lrsYqqK-ES5IFn{1 zD6OAbhl5=s=dHh-n#7TU--?W;L8B_YIp~3ndmW*2z9k*>KO)CxL^1&Q48C_~L>UHZ z!^5_CBiO@VL^L>WBBd(A=cyML9E^`kM?S>rKCx9K|RVBNN)UR~zPXT0XaohCwoLfyl z_6t*@cP;?7fA^BLXcS{!7VZvgexE!}uD1)hN1*wz_`VgeXnbvi{&;Pn%b2dF@*ed@ z54jNLg~AP$*2@D95{|iWCM-u(G0#8RtbfRm)?l;#VplV)B}YP70-t8>K1JAv6c0}! z0{OB6Zgv?FvTpO5M1!RmJ_iXei%3yje5W$`WzKOO2W4kJt39I{&NN+A6RG<}tMa&y z1$Ev`RW)4PO6Rm(k0ub-1w0pD!phoT-H2N__*HlmEo8B?KW6KZ+=GGH`vTN*`!PTX z{J$Qju_O9yzfSn8CaZ=YaOHEC9vWN4WDc5Bwj`YXqF&LtV>~THIwysj>+u^;qL0oF z!iX#EmvG?051?Bmf4Tt(0hRkf;_%ksY~Nb!)xkG88r1!6=R4^_AqMWk-Om`FH9SjPsEXYc_*+cHG{KjbU?$ifQq_~s zPFvB%^Ucnz_8=O0xooIeHd=pUH?&`|zYebJc<93I_)k8OCYQ!(Eb?;>VUr;V5tOkJ zwBG+czX1rYK>GWs=^Y!GXwI~&k{jdPjndV63N0p7c4*~6@Kn1no(?kuXxDVP0b&;m zQpy9;it3zOv2Z~}k7om4s=xJ92|H#B;P0ifZ;K&xIXk*|*enGt0*BI#eBMa}Ao?qV+Sr2Zt_ zj&p-Y;JC5-)wiS@g7^z=^ai!*OU5CcaI#7z0|W=KpP{K(<5Quu&v1tL_d!(O42I=V z!f%gyUiK=Z<~{aGevRd%`TLIXSl9-?e~BX{!n_2jM7vR?uJfHla`o3xB`QD?bpK1A z1Crn#6eJVkOg&U-YjMwN^ErY1Rbe~1p8WfQrAhf6N{!0K< z7;Hkb7^BicK`9kp?kRQ0vs_Z{e&y>SIt}H{qA=ZxK5MmuY0GbtnI1I6lk|8=_!Veu z6lNYeOjTpUQ7JcxyJsnLDufVu`0F#l%%9)44Qd@2p=WTtomq&n-$YB)BiI--reYfn zd;dZ=`;`jmxU`h%K~%cmD;}-JV?aO_J7Q~p@Mx-Vaj+!R>k*xWs$92r0^j|=4Q&;u zS2oW@=;Nbxkp@trA%*3q10M3_ZZy>Jr}87Am)FFFgjYvvZkE_>t`lL1x79mR#!txxpn|mP^}H~j}BYQ zv?38%)Vr?RSnLC}9B}akBP6Jr;p#jn6tL8-W+`stgQy4)9oq_Tn z>-+T`S3|zX64cH90wwrqMBx9twc*JdwbSN?y)8}Ls+D-qU0o&%xl8<=ATZ^(!v%Lo zqM4$SjjV9l+Bweb^aHQ%_$s#9b>Vx%Cxwg|C-70)_yS=t#brfF-cV--QnJ|F{`~zf zYNN~(Z}c1glRx21a{3)e8AYs775{rIK}2yZ2n@0h2#n=*-X%`=u|7OF{r90XI_{Xb z%2ONoz2)`8)%x6kq@PD%_lJF%jygCm(jQpcx_#`qeb;Fxc^Y|wZf(n%pc}f^7kjVk z>e~++S?j13YvgP7dl?ymobfd5@>w&^6?iMs+ct2Klu?m*asS+EXocX-B{`5oQRG$Y za(@0H7Dwr7$VJY*i3qfBYyQA8G&}V7`mP-&0o7pfL-29!X~qS@ae3u1vz;{*WrI>S zYMgQ!6-b&9(0VpTzLb~h)-0yhB_2#9L$Htmw=sFTlqFq8ytifLb z?m}aIFO(DheprjNZ<+FqG_sia^#|=vwYlta{z#E+y9~8lmNEX2p=gTzB`gxJ8Iez``DkRkh!P>W&H@~||6tss8f+!zd;{pUXUe6cD_pX^kf$gD)kzbCn& zzJzJDVKr27#EYNb;eQsY#8!gNn~Nay+B4wFY^D(QqqEKg$+49L`VW#cvOS0W4Zvva zfsNx>KR1H4pH)>+ebYcr@Ykd-51j9FC9F!JykZ4Jpl}8VHs)|+n)Y#X)8$+M%7R$_ z7oD-cR$a0M&yHJfjHg(qu{47pbx&>tY28YS9{U}qiPvQ{I6F;|_O8p?T$7!D7JoVA)zvCDH@eX>4&W}vU;RJ5)YAOZz)59mrB)ELf1 z>J}ufDnHi$FLs7}y7z&~U1h#t+n}m7Oj#oiFXE4mqljit_&>Xq)!aBrpUi z$*ii}K7T-U`{H_YFqg8I*mWM`$Jh+CcAuh8qE0!5Fdbo#AznEm)Cf*eH3$0;xy)C| zA*O7<#h#{NB;n0pFK)@rNQ$|aY&@MUj*;v_TAIgZsCk-%h@b7r*5fYqebF4CgcD2m z(mZb1-Yh&RgAfPP;c}px>kBJAkxTjQwYZ^A4hlVEO8R0}Me@ zu*WfciKu&x840POt(TO(tsIjA?1~a*k^k}$oZ$8hd<3IHg!z~plK~PRB<3BP7J6 zLg}O=WGP0yl=cizUpHUYlRoErjQeeyq4rOb?V{U-+(aEIlQdi9Bf8Ww5<27DYu*zq z@s8rVn43+m{9o+clL6GYPz6qDK_j9(2RtmDal4UDPF(LO4h!TG_sniqy*U4JI5&&B8;@#O-4Sn7%Nv0Kt~XFBdnsi4i|yhlqU`gaDO&(Z>n2Bf z1XP02t}J%pgzw5_SsaNb!+-5gv>JXavPB}_O)%BXS{UG|Xw?M=T4}S84}N3|+A@=7 za17N%d-JiSu!Hyxce0B6N8mp58Puc$@$7N{!9>c1(&Pa!og59kp1IL-5AtDh6XpB9 zA|M3rdYrdxBwz!cH)whP#F45)?xjhtWzr?bIf<$G%pBVtRG*Er-Sm2V?loVIpSM!J zD`JoRNTD5(BT0Ny)340~?D*9cEUe&}4%>rTVFQB5Uw%!?KYv+^(RGDi_FtQ& zTBaL&r|NN2Q($~@U+eu61iDG)yXC=r>;}raOrH0W}ElRxkRyzdnPmyzimf;V$1+qL#S@dS6v;ad_CN7;?smOANji9s%dgqJw*x&g&9E*rttgxv$AedjTPZgC&LKz&+DVKf8}%% zBH@Op^&PnH1+36~AvR;th8Yvzs_&ADZ$o{i(FgHnRRfea!p^$qMV0M$s1Ll9>jM&s zj_JajYr?{^u}ipVldoaXWUGJ56X#6;32XXsj#;L2d(1eO{RltrR{v=x^~DYD+FLeA zn*ng<0MC*!1(TDXMJ@?!$a(ClB6D}L|ucWs7MQ9!z=&O6$A+>)#rA$ zIzE8dhirpPlJ_%aH&kLeV$$UR z&ufqpKv68Q_?T!-t46pM6!-fLWN$gvJO}7Ub_!jCW}192Q0@%8rkJ1CtE?EnTLjxW z1|w_vhUA*}TGXEWnMK~Dc90&2jB+Tf$|uKi73Z7|PL4A7NH`ctS`=lq zK|rB#+KHR+u&vjj6w>!ke(*@7BSoEKdG`}nTFFFE zFwiwE{NvdViRc!_@F+P#EKnH=v$3)WKj(!VN0IjXf`V{`>5s#$#*y+--_T~3zd|4U zQItWrUUD{!>~Z#w$^C&=OTEsI5A*WGR?}(F>jk5CQAnuhAcVya=2YvPKv#iFLrD{7 ztu!exn|CrifEj*x4noI7Tf|*-5x+Nn_|tLUHb%G4UHLa^1}1k`4NHWgt6}xjXF2m& z^ARd+oioAp9C?{lmw|u>s!FzgDx0gB6?s+Vor=KOfG`b1?tOTM$Bt{1{$;`e^W#BA zO&~exDcM)?vuMiO)m$OmUD9Op&0?`^E5^WIkZ3j9xMk+U3JFOs1A`xI|jll@jk*% zAUXF&@6j6$rgZA<^6a_>kS%n=cabs+U?UWgenKGF0el2zKSXi}7nlf)WB~aR>`f?ppjE8Hl~C~!ul%Jm^JxQIx{B4(+wepFRMvF#3?8I{ z2My5#0oq$Jw~KEylh++eY*FKY?R!qA6!<@D_?C&=|3sj|AP*pcKfLtcsF(GFrM#-~ z`;F=rthvLs>b3sAHKe!4e##K9cy*o-$z)r};$(IWA$f;%MH{A=f)3c);4mH6Z5f21KFdC! zEgfNneQ%ivD?pAChAW+=hlVHbg2ZdK1r^k&M}}{TjG^w)>U@P1isLT3EIo-r^wm?f zExyJEbseh080q``yI(H&hf;beS+;yf4sd@4N6O zJV2$&*_=kJL2=xA6B#;@N^jeNkupyVOG_{4I^=C?^Vi*xN{f1eDgQoiujpQdd&23Y zv$c~}%+w7eLZ<)*wJc)Sbgpmoy<>^}#-G+3`U^NS0v80F_8H6F3mv%)A+(VP*=h^e z=SXP%v`c3ImOYtH_&P3kVx?inknlBdkba=bCFPNBnNtiq5CyoV8=OF)UW*Lc@6ywS zPAquef)bQ3C`TzhHqLPChc?;)nu9W+gR@2^5|Aqo1;+=#`nw>KdXfps6Ek*>=?SvC z6w(te1gl9eFT7nQ0j{Jn;`4)To%qj9k+h$>I2F(})iSsI$Fs|$r$uNlD$Y+0Dx|7y?Ok6sq#kE`l?^TzK@3p$!o4NUzq#$D|QxK@*3?2 z-4KbwaXrd+g+!VwTWH8|u?4Cl{jExju)+V;n{S!iM$?F8jMDz(|FZ}s^P;Jrs}I^^ z|BLagy6DMyM23z@+^)k?yHa$-snB$poyZhj8BsBAp!Y>E;qJ%UooROkd102Lf_mY~y#=ut3OG-xBo&6!= zJrb;e2Hl0ktYFcOM>X2}{U*pdbAe!2f?J@$SlwtpnsqHLXx6>1j2DiN6jjGy$;^^; zDqaw>;5s!!eZ;(>s+>u-;mkv7e|E%F|FMQl^h2AZ=U|5t<9OIJ`hQ^g~;+hJ97Z8>{vE7yEWmZj+S!1F! z=0U9^N?R?$q@j6Ae{~$ExztsYplIZWfq*@N*yq|lbMU3>@h{2UxEVHOgAt(M9R4yp zYY!C3dk9)j(4JL_97t-su^BgqdJb(PsoAX4d#P}(ElLDj8LIb%*#QDh2;S@dpE4sR z2ra<2kJfYYd%*2&;Azd9hup8H40^Wh`^^4)WVo`Q1U6(3_ht^F|tNA80@}PP%O$vLUQx z@!zgKn4ox3(;w^QqeoZ_twl&O+@c<1Uy8h!L+9NDenG8GYl{dTNUTnI4e5;hA=CX? zJ<_Wx|C{ZThd1sBa^dXv(wtq~U_4rF!?k|jVOah4=spztbW&5rdYINL!NBS3y5uZ# zQfQutxN}O)CY^iK6N$z8FePLCkrC$~O=YCZ1>$7Etxd>tR%^H%7^R%RuDobHzL%f# zvU#Rzuo+AHO)f?_WH3+pyy47?TvnwkBVoR;yXrthKX5}|V5oM%$6 zBT$A)>so!%Fstkr>lNkx{!@r3_sY{WM6G=D#{$G8d%tuaxp;aWs+VX4P~cf_V2#~S z6scS_aqWC?NK<(iBgmAPEleb^?A&j9C3u#(>FRT6*GqI>i#|fuqm8d?opRCpVG-GI z_uNGmg)ftq0@&FfJMiUSB9Pg@UO34CJ#&UB+7>Yl5>K&i1+(H8eT0O;K^xt6QgSBwW{~B z`~Q$tDX_+r4r!vuP*Sm~!MT|#xeeIwz(=Q?;`)GAa$~rbW7+P0&f|Ts>(fPk%k2M@ z3bJ0RonSEbhAgUuY}FD#FqZZfBy@);_Nc065;T{y|peI?zC=?vs?W&?-It# z^U^cv`uVi#9=s9~()Z`>K$4iA`z7$L=8s>XHNFY zW7$WSNhYA16b&<8jMj8Wo!;B|N0th|b{8rY zrZM&^)>9v5gN41^$NepUu&wzVAWDl}tlXEljaqYz2!*!FOqpg#tEasp6(0WB=YOX% z;8686caSRI}8hq&iT-7OY= zjBJ6HL&)vLK&|2mYm{9hC+bk1i3};BbUlVBo4fQA42q{P=Z*l*S*#px`l-Jt4eA$X z7z7n6`)iE2OZ+K(oxeu$+>Dxm;@DoAy&pxH!kQp0G@i}OyA*{q5dzWkDIZ-sNusv$ zraw3p5~_w9CCwjUE^lj=qd9Mz zb*1=<0*mqJOv6xkhO+9FoIiwkJ?WC0DJ}DU=ehE_&?Bn+jx5(U)eC)P%I=>#}pMJFVU%R>Sy0GY+`p=y3&Urb*vfOpwC)s1i4 zOt!DS;r-j3$AYhoPEw(-jT*z$_H38U<9i!;X7(8}xnb6txJr*qQTr5LpZD1pFL~Ow zjH=8wT7BB1m|;0B_@9=?XqhBXF8^2chi)#<0IiR=b#HwULqtCDmb42S5NaI{4A-?i zsL%0N#7!C>Ts_Mf%=Ij6>RSq1x*2FK#ty=7dY+lnU-0@pB(=VLT5Cu?J9A$eSSz{l zY})+y&hELNc0W~O`d=~Sd+I}4^9WOocUvcX`j9gWeZZQNG^maq(-F!G2yC=H?;imL zeNvJoZK2st)UP*do!Thdn2O9eGW{IdJr=Vmj)N`u>L8Q)bUZJM-lnoaM#8VEiV{jc3?DZ9kjDnV2=FVc@*TlXc z{jCzzmnMr|LKCG|wW1j(v3Af#4+**r>lDIh6RmxYTz0HWhBFfpd(TGG_y>0qRy(1z z=n$(e`Zo1oDp)N6MGAa0t9|zNftz?38|vjkd+@JJ>91gWz-d*8L>H9O{Of_lrk%k; zm4l8-&u+Qota>I@A}dzb*ezFKJGycPL+b&8{rY75`E8HvuY9sRH#WN*zxj^AU z$)wPXVLLqIkMkQ>8Sg(IP2Wy++Ov)Cpi+j@@PIMj+u|zFIgf5K)Kl>-B*Nb36bknN zj4I<4u75y<40zXezu!myu0+i5)z`9+R?f8-M=Z1`HKv1OwXx3bi&4s9KJG1WKMwtg z)$X2KPHQ*Igm0QTtFVwSH`MtMLgKuJ{&Ou<8_bd9+WGaG;UxfDcZ|kX<++U1@c5H0 z7oOU`A#UeCQDypE2@nz3Dq@j`v8lX15{w;p-5K$$I>5^ASr}xI(Qgwz?L4zt%)TY0 zU(`@;HQ3(0ez`AjBHeu&Y3cS=K>+sEFOcq9cseMN&Hgf9o$r;3_!jx0oPY1x*t+g` zfcFmm_D}oO+q+Dmw~%|muu4Wy!{v+qmbUI?A?16D9GWa=@`fett`@#){B4gh?;pOb zvI<9xpVJYlG_rcTiZkF(0^%7MCa&=xR)ZW-^~jU8pa=itQRXyJZIXDGvrzLdlm%kl~4 zOTLz%dmkzPH*Cxo{tNB0Ew8JedcIYg2e#S=JCrwMZx+5U)&?45gdF|k@T{Vd7r00D zDH6}baDgw3H{JUKi-|YMf(Ob8Y zrCM*Piq%_TC3J=|3BCa}SKpJfZ?@nzqh|g-5fZ#bBz}9<@#LQ+d%wa>6W5-)9Ff(S z&>R)e(S>DJ34guH!7haASe#Ajtu4h~^Z1H(De5JD`;>5BtIY zu(h0MXIx`A4WzJ3N8m=_+(L6Q#Y0qKp0+vg5<*Wq$HeN8ZEj0;Mzl%zKsONy*UhkyUde`j-sG#qVuoT7i;%ttlZR7bd|4kdFUTVc4OL zw;Oku$#=$Fi9O(T8(p8nk1JkQ1lz?`=}(tOOUq4*yWVA!Hm?(#HAlZo!C&(%7n|JJ zJG|IC0(+i%o|_sdJZ<)>=r5Kc$0oT%{!5mVsK4yt^#Zp5VC3Vxd0u)Kmi&K+NteBb zNnsM%n`quK>hmVFz#)(v0n9W}erNBE@m?ED%b(-8KN z3oS98);n3hEw=nS%6{+s*Z0-qJ6|@b;B1?Qa}Zd2KMu;nTC0DZ+#$WIDaJ@8!O_NI zy%720S}Pb}c8xiMXj}SdN5fZlE50vw<6rLLKIk^Cc;NF0#Giz|ZoZcN(lAs-9TOW+ zuGlkvtW#cY9s1(ApFPW2=VRL{Fr0-Jk)Qio?D@B+Eh*ATr0NYX3rl3glshOho`{h| zE?hr54zc>@0@FlC*xN-~jVY1u>)l^Ro{9hL#Zn3!KPAD$?^NIAbj-ce3$oLhdt4Z1 zQoTT34DK?C;AJJGkXUBG zszS)!;*eT5+u78|#OSRz%XP>CJr1tW@R8EO^k${)?#&LKtSoyc?1*P7|20SM;Z(ut zfMuWQH&V>$gG)lz-Z{x_7>ozU~;@7DJ3lr=zc>K@3Bp2u}VW@)Iob5Thb9Aq^N z^PNvnN#?x4WpA{es4>o?yGY4M}pc>PP_R+RQZ zC~vV-?ckZ>HM5I@wi{H)bBc9_!IE24-Jg5rrkCNa5VTNGJ! z_$~@yBo{i|P&>^>rw(l`R|Q1-*;Elfb2hI{M->ZxA|^l`_%45xem!cy z0IzMz)?C;3c1LN3z>9d%=-74x8}y`Xz(|8ON#V9lWLMA1igV_1Tuq{xkYL`yUz+Zn zxJpH_Pf3W<=|^$0Alg3q;*10oTaDj}BPI`pbImV`@HWLC#>UAgF!kpV8p@;tD9e12m4` zVmDkA_NQDd9{>I<(?zLVJ-eMm>i4}{1T_1?Tdhw)@BE0dynju(m>UD6W*CrUR7I9; zFE=v(^K1}1uAK*YUd_B<4N^3zd_T-bnn<`)(8U#ti6RVV@B&|pMh^KLay}vh$wN%n zpj=_O77J0YB(53{PD$GizMWY3Vb&|J=h%(C3z9(|wTt2{I_~Jw$rY(O?E6K7p^mlS z&$JB6j~|Ek4(%`#+jcR7oP&fgYc|_dLW_j)5x0&`MZ@N&d?qx88c&@EoCe`ErQ^vs zr9AEkz(Jo;qXMvR!DRRJLS42xWLpwArZ7!TDCL+&g@L^2hLIcYagcbZu zSwFZXFk{`y7Skuf=u1+a&}VXMTx$1#uC9YyU{+3l4~@-qd0Y5V#C^rMO8)@I&tzqJ zxAhAbXNe|tQ4Hcf$VmJVl|?OlU3wr{KfATmg7KAgeyc`<+Kx_U&TCkV7-p~&X`2OpJDnE#^MTmVmoqjU zRjqeTPq12`$etO9!{Tm!mlpdo|A6CS2uOGcG+rMy4E8E%P8^GTUru{T^w`7Z(ne2z z^qw<3WGrRRen_>;&H0Cth0sU?v`=2|e<&H?2f&nlH3rOStkrYk^h!v7%M~y_l2^5^ ze7vQ-7Jq-*AibqSE(Cpa<@$=)EIN=jFmKk73EJfC)uTQ9+j+KjQnzZH*F>Zb7N6xD z`H9?h#X;*beExQKq0)BellAsI?1(%)2uF891T8o7wR9@4Y|Z@l$n519DAz{^QVNbOc7<$Y_f0hedItfR!bjH>+`eciOlw3!1&9evZM%K0*U;R zJp+j5CUd9rAY>T%n@-wd(o~fM{-qpyy`36Ce#PX&Wyg~!PwQQC@wXazR1~nD+F8M$ z2MFYQ_tylq=mb;SR{>o(9%fuE#-GH~UToR&snqS4J3c$kCLF^>(Ptx}biGs< zbT)Yr5i&;DHPidfi8@!-Z@}>7L>}TA^$bzuNKA|Q-B_$ex+%E^P3pTz8hhoU3D*;? zr$g=G(AYXtP3tMI({agf?L)ildSeM`6UsTj;6;SuT4@ItU^l&9fwe4B5#S^!*H5lYT-mm;lroag|7Q~iYl z+)F9R#1`^7Xkvgl;aA9R-{-(GagWf-!?dfRm+fDqQDAqf1J}nMQiK0FQg%R`y1$Rh z9s%rH^n5J&9+tk11;XOPN16AmD&S6?7}ADvtRCmCW!JX#*egRpKO0hT&-LbGx`^ZW z%Z2#elUDcRS?i1J8q_h~s@3_N)l-)QaX2zgH3lF9FWA|Gc`JmU&o}ZHMJuoP&_u<$ zJLDrNx5gRXClb<79tOBQ8>}`L*iYVBk)U?L$O`)juP_IQeX^1r69h5ro-uAh_z`d} z09M(=*7^PQA{cvG2GM3$mNz#tASSW;W|Wc_dnq$I8mbHey!MRveDr+G(=U;NyjLCG zDsSLM&hbUz0^sD#*Cma<%}9uXp5ubQG@<=2z)OOPfI>MIdYELW-v)&s=_f`bJV|?2 ztFFwmpb%dFOfXKXZMJ~=G1;b8mP>>7O$=y z9LkPsz!D+kG#P3&${REw92g?ci4Hg?HG^^4%(d83qGRS9wMi>TvfVo87gVg61|&*W zh-H$3^TT8UFc{Y9q{&^J5Jx(n`vd7|1@~)%7wDOTv;3a9)3qtwvN%&A`6SmR;F{|VI)&>pQsr$a zU)tF+sXT7HJh@*o`|71iPqfBpum40EsQ3qs(WL=3g$RF1YuSF6UR*!&m47gDm~~Iv zv2>My#?W2QBui{=UkA9|s5WQ)?wIZRT_CAl<91M4+Dmb8e|7bue^L19Cqx&;-=^=< zW=GiO88qqeY6iu9|J+`^SUoZP7p1G*yMo$BGv0s6wvrPv?$4ENq507%TNyGiU&1_1 z(Et0e`1p^=6NB=Y@m$P7v=y!QCU91qF8A^gV_{5O`+P`w_`4G;AeKbesB(~920$DZOyCwsC?)5~EgKZB zhk>p~V3|peaQodNr3~AlcNVw#arvX&%uhwo6p&&j>VY0zU?O=;aTg*$m{>WK5WjF@ z$P~f$0h=DhA=V8Zo)UE+wrUme%wB&xQ!l9(mH=c-MCvqf8ncUUo9wz~Lgg*(8_l#G z56m9&YhDYBO!c%-tOvP*x6=V*MEDav_JZ#fdB&&NUjNS0|BzVifs59QX#(utblDFT zwH#!;{55;%U4z4IN%4+er<&^?`Q0L+q;6{N)p)#+iFU8Db)DQ=wyeCHD&Mut;MWys zG+26<8MJ19a#Sg_Xe#nLOahHzvI#e_mv!Fn)(Btn{`vRNnxLu)fZ^l78%q5W+xqz& zVp3`W_nDUVAepIlCTc0^gC934G9G_@J6y5TcWj-V5Y)dWlYFI{>nMh{aH)r#e-_K= z%VLKJmc}}dm3FfNJY|hkg=>(uoM}Hbh1;g}8*VH+aLYOpyV>aD^B(b;!-AUOoR@xo zl3a%M;Pr)l-_AMB&kh$+<+43KR=pWB$JKpB%Ka)>+wheoAUs3B0X?IE99X4XpbAw|x zigtK8HKYi-$m(eIk91Y+10t(Q7dvnbyso2owC-$`pnOfqi*B;SbFeMoYT;JN<1ktS}Z1fJNHI>v8HW)a#{QKdac{YdZ)nD?~1?r zCQ<g>6)sN{xV^Mba&oif#q;MU`D2KG@( z*D1k%EFr>%krA~=@xxX_GE?6E(ItiJK6I%mDrV2Ao(ebj4)esGW2oU(dodJ7y%7pm zIi-MQV;hF;DD!Vo}O+fBE=IHx{Fbb~k%j#4Qj4R8WI7%lCWgKIy zDOnZv%}nh8Y4rELLy;$Oiwia@LGFve>OxJK?CT;vqPQqB-j2CPwe{aF@ZzfP+~8RM zk;WX*Si7#A-P5Ke?ur(@ydE^pt>gjTHD2s?qf|t(zSNx0T)$8IW&j)#urVu|fx4m+ zpfz07RCW79eu0tN{pL?wdpL8)EJMy!w0$RQGI5WA>ET;|_f$7Kglk8syiRVs^ssfX zA4eZ*4pvTxI&>iCMqPIQk{mds@~hBH=-%I5Qlk%#QIEPo?b+RZ9f*m;i~>qYY1-4f zI4xRt8#x15SIv|e1o`&;HAN=~>Z@`IwKC~TxtBz9`+RQ`I*cZdW=7qEtVuB>^!``6Xt5;N5@efSJ-G^=-z|LQKbNp2!| zNn!8jI6F+E+i4^#4B63u9?9s>rh5ILFxDXFdqe3{O<592`~k#Ab@m6AVvQJH z3Oqb2j|(0%WJ}0jB3Mgm59t0VIR2mZ*g{HnQ0HI9n z+qs^Dk2)<$TjMv~%!#|C?h(*k`Sl!%e%7F5;eyHxLu6-S-yBj|+ML4|^-Aupb}1tm zSW;*YoZ+?ZG;2FsMt2@wQlF_^b4Gm9c+Y*l!sJ#r6vZ(iM=+#|GXxH3r|!zc zxr^OS5oGfYCAO~eD3U#sHt)R8OnNbD4vk;D_Sc>S+`ksR-xvdQ4(!uuBHEqb)Uw=&IMQJk4H~iK8og(U}u zeA*UYyNl^SQ5B2KJCkQ$_%+atBJu2Wt;%WKd5kk>7)O0oIHzafylR{GSU4uPiR@** zPGqj7`7LyM<9>!3qUtp4)7&>9Cz~xAnw}V=5NO|@stNPY_lcfo*hGBB~nOJQ&b5IyH$5Rbb?JaWbSim4>4 z*xUiX26JdkVn}oLV4DL%O0@LXS|3QeCUTg3??S+pV084%;$tc_U3nice)_OVt|@F z0b9Z!RMHPbMc3^Ewgg^mKo8nq^$uo68L_Sl2!&Up%#2#LF?l%P&H7{>j}D()wBls# zPT?{jg1X>|Jk$?J&DBN4_K_nX1$m#THD(5iDJHyWOkh6$Hi`0K7(hytv*khl{zx&) zN!Jt9`jcnse8Uy;K=2tmef$Mi2%yH2HBaI{d)#DF6EwNna2?u$>-sLj$*vtwpL6AZ z=rbBH4{d_k>AmuwHn4X72N(!{0aVk@0{AaIeENcS6-R(2Y2`tv3Jbu&*loA zRQx_mIx%TCG@o;Nh;iHJv7ev5ux!sWPmkMdpQz5Bwb_QMGOwHPFVNtf(V?Ihdre@g z*2>^N=}!lWuAhvc$IF?|v5R;26iA4nhqjASA+)uViT!|)hj&5(X~$LXcw z;G)c8(1C?$W?X6|W3r6howlK-TvOF?zJX$joh=ssjy8wDJ#c-w^c1&h*pcZO&Q|Q^ z4CHWa)ki;lh-x6wz4qrEO0+swBcV#)zrLT zH5@0MOGA@)K?Yf_M&rf)7sQKvX}^4mVWk*F)LPtXSNn12HOyZLsH=z+b>+*`+=!5_ z-lQy4tFG2K6y1A->I`!B1sM! z*<+7_u{K&3yZ*B#JpWR7QP49_S*-huLt`5xQ5ak2{-G6*jUB{Or+h=xTecq2mcx$A zKv;*M%`s&``-&r)uw8e84Y>b$iwj2J>YuMy3h>nq71=^0o7_j2&!lK3o0jCLAMOr}lT z1V)IO2vq;weH1ED{hFTEd*|oX#9My>v7tdq>0R+_w%w&&K&n0>>k{5JoNxI=F8Iw) zXUd`cX#PJRykXU`p49IBJ-x(GBThkS&$RT%Wvm2s60yT2@2CIvoOWN$Mdtk`&`Cex z;Cm-zMj>fs>oTx)h_|)v(kWB)$}y4e-^Qqgw{qZeHCisDKO5WjLULeAp2!_KlqB@% z`l1o}U8HGLV(ts1W^N~mRb~`c6Z{7kr79@teqXK~-=gdfLfAf2MdP%?N`{Zy(LF9x zi&Y@kLH5@nl0HX+HATEZ+jim(#1mch$A31v10v{-?FtI`1!N3FVbZ4W`J5Egop!W8 zbRYTX^ZRK6*3Z!-xAWzbE8j|O6);XxV_yO<7FW7UNCXouG~Z{qUSQpLmOanrL6$T< zGwXeAD=M!9QpJ9Sf-tpGCtMZ{kc9-d%DfOg*!L1cczu(ReTl8`3#ZdB2^=GacO=3v zk{*GhCo!`2k;t5cV47{CyYH{sSAk*yyH5{lXN@62YV;EqB^ST8{rPBuTB)jbix<7E zE>SkIt%owbSeny9G;r)SzwlK`n-6kvwC~D1qL05LpY3ZxE^OZ=#GW93qN1`r|4556 zSjv;8wkajEVv}S^6y_8z$J<+PzK5M0*BE!i2}2i0*b_|nHm1uhIh5l#3&9^p`h&!zdv zswO^fOWctPai$lE@Ssu!neR^L`0s}1(Sr@jEP_1lYb#!IdF4gNuT7%7Q4$wT=3{@} z@>O0*2&c5I6^*{n{(eYPy5%H=q5$NX03I#7WnFEZvz^t$e<*FGZ=G4}!?`n@DHOq+ zTIk`extBS`;mQnIM2jKaPqITS6<=5(MywtiA5Eod+!`{$ExW~d&5Kt(+^WpLb1{g$ z_Wf&@MseKTa!T%Ssm$M3T|KZrXkXt1I)9#pDr66M6q}Ho<=%A~ILtz6IJD4?K5_`5mFO0Eda2;f;Z%(fAn%=7GSzdK2QU{&e z-xfXjrgqoFn4W`y=bwv)09kKM;mdX$aJcgva39+J)g(p3(2e*4<{x`Y87_IA>`wJ3 znrh6p6!{xeR6~Z#oPJdp_)%fJ5~&0w)S&uvKNfcx#h`1P&N_u@Fi8nW0LDrmBzeFQ z!o1YSjD}Ew$8%9H&|C`l>F-hJJF9u&aRba5=8FIcl~(H9U2^lueQ6oFARLzSolRLs zW%n05W!g1tH4>fAdSb(NUS3X1Frs>}rE_?_;AmAXKNH`ZM6jTnlAg*>PjZU7p>zz< z2+asqqj)>7vD9m>ioIL!b4oYH$ak#vwKPhSPapk0E{TTU z_KBG4e%f-9tXwU$p8m>2nu+(Xz9|vfo2I34&a{-7E{9T=U*}?YI*w*vagx#*xsa+f zd15GRkHt&@H0g8)#mk3`*x|y$q4+U({0Ik+1u8@Q9@$Xr2FpOhJcq zZl*MMnBaRN!7ZeWh>o6w$3^B`NnB33YK=A7Acgl9$ZpS+ry;lU-NBzbUsjn6DFJ5G z-zRqj;~}mIq6gK2ZwB*8i_JB+?0+Vrg~XwWzLCX!BSUt{p97Bs(Fz+)7#)Q11NM{I?Zp1#xQ28Fe?XB(o z+*o2W!?)pNr>xyTygh22pIo|Mh*OO8EcNV`{SohZd9RCk)@@OsQHdz91IH|B>h1Go z;}Kl8U1EMp-Rc6WT7{v}!(3bCMfEYm^B$ZirobLxJTAU;iHgw9h5Bd2ccd*Y$nEljvu^9DaH$N$LPXe|`h zU2EJq7ZA81rTA_#vKkro?X-dAepmC}zj5pUW zJHuIwX})&&ivta#9)+PD*>%s}n#y2V#U&z-Tl^x{beFa50+~C6Kq~iMN=3diZ7c1{o zesl478TuG}T^HD=_gzX60Fy9<=jne~9JHLT^ZonhqzC>%1+tq54bufVPforBcE$ca z3vV7NVp)RyIO1_i462=)mF&u1)5CErWzVWW8Wp2i1Bxa*Kg^H zM508o7#AfX^OtbH+8+I=&j$@8q^;E|{Ac`=9B~AGNhT zS2WyQhEBLIkn(;C#0#qd@+zL<==O^0M|n92O0#HVy0dAQaBH$(R%0PZGH8o-razZv zhRj%+|Chm4{c(8(g9(?a&&cEo@O2Y1axpmn3=9oC+oh7VC zaT95yZq~zJhJB}!fHOd??-H(U!4qL%RWIux8O4#(idoFMRuGPZAO4C=9-IneX=>|Q zg&B@!m&;%T6ZK{tR`z^3q>1*Wc?PHLb-cS9mMkRX?C%F%7;O z+{$%Ihs3#$&m!f=C9-2SYYuX-O(5TpX=n|mFs62JRg7{9oTAg((1~@^jc2Y$snGzX zqEkj41W)~!Vvt6+^5=BI3>rc`Z=T^KJDD4LgHD%|Gl43oUH9L71x4B6LpK);*LR2v zR`qdx2jTK-Wl$XWoSibnul2mL=JBNo(zM<>y|Lz|cze)YeKeU@DAdJfKeR({w-m_& zHIwZAx_tO=a?h>qd|m*a>bhcSPf40bsM%cH1Ed2ItzL4lzu8N&Ce|Q>HUi(8$OXl{ zs@4Z0p|Ih>z_MU$;b}^aw)&-+cj}?P(vsutkIC=jgKs_&nOb%sbd|in!mP4wfL%kN zD8t+7vY1B>KqOv9aFuh0i*T|rqk0#lf7;mCT?9q+4@Zhom*9<9)4eAZK!+KwECnz8 z)%tn&)P2^!(8?vxO9%D<(eQt8gK?_g8X^zs2*b-?e+-mV*T%?+g6!+2-QNZ3FKDXq zOE|tst07qmn?TBV_er(b`p$rRaO`9O7GgDeh*pGoL$nJLa~nB26?Z?^#p5TmwZMznMhz%uX~fzxN?3@UEqLdA`*qkA%2UjiPV5}hwq^+oOZN7F@Fw%Tebfa~_Q z5Wd;-LXaaJ<*p}KY;1fqfJh`fusvg-hKp`4M-I1wZ;`N1U?6`ohQ};hbtfOQWQP`c z?cHFGU<)4)#tfS;cq~u>$v8wnuSo-9M3xGu?1)FtAa>64DL`8&J?&{EhgFa{F~Nj0 zCFoP5K!aiT;+)B`!oF`YQ+yybA4mq#1utVX5?*n;LC2ILrob@b_Y-s40V(k{;?2^v zb3%w)>KxlG?~3zc%jiKvv%xAlHtVz;?a^@5jZ5C{PxnR=6TRSv)B69v#;M`4r>Z^; z4OVfmR#@xn=F{@&`_k}jbrP_*7mM=5NG09FaTagFGI z=YvqdW;LnSt((5W2pp80Raz{k)~;h?--2P&)bveBuRbMOB4lN0#nQiN6zgrX$=+9T z{z?5u#`8_Ot!a41mpqX2ksu?C+LAP)DrG0>)$qY(9A%b=j98SM9vwDw7V8%`U{5?` z0h(!HP#a2jr)`a1ezfYQh5rGng6F{uSGSUnKvgA49*Xq$eWx{P)0Pz$>18F{8LWvt z-!b;Qq;$jLAA?}Jf=0l&;Vzz~oTC(~5LKvmVV2;&j3cl0i!{4YQ>9nD+nu4w6X`66AiqC~tOarppAAs?AeUp~tWUDpbj4){z2C5)8+Z%PgUPZA z0nQHLT%AGPeU9HWQA!7AeOTQVHFl9&GBB3mz>Hzv)gAD3hXw7x&>9d7kSV0II@!fR z8y<{Iz^xC5`MEDxM;6j-!J3iz_41Pmps|DS9+NI!X_AKe>SLhs))y+e*jbyw-`1zm zcz^YS;G!4FTwkohP6j51WY#TutxDSa?j=%~51iP}&jp5#1dGg5PlaK0>iP`sd{g>SZ~FLDz&0wy2+=dA**3u!6*fSo! z7&L2IwuswUNFx3<>$D|q5n_hp0MRUL$o&b$7*JGKpRotHR*|jpc=rMq=e8+O;H`~h zN$ZfO-Q{>|S z6U%Kn-3J^+wM82iT@~FoOHIua`$~hQuU6}P)(5xj#{Tv-jkXl4HrlxlcX3d5 z#C^m#iLWHSj5SRD3->G*KJtlZDMfoUltX1v`+%{yW}QsjFwoJ`bp2;xKL8S^82A|R zE~{fsOQ^*^xQcigzF2oWMN$9J|MSGCoUAvouk>sbZXm4!_v%@!q>@%>zbi9Okp&&-CU4N0ziNh~H$7+&Z(|2q6h5^G@FBD-_VpXjOu7)BQw!GE4f1d`Y|BQ)u z=n#hrM`TC%af?z(OGVcMu$!~Khz$ia7vemTTlo6H)90(oDik4__vg9kgyL&owZ6NX zqB&+qbx}jJ{V;FK5$|!W&&|6Y!Q@n#8$n^F&2%r3~pwaEo zYGp)_Uk+)en9R-YnH4V}j$~t};wv2hf5jh0b|p{e4(%2j^4CweCz8M$QWmWW=7v>T zj(gin!z2`60mJylq=}3=;K+I3H7DS#2_NAylOg|ep&tC`*?PMUrSd=*mebeGuk=yl zv=ae8*u3Oc`^l34gV{u=zBfwMj>{q^{ODaN!J`?*CdM@ z0_5~(h9`J~63}WA@2Z^E8F&3QNW5xpp?=blt{zjK$fx_%POn!VB}LcmuV;(JYvJKq z$^#o2J!&(L=E>t{P(-?n7L*(-YQl~Uw;?f{6=;3w>$3#R_FlszljD_{@%M2)wouSI z=yEWkj0vJdDBCahQp2=&u8wWsyKsH7z`?*K@URmt3;xs?uJA_Gt=AIyFC(>;plBsK zUnLKQi-t5Sx@fQ3xiDMSAVML}KK~Wf4^x5+D{~su%@=h1V&@kzi~;fXPl!R z?=UXQRo2 zwQC$oCFg8S|1C}a9fP>L+y&t5jV2ULB3(1}2^@Wtos;dIX>&?EVNI6SZf$~Ph&Rjq z#fU-AsG8yaB{$rljn;u>PzIYXLj0!3!r(AkG$do zQ<|QYQW4P^?@!;Rn2|1~!x6(9Su9+*UE~d>h>04bYG0eeYGtpiTKl@!D^FrjxMPo!-~r=j}s?MIRSde2TT z$cYe-qn{Wrq$m05kz9(7=L=~8?_*cs<AI}EHzlW2rr(09OGcYtW+v@%S0>=YV;eQETcZ>Ah2u~-7+z;w^^Wm z;>jYw)pYZ2oL7T-VhHa6jqYg9K}ozGCA=sa?kl(@zw5rCPlR5xK_wl7N{>#|dHx`) z*vJOOwE7;XQ=-I8C1X!_xpJ9@U_RfWzUii^7MH~|KgEu^*G4~}?t&+`>jw~5H%3xi z;&B%HbLP*VwA{_AP=sAl9x)2!auDa%dh(9dAIpXoh7YW-+|!*L9dL=+4I;|ABX zLAqTs+?h&T06lVvSndME4K({G|OX(!)fgue%3!=JOXWD8HXSR&h+xwR0Kh=mbXq> zZ_6f3+XcmUk0t+npU{Nq3?z+DgTp*SkN$$QRj3XQV4Pe`4vj_=^c?(Dh}Vr5p(t*b z1{>%77Iceh$234Kdi|@v(|(3*AMDnLEL45 z+&LL4@y2;uz3RT&J{Vb5tzPh$q!V?#4dHKlqaEb?Ppd;8XYkA6U1CgqZi6~-(-DRZ znZ=m>6GBb1B)X&t63fJ7W$83ubZSDncsGo?F5VNB35Yyt2tQ50pfSqEZ4Zh^wdnV z4*IvDJR`(ZuNgnYORk;$z!+&vfox*&I0LuD?7Ieea^0sKR{8;hs_%aoEW}(=*9<@V zf>OUNkz6X1wq?DG8;F$@N!(^m2r1F; zHm~Qn_@JzEum9;x?-4o$?55&c17IxBhj6j<544USQYLwt&gfqUQhNOMR&1R6-)2BZ z74>yX>w}d|Pkl>)^yizT9l!76wM7#X1I`Pjn}@6WC%{?HtI;VptN+~*Jw?xzmT3Q` zZOu9}h;5JA|8>4*l_{>)j8ny~#%?k*QLvb( zsdR0swrdQuT6W!UG>bmUyFq8 zT?{x|Cv!K%-)A*x6Mc%_8)!oqE1z#9j`z#mE$`4jexc-LzjAz0AQ>|K$^U7aXlM90 z;_`4iCXXzrdv(G*J8-&{`j7PIb?{tq#@3rEo+rzHB4cd$# z9(2g$h4>euSCKP(-{|u?s~Q7Ui-*80)?sX1PQ$44IaE^~*MmRwkV(<;>5GopFnVP) zr|9rY9L_@}PM;wgoK51%;K!c{)XW2F;!pm`R>(k0V%2W1tEo(SmMXIS4KSC%-FDw8 z9D%peZzb@$nE|j48s2Sr1(%y~WjW}Q51|b3(_6#;Vn!`4a1;&q2@0|cw7)PIw~7o>r_8vy+-k&!F6ETkNQa&*I6;?o-2spYxf%%5&R1=_{6#3|MDr61k^Cy)17>eu=dADV~@ka$a zaf<90z5mh~#)Ero3WJWJGuu${(Cf`b>_;3j`3OU^HA4Xt6oo zh?|j!Q(Y0UGb!%Re}0~G^Yx+*amvxe{&M^=>>{wv3Jq~BazSz0?!1-=NS_f^EL>Mz zCNtgNWB@61l6jfr8DrFq3))m{n5SJE;P~pZ%>^MX8QAs0$Q!KOSINGNYRh&yTZHO| z8)O-Ge0#gBPh-j+->|^Aoz%uN6)F)wHV_2fx+oBg;+d2v#7OTX|9?Eabyt*s+dVup zbc1v^DBayHUDBm=cgIlDjdTh~NOzY=w{#=jDK)^%!}q$^^ZVy~0q6RxBlh0M-oEos zZ#H~ipy1rOPd$$fUupDPX~by?++1!2va*soDH9ORR6!eGr_VRGIQyBvi3nAxXrEES z2BQDM97g6Mia=TMV$3pe-ngZmRw6tkyyk|RV96X3UA^X)@IYTgwL37|-ru=6Q=-la zal@!NcgKADr0prbbr!`9j6;Rq)w|)sEDudL@%%YWXn~uxda8GI#FU0@uMZBjih`J4 z>{R+x=M^=kjxbM0j&*E^`Ly&x}jMK@BTA`Go6V_;r&VSx!!tj`SV% z=l_4FJj~1=_@8D=m2m?N1nij}p6u9hsm?E0%c-69b82P$RU5FxH`OEVm^EB9Y`yZb zcPV{SNnx!&Z6SE7^_*ilzss4o)N^Qm2hlfy4T7JxR_%>?n!K+!nJ=~cH^w#&#hX4+ zeDZY$Bm7pl`9(}WnkJ!x%Mz9JOX_zf?Pw#{_t^yEU+ANce;JsHdhP~Js;bWpOO zlc2gPIL@kAui%iK4cUc9N8b){Jzv6Kv|Lhdoo@C-lVJ88NOzD2gD8+Iza5Z8dL?3g!=D0LY z=z%U++Mu1bUm_x!y?M`N(nz*=QLd83p+f94Hysd z(do_7&dPrxI`CJcIce8C5@x-D7h9;Sub!)w{z`1M{xAWh*(@q+UEj)lf{30qW=!nP12Z z)gYOx$T#eA!J3a=-_=t@n#K|tv?lAzLOw?!zrP5K=ey}8zY&j;)>^Y<%v#&1UI}|2 z?^%UhYE_&9i?l!yVj+n}B28Vce&u*GM^#@B_N@lyLZT$7S()k1)@d!WN+J}|@ z?@09qW_<_y1YxFXdQ98(`mx!3`R>bOV2!tznCjF@nmLI=O`sJ^Bb%0y?V*k@332lz zxAD}gm}5aJWVYA(ykPV%ETP&^kdz zMdz!>E;KGpi6)(Zdup_q6WalN%E*{S6ft+e?>~$d@olLe)}jC!twS2Wc@Jt6=+|Qn z=w!ZoXEm-{=I&(9^?YX}<@!!u#bNO^#ZY-3*f9?<9 zx%h&If*Ws^LLsl$5vwTg`}LzUmFh`Ri~o3w>s+N2jBL)%XF(-d(CUWJn4^WG{lKT< z<^mSN_Z#*Qaq&yxC975MlFP6NE7C~R?8FEAx&E2O{Zlw6tn&bz;uxhBv{+(@)|qR) z9I$!BJDHQzz7Ou68zw0d((#Zc8^#=-FZ-11Q6G|9xtvdzMP{DSf8=hIINXRDfT7V4foq|i;{MT~WTp0QKBr+W# zzgKw5xw*$vA3J0mW!Gw}OTWjLvfGu@JH2A#GO;q$OziF4;Sj#h0&lrBI>fmZQs2+; za4#*nL)3VrH6nF1jvye%+9ZIew8GM+^uCPcwJ7R$mGG|0zpT`Ky066tdS`e?Mu+%b zyn2TDo|v((XC3{R+u7;=JO9%4O|$fGkgdi+TERYn$+f;Yj{Q>!s;bC&EkILYGdcFz zk40{$mWfVd#Q+yqv}6VdcEKbp#J4!WLu=@1)?Qx0w@HRw0@BxdE=U1*^@*|04;Qcu z^PDrMSk-L@|Mk8E-fI}ikm#`6;aOsR!e?}nz3Ua&43!8~E>? z5pDhVee-TeY~RMmUP6V74rsM5Pc+|Qd8r)oT$Eow8mRgAS1zZFt3Yl5 zpKyYE&qa2=Q}e0TMkXZlIcu$3hbj@a)BEE50(&liG5Z^jvqK*f#ah@af1f^}Mm_(l zL*5?N5tF{LYP;%UHjM7%Q@~?^!|PD{sd1Ndiv&#HMmx9iDlj(&^r45^k&&SYh1E7< zO1khArUepTo_X!1?F`q0LD*_vm?TYmMWSdxbksn>-;=NrP-xXk8@1TCC_e^QA0$== zGlpl*IC%giUg2$Ud!H}q@Qqx+d_p9-`uFNso@Bem@_TuIlwWo+piYr;vBQLwZ^MIe z9E3P&F%o;p@G4)NSZLTJ{9|nrqdw~%5`-TzT-EmFMz0Gp*hNRg4jKaT8Hky@ByR*z z)@h9G&-#kLfxK8FyUWZ%CunB!YF)NZ=|OTr9hj=jBFJKZS2PZ*z<<YthJ5-wG;Qq=|6ABUXK&HW z#B;wVa4%HG=6c}7yw_{!nR+iOVNmJAA=FgnS34|6F%#-c%yjzg?O8m%R=`NV)Njt% zz9o!uwJjY+?LOKu7RRg_^(f#hwHN2Lsr;38TK-JD$)Zj%40u=bRd|}c_ z-d8CybVID=8=HyBaO1?+2e@e1O@NNH2@Ca^{I)}t$&ip*u?$wE_O8y_okX!{59|Bo z#$32F`Kp-04Sz(8fGhe9p1K|fAaMERbmNuk7kVy}iblnQdLRGZZGB+ejmY6=uKXU;-7nq%`3lx1hg~=>0Az;jD=f#M?TQx zGKAL5@KGP*^MiWkr0{nY3PzQ+A6tKIB`4k=Naz~yFc@ne7h&)j*1UzAvC+N>#r`wb z)-}1fxUl>ATup2Z@084R(Ei6p=X(BxA$K-hDE~gjQzLS);)~I4P3-mAdvgtiDuQ35 zJm2&oFq?(MqK6J?{4cv>5mX$yX9|e|2F~g=yN_;!8x$3sd;^oyHi-g09Qs322t4}Q6t!-((xq+QxpnuSo>l1(%U5laZ!D9roNkP#$TM|_gZvFi zi4BOid+D0>uFO^3*}$)InLU>7R9Vx={I0KnVaWSh;7{mX}dJ6Wlu?m+e^u+2x zRR8Nnu3(L8k5lkip!$D@^Z&cF08_(EEmNl(HJv_uIQzRZXWH#0M(EZhOI|_94?%hI zKbUM?o#{FBI`qmPa#?pu+^uqc1Hkj`11Haqx9snMTK;fHAa=_M7!b0gxs?1~?OP7m+Q+cI) zs2si#?@6Pvi{lE-X_Eh#Lc~2^;J4m6WYTv3WIH%(#54Go*&lGz69 zg8BZhwnHwC)5GSv{-PHItoVlkqmL8lZ7XgMj;{hlmKAoYRoW#LX{yE?T%V9`Zt2Da zxluow6OyBoqSVt8o3D)mO==GKYb<2wMZMSJjgkPrG509Bm*h!Z0_SHeUTjllwl zw5vXqIy?;NG%=Ug&0zZhHh!6+9UO0C&%1a^BTY@K@WSt1suNT+yFi3Wvv)rZ|A=~I zCa89g-vM{NQ~0(71k*-fGE94+F>XKRCwC>S z9GRjBcBmYDpX5lOdjqp+{1ZAqr>R>Z zTfP_c4tV>KreKI0kM>FYH{$wjY28^atLF7@?~FGYGnmW>s@5%azYkN}e-rh-2a+)s z?C$v>mQ~W%1jxDOu&!j!76*#AUl?4I4%ezcMAChYt|f$nG%u-%cS@XJ`N#QBEujut zonC)*jBKS(*S(}AJWdXG}2H&LA4z%{DXQkZ~s8muswMMlh zC9;+t9xs};61Ndcus2`#$TeS_&t6rkES1tJBC0(hC-j{v%fZ&6 zjv%tEv-(N|p95$X5h8k`16my;NtR2h=sUCMbJyN{B8-*}M;b(*2RQgZa|PYIrQ$;kH~}%LLpEiMcG9(|F_$WN^hK5OX|&D!g@L8SMUl3RqAO{OYOgw zv*$$E+P0N{ll=EyqTMcvfN&(Vy5aU zd#|(+n=#d~`6Js*T4s!*dh|JYu3Y1KcCy8IZYDTAZ6rCGpb*aWOnfA`{w_w{wSob} z{1boxw_hBlW>kgwuFQ81C#TY4qV<>GO;l|6i^aFtw8I=xPXqb_C4ypGp-S?0c9Qiv zmL85%6u(K@viSW44zRh9<_Eh;mIu>8U7R%Zc*4c;z&3(k!;N`B>U1=6>L8^f$Ckhm ziSoA)r!ddN)arQ9cZGO}s;9l@-NBuEdQz4VZ2MQ-skBqPh=bNw2jAj~6Fi$Vv87P` z;A3|!tYLK9U&T}H!z@GKR;csq(np8aEeK5Wwbd9I5aw?-CKa&O?Q_r*)cd7rbNCTj z2$K)YiaXZ|EVvjhy7;-VZY8_44x{bp(5zXT3wEJV89o-FTn}fvN@2dWe%i1XZkA*$?^Sdk6Ic+^Zmnt@)EkZV9+=TXLyOg7e*Dq zpov^T==w=UO8wIq09F{bQfq`)uz#_KpXyZ02S{Z#zl%XgM9-uuU3d*y@xJ`(q+#keF*(F7@G*5j<=%=e0~1ab8V1J#=7+U#Gk!U95R zbQ!SEyY`AHFd~NgE88D z#o`Y|7%%sd(&U(FuDGjYy#WO;=~*}akPsdn&P_%zOZu|*ymu;P0I0S2w*IdmO5cxO zmJ5bX40*?^XM5Q6K-;@c4Z%xZbq?q6>14KoKKS^G3irpOutQtd%#i}>O$iZPNjN7> zB;$z}tPz<(_H=uFuk|Xy*4@78aTwMH@8Jv0{8vo;ZR(OKtJ7Y`SN=6f?;Y$-JwXWS z6MJ3QiJkUi-7^?@_ylgd)H3ZkvcG_x_;p=nt9Y2C>Ba40tw!V>Iuh>ITnx$vp8J2& z7XMaT8MHBF-+w9IX$^xynWv$=&*Lx{7{a*43g{YVt1aD*{KX>O2=ZTl?kwdhR7qm% z+DQX}ZiBqy=QduL?i+WO<2p7-UEJg7aUz$ZT@ZyVF;Prx7r*;HoWb?D^Ox$=baRH` zHD-nazY_v6rI4M0ImTr`ita6Vc-id}_)WX)QGp3@KcjI8&f+d*Js11nbK4j6X7l5> zGq$XW3?LVS8R$q6uo22)6^@v2++GPvIvXy`x?3J57DR^DqiktC&QlXa`O{68;=#S z4J}u~L-D=13LlTQOJGLUshV@3#Bx~Pk4YDw2aO$AH-yYfNdGG@GG__{ZHbX9B9Sq- z?qrMXcdY}>ngwsIE$1d0GHZrCwg?|y`}Hb0YaoP;uSs&Le%yhdPj_N_ z8#x!IA(t^1%$qi_AjyH^pozr*ZK%i_4N3{^KP;BB2v?#x!};VBFhx0(*$iKY}#^}5pwCwR$H;KpThUlN$b-iaLy#cSNyozV<+3D}^eAl0tBDBrNU=W19b_~vxbk{7MN4_i6eW@yL!W_in~8s5UDR2Zys9hkt$%u{IOuv% z`jT83lMz`6AXuo*4Ys|eoxY!?MCyQ(@N|gqeJ#ATbhWI~PQ%ifv`FfIz=ckDZNE-i z?hCm1`Tw4K)Dl+RJ-M%fm;8lXkO**RqFt8{L?m#XliUvG9viE&_0%o{PCfX=O+#cu zzNPncKKf@Lx-fc*+0aWJY}!sVD}<7TO0ER2H}N(%RGhot{XoB|Na)%MJcTX7s$q%` zi{R8_i-+lB7@^Sxpw2CT3kxf2k8tZX3j%p)=W|Cfe84Xyunr|Zy`t-J# zi%>&Z**=8%m@$PGY5|rI!N)w-qUMxwwpw9j<}kY5oX1xXLu*{&1(m01fJa)L_3>atIPgkRbg@5;COC<#N# zln`4`s9#ixRYW-*pc58iw5Pno7FXv8P5dUz@teb*Q)?SW5-u+o+7Ar3aCm9G<>P$) z!>q&UziIfb3}KSftqU+?F}L=89rh0BmbgG4Dk%*oRL3g^u20V)zqkRScwe}NYShOO zUtgy$1{vzDKh7Jj5#wYy+Vze^S9MSD;3g8U#nForVtFTI+^{r9WDo)mY@`~{rqt=e zC79(GTrBijgwLA@&p&7?Pka5(P-qp{MTg9jz{dqAQf&THBH3Kaj#2xX_&fKqpyV3 zyV*w94^FVMUixV*L;#^j2%AuIeE#DigsClj>c0tS>%V>#cn3pcZ5`yrpY})b?@|5& ztD91Kjzw~`ay6>ZR`w)h@;-6@wC)GHZM)sVzkJ!bq!n7U^M*RLlm-qK&mHQ*2Ao-1 zDObFWpy%M{+WW-5^BW;l3JQMU^aRtRC;K6JwgT0)h3qGW(xFpv(KYqpoP+pV?#-|n z$(E?}dd9v#vnc&l;Wl3!4S5IDBjDQ(GjDOEo}xdYi;du2*%Pg7(w!n6%mexbZMa9B zEVmJ%jB0c-sKmOe!-I`HL08V&h^}|Kz}pGt5J&FH71G`CYZPT``t z(0#IZ+KhQgA3!00XaLF)7U+yv$(&}}`rS=6i67{#-g!Enr~*$H9!6nE0O=pV2Jr)K z4DviA1Wm+8Mu~kNi#ehG2w!vb*>Q!yWeDv2ZEj99m0OHCIUT7|Bt^&}8esA2qsm01 zvpf7_nq_bw2>8Gm-2{Mx*Do<)@@_m`ZgYd9u)cfn+p-)9Nx|N?;{&-jSG*rdHE&m* zI`zGVuj-3DTatx^ZNp7UDEB2@$aKxGRrh5{YVFN0s~(c`g#at2Luwccl@7AdtK++| z_ZLkTq)b!(CABn#&Dv9IlOT23=S^GD>vAq)bsuH>P6%rP#8F~`2^R6C*8=fgdq1XT(f6F6?rjZa?{#XXRv?{4`+pVEJ_mn}>PnEUM6X7>fuK@Ox$oDqQoW9?8-7py1_&b`X zZr;dZYcfSNYH@7ylPO7XsUf{Na{Ff=*(OpZKZs0DrTC)!P;-k8l#DzjaOh{Pm+vNT zW3)?K>MCX>bNHRZ5W%)IQTzL49G{#X(?4<^PwaY-p!v810r^^*5HiUM+j0zX-}xmK zAF`jm2csv>>Q5FIhst3bcf!y(bI@d1K8VV&>o8VXKec(VEy65uDocWb^7+)U4N5H% zwQ0>8Fy zFJ0koPs}yzJ2oUZu?TxugjpBQ7zd&3`?wnun*YR^e!u>>Y+F;D!`o?I$3BcI%$NSH zjtg$RuQD3Qv8_+s_fZ3%re--wb7oF(J1CHCXPdOhWA4NXLUGbNr6Tz*m<&Upq8Gsl zr;aO<9I1|D0A(;sKwwc2{GJ$aZn45agO8lJX?jmFv z_wjXD`|By@j6|TUE*N1H;NV)rfo}3|HlWQLJGl?b3DZQTNmRd0XYmL9+VES8DhYX{%i*SC5#9Ip0-ms|4>o}|Aqxm^`!ets*T1!!D8A= z&${;{$laLB#WiF}<8VcBg8MctZ`t&{2Pp76?Z zf}L9uB*{>$(ehD9{xM5~-8VCkfst1BgKl;wMci%@7FQT4a8gl%?oy|LBc1T&mdzS9 zE?XlrbxG%rNISNQ0j#u1dODkT;m{5hmHNx=W(X4xhhE;0e=FPVU5?w~CcJ-4{RD4D zwCN57K@}vu3lcA7C&m z{de02(~ewavv0fucXZxuwLl5kTcF})u+H~@T-3qo%3cF2f}ufg@QhVW##p0+|0k>L z^P)s~cm3wM7RZX}%#sqs_oM!`_OR(>Acei)=8`E`Y^B$k5vF#A`@R=?3O+=-A5;82 zhZx*j=LW-RLq;S)39vQN(8o&qYG7qS#GhY6TOxF^Km0e_StKMaGu3SSQK_uv%~4G; zvcU019EFM|CO8X@SUz_V*h;f5F-FuIB9Y*N3XDMfX%*a%J7B@{HPKDt+%C1V)dhYH z(J2^$e1BFb-N*?nQ4OL7a)vAaMcp%iLYip%24*{m52ItuF+WZ3;}d965$O{yVa>2- zDt%)2#2_L4csHA)B0*1li}=4x^)jr!F|Q}hepA{H~6~8Y!}LIl(_~V zfI~y><`_|&T0>z&G;WZ2oEm1T|HxB|fe{f`qp^-LA44XRhM*`*V`j@LT+WASG$WD3 z8i-5zhJ;Z6`>(U*k1b-56IIex=0y@nYr2LKtUso&zmbs6`~WnK7TL4+KoqiHzAK+K zU`@lQ5>(Pyt$_{Oa_w%>N2l`Swvcj0kY02E$w~@tE=%c;iwtNZ