From c02607a83eae2aa751087a11ce35e434bd31e8f7 Mon Sep 17 00:00:00 2001 From: Abdelkarim Bengrine Date: Mon, 31 Oct 2022 22:21:52 +0100 Subject: [PATCH 01/15] feat : add run feature for trello provider --- api/dvmodel.proto | 3 +- cmd/depviz/main.go | 8 ++ go.mod | 6 + go.sum | 10 ++ internal/dvcore/run.go | 33 ++++-- internal/dvmodel/dvmodel.pb.go | 190 +++++++++++++++--------------- internal/dvparser/target.go | 6 +- internal/dvserver/api.go | 8 +- internal/dvserver/server.go | 4 +- internal/dvstore/query.go | 34 ++++-- internal/trelloprovider/model.go | 69 +++++++++++ internal/trelloprovider/trello.go | 65 ++++++++++ 12 files changed, 320 insertions(+), 116 deletions(-) create mode 100644 internal/trelloprovider/model.go create mode 100644 internal/trelloprovider/trello.go diff --git a/api/dvmodel.proto b/api/dvmodel.proto index 186a5d17f..842c45ea6 100644 --- a/api/dvmodel.proto +++ b/api/dvmodel.proto @@ -145,8 +145,9 @@ message Topic { enum Driver { UnknownDriver = 0; GitHub = 1; + Trello = 2; //GitLab = 2; - //Trello = 3; + //Jira = 4; } diff --git a/cmd/depviz/main.go b/cmd/depviz/main.go index 4a1562388..751214964 100644 --- a/cmd/depviz/main.go +++ b/cmd/depviz/main.go @@ -53,6 +53,8 @@ var ( serverShutdownTimeout = serverFlags.Duration("shutdowm-timeout", 6*time.Second, "shutdown timeout") // nolint:gomnd serverCORSAllowedOrigins = serverFlags.String("cors-allowed-origins", "*", "allowed CORS origins") serverGitHubToken = serverFlags.String("github-token", "", "GitHub token") + serverTrelloToken = serverFlags.String("trello-token", "", "Trello token") + serverTrelloApiKey = serverFlags.String("trello-apikey", "", "Trello ApiKey") serverNoAutoUpdate = serverFlags.Bool("no-auto-update", false, "don't auto-update projects in background") serverGodmode = serverFlags.Bool("godmode", false, "enable dangerous API calls") serverWithPprof = serverFlags.Bool("with-pprof", false, "enable pprof endpoints") @@ -69,6 +71,8 @@ var ( runNoGraph = runFlags.Bool("no-graph", false, "don't generate graph (pull only)") runResync = runFlags.Bool("resync", false, "resync already synced content") runGitHubToken = runFlags.String("github-token", "", "GitHub token") + runTrelloToken = runFlags.String("trello-token", "", "Trello token") + runTrelloApikey = runFlags.String("trello-apikey", "", "Trello ApiKey") runNoPert = runFlags.Bool("no-pert", false, "disable PERT computing") runFormat = runFlags.String("format", "dot", "output format") runVertical = runFlags.Bool("vertical", false, "vertical mode") @@ -270,6 +274,8 @@ func execRun(ctx context.Context, args []string) error { NoPull: *runNoPull, Format: *runFormat, Resync: *runResync, + TrelloToken: *runTrelloToken, + TrelloApiKey: *runTrelloApikey, GitHubToken: *runGitHubToken, ShowClosed: *runShowClosed, HideIsolated: *runHideIsolated, @@ -314,6 +320,8 @@ func execServer(ctx context.Context, args []string) error { Realm: *serverRealm, Godmode: *serverGodmode, GitHubToken: *serverGitHubToken, + TrelloToken: *serverTrelloToken, + TrelloApiKey: *serverTrelloApiKey, NoAutoUpdate: *serverNoAutoUpdate, AutoUpdateTargets: targets, AutoUpdateInterval: *serverAutoUpdateInterval, diff --git a/go.mod b/go.mod index 61692df83..d542683ab 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ replace github.com/brianloveswords/airtable => github.com/moul/brianloveswords-a require ( github.com/Bearer/bearer-go v1.2.1 + github.com/adlio/trello v1.10.0 github.com/cayleygraph/cayley v0.7.7 github.com/cayleygraph/quad v1.2.4 github.com/go-chi/chi v4.1.2+incompatible @@ -23,6 +24,7 @@ require ( github.com/rs/cors v1.7.0 github.com/stretchr/testify v1.8.0 github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502 + github.com/tidwall/gjson v1.14.3 github.com/treastech/logger v0.0.0-20180705232552-e381e9ecf2e3 github.com/xhit/go-str2duration/v2 v2.0.0 go.uber.org/zap v1.17.0 @@ -61,6 +63,7 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/piprate/json-gold v0.3.0 // indirect github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pquerna/cachecontrol v0.0.0-20200921180117-858c6e7e6b7e // indirect github.com/prometheus/client_golang v1.8.0 // indirect @@ -71,6 +74,8 @@ require ( github.com/sirupsen/logrus v1.8.1 // indirect github.com/spf13/cobra v1.2.1 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect github.com/tylertreat/BoomFilters v0.0.0-20200520150052-42a7b4300c0c // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.7.0 // indirect @@ -81,6 +86,7 @@ require ( golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect + golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.26.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index ca8d1f8dc..3965fceb4 100644 --- a/go.sum +++ b/go.sum @@ -51,6 +51,8 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/adlio/trello v1.10.0 h1:ia/rzoBwJJKr4IqnMlrU6n09CVqeyaahSkEVcV5/gPc= +github.com/adlio/trello v1.10.0/go.mod h1:I4Lti4jf2KxjTNgTqs5W3lLuE78QZZdYbbPnQQGwjOo= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= @@ -589,7 +591,13 @@ github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpP github.com/tailscale/depaware v0.0.0-20201214215404-77d1e9757027/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8= github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502 h1:34icjjmqJ2HPjrSuJYEkdZ+0ItmGQAQ75cRHIiftIyE= github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8= +github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw= +github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/treastech/logger v0.0.0-20180705232552-e381e9ecf2e3 h1:0SnC9653NEySn3YUL1UV9o45KfQzszcOpIJ2f2BlrVg= @@ -854,6 +862,8 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/internal/dvcore/run.go b/internal/dvcore/run.go index ffe28fcc0..401749922 100644 --- a/internal/dvcore/run.go +++ b/internal/dvcore/run.go @@ -15,6 +15,7 @@ import ( "moul.io/depviz/v3/internal/dvparser" "moul.io/depviz/v3/internal/dvstore" "moul.io/depviz/v3/internal/githubprovider" + "moul.io/depviz/v3/internal/trelloprovider" "moul.io/graphman" "moul.io/graphman/viz" "moul.io/multipmuri" @@ -30,9 +31,10 @@ type RunOpts struct { // pull - GitHubToken string + GitHubToken string + TrelloToken string + TrelloApiKey string // GitLabToken string - // TrelloToken string // JiraToken string Resync bool @@ -61,7 +63,7 @@ func Run(h *cayley.Handle, args []string, opts RunOpts) error { } if !opts.NoPull { - _, err := PullAndSave(targets, h, opts.Schema, opts.GitHubToken, opts.Resync, opts.Logger) + _, err := PullAndSave(targets, h, opts.Schema, opts.GitHubToken, opts.TrelloToken, opts.TrelloApiKey, opts.Resync, opts.Logger) if err != nil { return fmt.Errorf("pull: %w", err) } @@ -76,7 +78,7 @@ func Run(h *cayley.Handle, args []string, opts RunOpts) error { WithoutPRs: opts.HidePRs, WithoutExternalDeps: opts.HideExternalDeps, } - tasks, err := dvstore.LoadTasks(h, opts.Schema, filters, opts.Logger) + tasks, err := dvstore.LoadTasks(h, opts.Schema, opts.TrelloToken, opts.TrelloApiKey, filters, opts.Logger) if err != nil { return fmt.Errorf("load tasks: %w", err) } @@ -152,8 +154,8 @@ func Run(h *cayley.Handle, args []string, opts RunOpts) error { return nil } -func PullAndSave(targets []multipmuri.Entity, h *cayley.Handle, schema *schema.Config, githubToken string, resync bool, logger *zap.Logger) (bool, error) { - batches := pullBatches(targets, h, githubToken, resync, logger) +func PullAndSave(targets []multipmuri.Entity, h *cayley.Handle, schema *schema.Config, githubToken string, trelloToken string, trelloApiKey string,resync bool, logger *zap.Logger) (bool, error) { + batches := pullBatches(targets, h, githubToken, trelloToken, trelloApiKey, resync, logger) if len(batches) > 0 { err := saveBatches(h, schema, batches) if err != nil { @@ -164,7 +166,7 @@ func PullAndSave(targets []multipmuri.Entity, h *cayley.Handle, schema *schema.C return false, nil } -func pullBatches(targets []multipmuri.Entity, h *cayley.Handle, githubToken string, resync bool, logger *zap.Logger) []dvmodel.Batch { +func pullBatches(targets []multipmuri.Entity, h *cayley.Handle, githubToken string, trelloToken string, trelloApiKey string, resync bool, logger *zap.Logger) []dvmodel.Batch { // FIXME: handle the special '@me' target var ( wg sync.WaitGroup @@ -198,6 +200,11 @@ func pullBatches(targets []multipmuri.Entity, h *cayley.Handle, githubToken stri githubprovider.FetchRepo(ctx, repo, githubToken, out, ghOpts) }(target) + case multipmuri.TrelloProvider: + go func(board multipmuri.Entity) { + defer wg.Done() + trelloprovider.FetchCard(ctx, board, trelloToken, trelloApiKey, target.LocalID()[1:], out) + }(target) default: // FIXME: clean context-based exit panic(fmt.Sprintf("unsupported provider: %v", provider)) @@ -307,6 +314,18 @@ func graphmanPertConfig(tasks []dvmodel.Task, opts RunOpts) *graphman.PertConfig // FIXME: styling }, ) + case dvmodel.Task_Card: + config.States = append( + config.States, + graphman.PertState{ + ID: string(task.ID), + Title: task.Title, + DependsOn: dependsOn, + // FIXME: auto estimate (PERT) + // FIXME: DependsOn: milestone.DependsOn + // FIXME: styling + }, + ) default: opts.Logger.Warn("unsupported task kind", zap.Stringer("kind", task.Kind)) } diff --git a/internal/dvmodel/dvmodel.pb.go b/internal/dvmodel/dvmodel.pb.go index 3ba978b67..bde0ac182 100644 --- a/internal/dvmodel/dvmodel.pb.go +++ b/internal/dvmodel/dvmodel.pb.go @@ -36,16 +36,19 @@ type Driver int32 const ( Driver_UnknownDriver Driver = 0 Driver_GitHub Driver = 1 + Driver_Trello Driver = 2 ) var Driver_name = map[int32]string{ 0: "UnknownDriver", 1: "GitHub", + 2: "Trello", } var Driver_value = map[string]int32{ "UnknownDriver": 0, "GitHub": 1, + "Trello": 2, } func (x Driver) String() string { @@ -450,101 +453,102 @@ func init() { proto.RegisterFile("dvmodel.proto", fileDescriptor_106647ce772da30 func init() { golang_proto.RegisterFile("dvmodel.proto", fileDescriptor_106647ce772da30c) } var fileDescriptor_106647ce772da30c = []byte{ - // 1503 bytes of a gzipped FileDescriptorProto + // 1510 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x58, 0x41, 0x6f, 0xdb, 0x46, 0x16, 0x16, 0x65, 0x4b, 0xb1, 0x9e, 0xe4, 0x98, 0x9e, 0x24, 0x58, 0xae, 0x77, 0x57, 0x54, 0x94, - 0xdd, 0x8d, 0xda, 0x26, 0x12, 0x9a, 0x02, 0x29, 0x10, 0xa0, 0x48, 0x2c, 0xbb, 0x49, 0x84, 0x3a, - 0xb5, 0xa1, 0xd8, 0x28, 0x90, 0xa6, 0x10, 0x46, 0xe2, 0x58, 0x9a, 0x8a, 0xe4, 0x30, 0x1c, 0xd2, - 0x46, 0xf2, 0x17, 0x7a, 0xc9, 0xa1, 0x3f, 0xa2, 0x3f, 0xa3, 0x47, 0x1f, 0x7a, 0xc8, 0xb1, 0x27, - 0xb6, 0xb1, 0xff, 0x81, 0x4e, 0x45, 0x4f, 0xc5, 0x0c, 0x49, 0x89, 0xb4, 0x94, 0x34, 0x0a, 0xdc, - 0xf4, 0x92, 0x9b, 0xf8, 0xde, 0xf7, 0xbe, 0xef, 0x0d, 0xdf, 0xcc, 0x9b, 0x47, 0xc1, 0xb2, 0x71, - 0x60, 0x31, 0x83, 0x98, 0x75, 0xc7, 0x65, 0x1e, 0x43, 0x25, 0x83, 0x38, 0x07, 0xf4, 0x59, 0x5d, - 0xda, 0xd6, 0xf4, 0x3e, 0x63, 0x7d, 0x93, 0x34, 0xa4, 0xaf, 0xeb, 0xef, 0x37, 0x3c, 0x6a, 0x11, - 0xee, 0x61, 0xcb, 0x09, 0xe1, 0x6b, 0xd7, 0xfb, 0xd4, 0x1b, 0xf8, 0xdd, 0x7a, 0x8f, 0x59, 0x8d, - 0x3e, 0xeb, 0xb3, 0x09, 0x52, 0x3c, 0xc9, 0x07, 0xf9, 0x2b, 0x84, 0x57, 0x7f, 0x2a, 0x40, 0x6e, - 0xfb, 0xd0, 0x26, 0x2e, 0xba, 0x07, 0x59, 0x6a, 0x68, 0x4a, 0x45, 0xa9, 0x15, 0x9a, 0x9f, 0x1e, - 0x07, 0x7a, 0xb6, 0xb5, 0x39, 0x0a, 0x74, 0x78, 0xe2, 0x63, 0xe3, 0x56, 0xf5, 0x0e, 0x35, 0xaa, - 0xbf, 0x07, 0xba, 0x9e, 0x20, 0xef, 0xe1, 0xa7, 0x26, 0x79, 0xda, 0x77, 0xb1, 0x33, 0x68, 0x08, - 0x50, 0xbd, 0xd5, 0x6e, 0xb5, 0xb3, 0xd4, 0x40, 0x7d, 0x80, 0x9e, 0x4b, 0xb0, 0x47, 0x8c, 0x0e, - 0xf6, 0xb4, 0x85, 0x8a, 0x52, 0x2b, 0xde, 0x58, 0xab, 0x87, 0x79, 0xd7, 0xe3, 0x6c, 0xea, 0xbb, - 0x71, 0xde, 0xcd, 0x6b, 0x47, 0x81, 0xae, 0x8c, 0x02, 0xbd, 0x12, 0x4a, 0xf1, 0xde, 0x80, 0x58, - 0xf8, 0x56, 0x44, 0xb1, 0xee, 0x5d, 0x63, 0x8e, 0x47, 0x99, 0x8d, 0xcd, 0xea, 0xf3, 0x5f, 0x74, - 0xa5, 0x5d, 0x18, 0x3b, 0x84, 0x90, 0xef, 0x18, 0xb1, 0xd0, 0xe2, 0x5b, 0x0a, 0x45, 0x14, 0xd3, - 0x42, 0x63, 0x07, 0xba, 0x0f, 0x4b, 0x26, 0xeb, 0x61, 0xb3, 0x43, 0x0d, 0x2d, 0x27, 0x5f, 0xd0, - 0xf5, 0xe3, 0x40, 0x3f, 0xb7, 0x25, 0x6c, 0xf2, 0x2d, 0x95, 0x53, 0x8c, 0x12, 0xdb, 0x32, 0x26, - 0x7c, 0xed, 0x73, 0x91, 0x09, 0x3d, 0x80, 0xc5, 0x21, 0xb5, 0x0d, 0x0d, 0x2a, 0x4a, 0xed, 0xfc, - 0x0d, 0xad, 0x9e, 0xac, 0x6d, 0x5d, 0xd6, 0xa1, 0xfe, 0x05, 0xb5, 0x8d, 0xa6, 0x3e, 0x0a, 0xf4, - 0x7f, 0xa5, 0x48, 0x45, 0x58, 0x82, 0x51, 0xd2, 0xa0, 0x0d, 0x00, 0x3e, 0x60, 0xae, 0xd7, 0xb1, - 0xb1, 0x45, 0xb4, 0xa2, 0x4c, 0xed, 0xbf, 0x53, 0x2b, 0x94, 0x90, 0x2f, 0xb1, 0x45, 0x12, 0xf1, - 0x85, 0xb1, 0x11, 0xdd, 0x81, 0xc2, 0xbe, 0x6f, 0x9a, 0x21, 0x47, 0x49, 0x72, 0x5c, 0x19, 0x05, - 0xba, 0x9e, 0xe2, 0x10, 0x88, 0x53, 0x14, 0x4b, 0xb1, 0x0d, 0x6d, 0x43, 0xde, 0x70, 0xe9, 0x01, - 0x71, 0xb5, 0x65, 0xb9, 0xae, 0x8b, 0xe9, 0x75, 0x6d, 0x4a, 0x5f, 0xf3, 0xf2, 0x28, 0xd0, 0xff, - 0x93, 0x22, 0x0d, 0x83, 0x12, 0x94, 0x11, 0x0d, 0xba, 0x0d, 0x4b, 0x03, 0x66, 0x11, 0x07, 0xf7, - 0x89, 0x76, 0xfe, 0x15, 0x19, 0xc5, 0x80, 0x64, 0x46, 0xb1, 0x0d, 0xdd, 0x87, 0xa2, 0x41, 0x78, - 0xcf, 0xa5, 0xd2, 0xa7, 0xad, 0x48, 0x8e, 0xff, 0x8f, 0x02, 0xbd, 0x9a, 0x4e, 0x60, 0x82, 0x49, - 0xd0, 0x24, 0x43, 0xd1, 0x3e, 0x14, 0xf7, 0x99, 0x3b, 0xec, 0x70, 0x0f, 0x7b, 0x3e, 0xd7, 0x54, - 0xb9, 0xc0, 0xf2, 0xac, 0xc2, 0xdd, 0x65, 0xee, 0xf0, 0xa1, 0x44, 0x35, 0xff, 0x37, 0x0a, 0xf4, - 0xcb, 0xe9, 0xf7, 0x37, 0x76, 0x26, 0x84, 0x60, 0x62, 0x45, 0x3b, 0x00, 0xf8, 0x00, 0x7b, 0xd8, - 0xed, 0xf8, 0xae, 0xa9, 0xad, 0xca, 0x84, 0x3f, 0x3e, 0x0e, 0xf4, 0xc2, 0xba, 0xb4, 0xee, 0xb5, - 0xb7, 0xa6, 0xea, 0x1a, 0xe2, 0xf7, 0x5c, 0x33, 0x59, 0xd7, 0xb1, 0x11, 0x3d, 0x86, 0xc2, 0x00, - 0xf3, 0x0e, 0x13, 0xc9, 0x69, 0x86, 0x24, 0xbc, 0x3d, 0x0a, 0x74, 0x2d, 0xe4, 0x18, 0x60, 0x2e, - 0xd3, 0x9e, 0xc4, 0xbe, 0xc9, 0xf9, 0x5e, 0x8a, 0xc3, 0xaa, 0x7b, 0xb0, 0x28, 0x76, 0x2a, 0x5a, - 0x81, 0xe2, 0x9e, 0x3d, 0xb4, 0xd9, 0xa1, 0x2d, 0x1e, 0xd5, 0x0c, 0x5a, 0x82, 0xc5, 0x3d, 0x4e, - 0x5c, 0x55, 0x41, 0x2a, 0x94, 0xb6, 0xdd, 0x3e, 0xb6, 0xe9, 0x33, 0x2c, 0x24, 0xd4, 0xac, 0xf0, - 0xed, 0x12, 0x6c, 0xa9, 0x0b, 0xe2, 0x57, 0x9b, 0x38, 0x4c, 0x5d, 0x44, 0x25, 0x58, 0xda, 0x71, - 0xd9, 0x01, 0x35, 0x88, 0xab, 0xe6, 0xaa, 0x9f, 0x01, 0x4c, 0xde, 0x23, 0xba, 0x04, 0xab, 0x11, - 0xf9, 0xc4, 0xa8, 0x66, 0x10, 0x40, 0xbe, 0xc5, 0x85, 0x45, 0x55, 0x44, 0x78, 0x8b, 0x3f, 0x64, - 0xbe, 0xdb, 0x23, 0x6a, 0xb6, 0xfa, 0xfd, 0x45, 0x58, 0xdc, 0xc5, 0x7c, 0xf8, 0xbe, 0x9b, 0xbd, - 0x8b, 0x6e, 0xb6, 0x95, 0xea, 0x66, 0xff, 0x48, 0x1f, 0x0a, 0x51, 0x86, 0xb9, 0x9a, 0xd9, 0x4d, - 0xc8, 0x79, 0xd4, 0x33, 0xe3, 0x3e, 0x56, 0x19, 0x05, 0xfa, 0xbf, 0x53, 0x51, 0xd2, 0x9b, 0x08, - 0x0b, 0xe1, 0xa7, 0xcf, 0x7a, 0xe9, 0xed, 0xcf, 0xfa, 0x99, 0xf7, 0xb1, 0xaf, 0x21, 0x6f, 0xf8, - 0xa4, 0xc3, 0x6c, 0xd9, 0xc5, 0x5e, 0x5f, 0xcf, 0x5a, 0x54, 0xcf, 0xf4, 0x9a, 0x0d, 0x9f, 0x6c, - 0xdb, 0xa7, 0x6a, 0x99, 0x93, 0x46, 0x64, 0x41, 0xa9, 0xc7, 0x2c, 0xc7, 0x24, 0xd1, 0x96, 0x59, - 0xf9, 0x53, 0x89, 0x7a, 0x24, 0x91, 0x7e, 0x31, 0x63, 0x92, 0xa9, 0x4d, 0x53, 0x4c, 0xb8, 0xd0, - 0x0e, 0xe4, 0x44, 0x0f, 0x24, 0x51, 0x0b, 0xd4, 0x66, 0x54, 0x5b, 0x1c, 0x50, 0x32, 0xa3, 0x70, - 0x32, 0x2e, 0x59, 0x38, 0x69, 0x40, 0x9b, 0x50, 0xa0, 0xbc, 0x63, 0xb2, 0xde, 0x90, 0x18, 0xb2, - 0xe3, 0x2d, 0x35, 0xaf, 0x46, 0x19, 0xa6, 0x5b, 0x3d, 0xe5, 0x5b, 0x12, 0x94, 0x6c, 0xf5, 0xb1, - 0x0d, 0xb5, 0xa0, 0x64, 0xfb, 0x56, 0xa7, 0xc7, 0x2c, 0x8b, 0xd8, 0x1e, 0xd7, 0x50, 0x45, 0xa9, - 0xe5, 0x66, 0xd4, 0xdf, 0xf6, 0xad, 0x8d, 0x08, 0x93, 0xac, 0x7f, 0xc2, 0x8c, 0xee, 0x82, 0x78, - 0xec, 0xf8, 0xce, 0x01, 0xf3, 0x08, 0xd7, 0x2e, 0x48, 0xa6, 0xe9, 0x5e, 0x6e, 0xfb, 0xd6, 0x5e, - 0x08, 0x49, 0xf6, 0xf2, 0x89, 0x15, 0x6d, 0xc1, 0xb2, 0xe0, 0x31, 0xd8, 0xa1, 0x1d, 0x32, 0x5d, - 0x94, 0x4c, 0x57, 0x47, 0x81, 0x7e, 0xe5, 0x34, 0xd3, 0x66, 0x0c, 0x4a, 0x70, 0x95, 0x92, 0x76, - 0xf4, 0x18, 0x10, 0xe1, 0x1e, 0xb5, 0x64, 0x6b, 0x30, 0x7c, 0x57, 0x36, 0x53, 0xed, 0x52, 0x78, - 0x72, 0x47, 0x81, 0xfe, 0x41, 0x8a, 0x72, 0x1a, 0x9a, 0x20, 0x5e, 0x1d, 0x7b, 0x37, 0x23, 0x27, - 0xea, 0x00, 0x88, 0x5b, 0x02, 0xfb, 0xde, 0x80, 0xc5, 0xd7, 0xc4, 0x9d, 0x51, 0xa0, 0xff, 0x73, - 0x7c, 0x4d, 0xac, 0x4b, 0xd7, 0x7c, 0xf7, 0x44, 0x61, 0x1c, 0x97, 0xbe, 0x86, 0xc8, 0x19, 0x5f, - 0x43, 0x68, 0x00, 0xcb, 0x82, 0xdd, 0xa2, 0x26, 0xe1, 0x1e, 0xb3, 0x89, 0xb6, 0x2f, 0x15, 0x36, - 0x26, 0x7b, 0x70, 0x80, 0xf9, 0x83, 0xd8, 0x3b, 0x9f, 0x4a, 0x29, 0x19, 0x8a, 0x08, 0x94, 0xe4, - 0x8b, 0xe2, 0x9c, 0xf6, 0x6d, 0x42, 0xb4, 0x7e, 0x65, 0xa1, 0x56, 0x68, 0x36, 0x27, 0xbd, 0x4d, - 0x2c, 0x39, 0x72, 0xce, 0xa7, 0x53, 0x4c, 0x44, 0xc6, 0x32, 0x2e, 0x39, 0xa0, 0xe4, 0x90, 0xb8, - 0xda, 0x60, 0x86, 0x4c, 0x3b, 0x72, 0xce, 0x2f, 0x13, 0x47, 0xc6, 0x55, 0x31, 0x71, 0x97, 0x98, - 0x1a, 0x95, 0x1a, 0xe9, 0xaa, 0x6c, 0x09, 0xcf, 0xfc, 0x55, 0x91, 0x61, 0xc8, 0x84, 0x15, 0xca, - 0x3b, 0x06, 0x71, 0x88, 0x6d, 0x50, 0xbb, 0x2f, 0x1a, 0xe0, 0xb7, 0x52, 0x63, 0x73, 0xd2, 0x3b, - 0x29, 0xdf, 0x8c, 0xfd, 0xc9, 0x0e, 0xf7, 0x26, 0x42, 0xcb, 0xa9, 0x58, 0xd4, 0x85, 0x22, 0xe5, - 0x9d, 0xae, 0x68, 0x24, 0xd4, 0xee, 0x6b, 0x43, 0xa9, 0xb4, 0x3e, 0x0a, 0xf4, 0xb5, 0x58, 0xa9, - 0x19, 0xf9, 0xe6, 0x93, 0x81, 0x49, 0x60, 0xb4, 0x22, 0x97, 0x98, 0xf2, 0x68, 0x1d, 0x52, 0x6f, - 0xa0, 0x99, 0xd3, 0x2b, 0x6a, 0x87, 0xfe, 0xaf, 0xa8, 0x37, 0x98, 0x7b, 0x45, 0x89, 0x58, 0xf4, - 0x0d, 0x00, 0xe5, 0x1d, 0x07, 0xbb, 0x5e, 0x87, 0xed, 0x6b, 0xd6, 0xe9, 0xf2, 0x50, 0xbe, 0x83, - 0x5d, 0x6f, 0x7b, 0x7f, 0xce, 0xf2, 0xc4, 0x61, 0xe8, 0x11, 0x88, 0x52, 0x49, 0x7e, 0xcd, 0x3e, - 0x1b, 0xf2, 0x73, 0x03, 0x2c, 0xe3, 0xaa, 0xdd, 0x57, 0xcd, 0x85, 0x05, 0xc8, 0xb5, 0x38, 0xf7, - 0x49, 0x38, 0x18, 0x3e, 0x20, 0x6e, 0x9f, 0xb4, 0xc9, 0x13, 0x9f, 0x70, 0x4f, 0xcd, 0xa2, 0x65, - 0x28, 0x8c, 0x4f, 0x5a, 0x38, 0x1d, 0x7e, 0xee, 0xd0, 0x9e, 0xba, 0x28, 0xa2, 0x1e, 0x7a, 0xcc, - 0x7d, 0xaa, 0xe6, 0x84, 0x71, 0x03, 0xbb, 0x86, 0x9a, 0xaf, 0x36, 0x84, 0x51, 0xdc, 0x20, 0x2a, - 0x94, 0x22, 0x11, 0xf9, 0x1c, 0x4e, 0x9f, 0xdb, 0x0e, 0xb1, 0x55, 0x45, 0x0c, 0x89, 0x1b, 0x26, - 0xe3, 0xc4, 0x50, 0xb3, 0xd5, 0xa3, 0x3c, 0xe4, 0x76, 0x99, 0x43, 0x7b, 0xef, 0xe7, 0xc2, 0xbf, - 0xfd, 0x2b, 0x57, 0xd6, 0xe1, 0x9d, 0x0c, 0x86, 0x93, 0x71, 0xae, 0x74, 0x36, 0xe3, 0xdc, 0x4d, - 0xc8, 0xf5, 0x98, 0xc9, 0xc2, 0xf1, 0x70, 0x56, 0x22, 0xd2, 0x9b, 0x4c, 0x44, 0x1a, 0x4e, 0x4f, - 0xa8, 0xe7, 0xdf, 0x7e, 0x42, 0xfd, 0x6b, 0xbf, 0xe9, 0xaa, 0xaf, 0x39, 0xbb, 0xb2, 0xb1, 0xab, - 0x4a, 0xf5, 0x3b, 0x05, 0x72, 0x4d, 0xec, 0xf5, 0x06, 0xa8, 0x06, 0x39, 0x0f, 0xf3, 0x21, 0xd7, - 0x94, 0xca, 0x42, 0xad, 0x78, 0x03, 0x4d, 0x0f, 0x84, 0xed, 0x10, 0x80, 0x3e, 0x82, 0xbc, 0xcc, - 0x98, 0x6b, 0x59, 0x09, 0xbd, 0x30, 0xe3, 0xf3, 0xb9, 0x1d, 0x41, 0x04, 0xd8, 0x13, 0x5b, 0x84, - 0x6b, 0x0b, 0xb3, 0xc0, 0x72, 0xfb, 0xb4, 0x23, 0xc8, 0x87, 0x57, 0x21, 0x1f, 0x96, 0x11, 0xad, - 0xc2, 0x72, 0x94, 0x73, 0x68, 0x08, 0x3f, 0x13, 0xef, 0x51, 0xef, 0xbe, 0xdf, 0x55, 0x95, 0x66, - 0xeb, 0xe8, 0x65, 0x39, 0xf3, 0xdb, 0xcb, 0x72, 0xe6, 0x87, 0xe3, 0x72, 0xe6, 0xe8, 0xb8, 0xac, - 0xbc, 0x38, 0x2e, 0x2b, 0xbf, 0x1e, 0x97, 0x95, 0xe7, 0x27, 0xe5, 0xcc, 0x8f, 0x27, 0x65, 0xe5, - 0xc5, 0x49, 0x39, 0xf3, 0xf3, 0x49, 0x39, 0xf3, 0x48, 0xb7, 0x98, 0x6f, 0xd6, 0x29, 0x6b, 0x84, - 0xb2, 0x0d, 0x6a, 0x7b, 0xc4, 0xb5, 0xb1, 0xd9, 0x88, 0xfe, 0x96, 0xeb, 0xe6, 0xe5, 0xa1, 0xfb, - 0xe4, 0x8f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x52, 0x5c, 0x43, 0x53, 0xa8, 0x13, 0x00, 0x00, + 0xdd, 0x8d, 0x76, 0x9b, 0x48, 0x68, 0x02, 0xa4, 0x40, 0x80, 0x22, 0xb1, 0xec, 0x26, 0x11, 0xea, + 0xd4, 0x86, 0x62, 0xa3, 0x40, 0x9a, 0x42, 0x18, 0x89, 0x63, 0x69, 0x2a, 0x92, 0xc3, 0x70, 0x48, + 0x1b, 0xc9, 0x5f, 0xe8, 0x25, 0x87, 0xfe, 0x88, 0xfe, 0x8c, 0x1e, 0x7d, 0xe8, 0x21, 0xc7, 0x9e, + 0xd8, 0xc6, 0xfe, 0x07, 0x3a, 0x15, 0x3d, 0x15, 0x33, 0x24, 0x25, 0xd2, 0x52, 0xd2, 0x28, 0x70, + 0xd3, 0x4b, 0x6e, 0xe2, 0x7b, 0xdf, 0xfb, 0xde, 0x1b, 0xbe, 0x99, 0x6f, 0x1e, 0x05, 0xcb, 0xc6, + 0x81, 0xc5, 0x0c, 0x62, 0xd6, 0x1d, 0x97, 0x79, 0x0c, 0x95, 0x0c, 0xe2, 0x1c, 0xd0, 0xe7, 0x75, + 0x69, 0x5b, 0xd3, 0xfb, 0x8c, 0xf5, 0x4d, 0xd2, 0x90, 0xbe, 0xae, 0xbf, 0xdf, 0xf0, 0xa8, 0x45, + 0xb8, 0x87, 0x2d, 0x27, 0x84, 0xaf, 0x5d, 0xef, 0x53, 0x6f, 0xe0, 0x77, 0xeb, 0x3d, 0x66, 0x35, + 0xfa, 0xac, 0xcf, 0x26, 0x48, 0xf1, 0x24, 0x1f, 0xe4, 0xaf, 0x10, 0x5e, 0xfd, 0xb1, 0x00, 0xb9, + 0xed, 0x43, 0x9b, 0xb8, 0xe8, 0x3e, 0x64, 0xa9, 0xa1, 0x29, 0x15, 0xa5, 0x56, 0x68, 0x7e, 0x72, + 0x1c, 0xe8, 0xd9, 0xd6, 0xe6, 0x28, 0xd0, 0xe1, 0xa9, 0x8f, 0x8d, 0xdb, 0xd5, 0xbb, 0xd4, 0xa8, + 0xfe, 0x16, 0xe8, 0x7a, 0x82, 0xbc, 0x87, 0x9f, 0x99, 0xe4, 0x59, 0xdf, 0xc5, 0xce, 0xa0, 0x21, + 0x40, 0xf5, 0x56, 0xbb, 0xd5, 0xce, 0x52, 0x03, 0xf5, 0x01, 0x7a, 0x2e, 0xc1, 0x1e, 0x31, 0x3a, + 0xd8, 0xd3, 0x16, 0x2a, 0x4a, 0xad, 0x78, 0x63, 0xad, 0x1e, 0xd6, 0x5d, 0x8f, 0xab, 0xa9, 0xef, + 0xc6, 0x75, 0x37, 0xaf, 0x1d, 0x05, 0xba, 0x32, 0x0a, 0xf4, 0x4a, 0x98, 0x8a, 0xf7, 0x06, 0xc4, + 0xc2, 0xb7, 0x23, 0x8a, 0x75, 0xef, 0x1a, 0x73, 0x3c, 0xca, 0x6c, 0x6c, 0x56, 0x5f, 0xfc, 0xac, + 0x2b, 0xed, 0xc2, 0xd8, 0x21, 0x12, 0xf9, 0x8e, 0x11, 0x27, 0x5a, 0x7c, 0xc7, 0x44, 0x11, 0xc5, + 0x74, 0xa2, 0xb1, 0x03, 0x3d, 0x80, 0x25, 0x93, 0xf5, 0xb0, 0xd9, 0xa1, 0x86, 0x96, 0x93, 0x2f, + 0xe8, 0xfa, 0x71, 0xa0, 0x9f, 0xdb, 0x12, 0x36, 0xf9, 0x96, 0xca, 0x29, 0x46, 0x89, 0x6d, 0x19, + 0x13, 0xbe, 0xf6, 0xb9, 0xc8, 0x84, 0x1e, 0xc2, 0xe2, 0x90, 0xda, 0x86, 0x06, 0x15, 0xa5, 0x76, + 0xfe, 0x86, 0x56, 0x4f, 0xf6, 0xb6, 0x2e, 0xfb, 0x50, 0xff, 0x9c, 0xda, 0x46, 0x53, 0x1f, 0x05, + 0xfa, 0x3f, 0x52, 0xa4, 0x22, 0x2c, 0xc1, 0x28, 0x69, 0xd0, 0x06, 0x00, 0x1f, 0x30, 0xd7, 0xeb, + 0xd8, 0xd8, 0x22, 0x5a, 0x51, 0x96, 0xf6, 0xef, 0xa9, 0x15, 0x4a, 0xc8, 0x17, 0xd8, 0x22, 0x89, + 0xf8, 0xc2, 0xd8, 0x88, 0xee, 0x42, 0x61, 0xdf, 0x37, 0xcd, 0x90, 0xa3, 0x24, 0x39, 0xae, 0x8c, + 0x02, 0x5d, 0x4f, 0x71, 0x08, 0xc4, 0x29, 0x8a, 0xa5, 0xd8, 0x86, 0xb6, 0x21, 0x6f, 0xb8, 0xf4, + 0x80, 0xb8, 0xda, 0xb2, 0x5c, 0xd7, 0xc5, 0xf4, 0xba, 0x36, 0xa5, 0xaf, 0x79, 0x79, 0x14, 0xe8, + 0xff, 0x4a, 0x91, 0x86, 0x41, 0x09, 0xca, 0x88, 0x06, 0xdd, 0x81, 0xa5, 0x01, 0xb3, 0x88, 0x83, + 0xfb, 0x44, 0x3b, 0xff, 0x9a, 0x8a, 0x62, 0x40, 0xb2, 0xa2, 0xd8, 0x86, 0x1e, 0x40, 0xd1, 0x20, + 0xbc, 0xe7, 0x52, 0xe9, 0xd3, 0x56, 0x24, 0xc7, 0x7f, 0x47, 0x81, 0x5e, 0x4d, 0x17, 0x30, 0xc1, + 0x24, 0x68, 0x92, 0xa1, 0x68, 0x1f, 0x8a, 0xfb, 0xcc, 0x1d, 0x76, 0xb8, 0x87, 0x3d, 0x9f, 0x6b, + 0xaa, 0x5c, 0x60, 0x79, 0x56, 0xe3, 0xee, 0x31, 0x77, 0xf8, 0x48, 0xa2, 0x9a, 0xff, 0x19, 0x05, + 0xfa, 0xe5, 0xf4, 0xfb, 0x1b, 0x3b, 0x13, 0x89, 0x60, 0x62, 0x45, 0x3b, 0x00, 0xf8, 0x00, 0x7b, + 0xd8, 0xed, 0xf8, 0xae, 0xa9, 0xad, 0xca, 0x82, 0x3f, 0x3e, 0x0e, 0xf4, 0xc2, 0xba, 0xb4, 0xee, + 0xb5, 0xb7, 0xa6, 0xfa, 0x1a, 0xe2, 0xf7, 0x5c, 0x33, 0xd9, 0xd7, 0xb1, 0x11, 0x3d, 0x81, 0xc2, + 0x00, 0xf3, 0x0e, 0x13, 0xc5, 0x69, 0x86, 0x24, 0xbc, 0x33, 0x0a, 0x74, 0x2d, 0xe4, 0x18, 0x60, + 0x2e, 0xcb, 0x9e, 0xc4, 0xbe, 0xcd, 0xf9, 0x5e, 0x8a, 0xc3, 0xaa, 0x7b, 0xb0, 0x28, 0x76, 0x2a, + 0x5a, 0x81, 0xe2, 0x9e, 0x3d, 0xb4, 0xd9, 0xa1, 0x2d, 0x1e, 0xd5, 0x0c, 0x5a, 0x82, 0xc5, 0x3d, + 0x4e, 0x5c, 0x55, 0x41, 0x2a, 0x94, 0xb6, 0xdd, 0x3e, 0xb6, 0xe9, 0x73, 0x2c, 0x52, 0xa8, 0x59, + 0xe1, 0xdb, 0x25, 0xd8, 0x52, 0x17, 0xc4, 0xaf, 0x36, 0x71, 0x98, 0xba, 0x88, 0x4a, 0xb0, 0xb4, + 0xe3, 0xb2, 0x03, 0x6a, 0x10, 0x57, 0xcd, 0x55, 0x3f, 0x05, 0x98, 0xbc, 0x47, 0x74, 0x09, 0x56, + 0x23, 0xf2, 0x89, 0x51, 0xcd, 0x20, 0x80, 0x7c, 0x8b, 0x0b, 0x8b, 0xaa, 0x88, 0xf0, 0x16, 0x7f, + 0xc4, 0x7c, 0xb7, 0x47, 0xd4, 0x6c, 0xf5, 0xbb, 0x8b, 0xb0, 0xb8, 0x8b, 0xf9, 0xf0, 0x83, 0x9a, + 0xbd, 0x0f, 0x35, 0xdb, 0x4a, 0xa9, 0xd9, 0xdf, 0xd2, 0x87, 0x42, 0xb4, 0x61, 0x2e, 0x31, 0xbb, + 0x05, 0x39, 0x8f, 0x7a, 0x66, 0xac, 0x63, 0x95, 0x51, 0xa0, 0xff, 0x33, 0x15, 0x25, 0xbd, 0x89, + 0xb0, 0x10, 0x7e, 0xfa, 0xac, 0x97, 0xde, 0xfd, 0xac, 0x9f, 0xb9, 0x8e, 0x7d, 0x05, 0x79, 0xc3, + 0x27, 0x1d, 0x66, 0x4b, 0x15, 0x7b, 0x73, 0x3f, 0x6b, 0x51, 0x3f, 0xd3, 0x6b, 0x36, 0x7c, 0xb2, + 0x6d, 0x9f, 0xea, 0x65, 0x4e, 0x1a, 0x91, 0x05, 0xa5, 0x1e, 0xb3, 0x1c, 0x93, 0x44, 0x5b, 0x66, + 0xe5, 0x0f, 0x53, 0xd4, 0xa3, 0x14, 0xe9, 0x17, 0x33, 0x26, 0x99, 0xda, 0x34, 0xc5, 0x84, 0x0b, + 0xed, 0x40, 0x4e, 0x68, 0x20, 0x89, 0x24, 0x50, 0x9b, 0xd1, 0x6d, 0x71, 0x40, 0xc9, 0x8c, 0xc6, + 0xc9, 0xb8, 0x64, 0xe3, 0xa4, 0x01, 0x6d, 0x42, 0x81, 0xf2, 0x8e, 0xc9, 0x7a, 0x43, 0x62, 0x48, + 0xc5, 0x5b, 0x6a, 0x5e, 0x8d, 0x2a, 0x4c, 0x4b, 0x3d, 0xe5, 0x5b, 0x12, 0x94, 0x94, 0xfa, 0xd8, + 0x86, 0x5a, 0x50, 0xb2, 0x7d, 0xab, 0xd3, 0x63, 0x96, 0x45, 0x6c, 0x8f, 0x6b, 0xa8, 0xa2, 0xd4, + 0x72, 0x33, 0xfa, 0x6f, 0xfb, 0xd6, 0x46, 0x84, 0x49, 0xf6, 0x3f, 0x61, 0x46, 0xf7, 0x40, 0x3c, + 0x76, 0x7c, 0xe7, 0x80, 0x79, 0x84, 0x6b, 0x17, 0x24, 0xd3, 0xb4, 0x96, 0xdb, 0xbe, 0xb5, 0x17, + 0x42, 0x92, 0x5a, 0x3e, 0xb1, 0xa2, 0x2d, 0x58, 0x16, 0x3c, 0x06, 0x3b, 0xb4, 0x43, 0xa6, 0x8b, + 0x92, 0xe9, 0xea, 0x28, 0xd0, 0xaf, 0x9c, 0x66, 0xda, 0x8c, 0x41, 0x09, 0xae, 0x52, 0xd2, 0x8e, + 0x9e, 0x00, 0x22, 0xdc, 0xa3, 0x96, 0x94, 0x06, 0xc3, 0x77, 0xa5, 0x98, 0x6a, 0x97, 0xc2, 0x93, + 0x3b, 0x0a, 0xf4, 0xff, 0xa5, 0x28, 0xa7, 0xa1, 0x09, 0xe2, 0xd5, 0xb1, 0x77, 0x33, 0x72, 0xa2, + 0x0e, 0x80, 0xb8, 0x25, 0xb0, 0xef, 0x0d, 0x58, 0x7c, 0x4d, 0xdc, 0x1d, 0x05, 0xfa, 0xdf, 0xc7, + 0xd7, 0xc4, 0xba, 0x74, 0xcd, 0x77, 0x4f, 0x14, 0xc6, 0x71, 0xe9, 0x6b, 0x88, 0x9c, 0xf1, 0x35, + 0x84, 0x06, 0xb0, 0x2c, 0xd8, 0x2d, 0x6a, 0x12, 0xee, 0x31, 0x9b, 0x68, 0xfb, 0x32, 0xc3, 0xc6, + 0x64, 0x0f, 0x0e, 0x30, 0x7f, 0x18, 0x7b, 0xe7, 0xcb, 0x52, 0x4a, 0x86, 0x22, 0x02, 0x25, 0xf9, + 0xa2, 0x38, 0xa7, 0x7d, 0x9b, 0x10, 0xad, 0x5f, 0x59, 0xa8, 0x15, 0x9a, 0xcd, 0x89, 0xb6, 0x89, + 0x25, 0x47, 0xce, 0xf9, 0xf2, 0x14, 0x13, 0x91, 0x71, 0x1a, 0x97, 0x1c, 0x50, 0x72, 0x48, 0x5c, + 0x6d, 0x30, 0x23, 0x4d, 0x3b, 0x72, 0xce, 0x9f, 0x26, 0x8e, 0x8c, 0xbb, 0x62, 0xe2, 0x2e, 0x31, + 0x35, 0x2a, 0x73, 0xa4, 0xbb, 0xb2, 0x25, 0x3c, 0xf3, 0x77, 0x45, 0x86, 0x21, 0x13, 0x56, 0x28, + 0xef, 0x18, 0xc4, 0x21, 0xb6, 0x41, 0xed, 0xbe, 0x10, 0xc0, 0x6f, 0x64, 0x8e, 0xcd, 0x89, 0x76, + 0x52, 0xbe, 0x19, 0xfb, 0x93, 0x0a, 0xf7, 0x36, 0x89, 0x96, 0x53, 0xb1, 0xa8, 0x0b, 0x45, 0xca, + 0x3b, 0x5d, 0x21, 0x24, 0xd4, 0xee, 0x6b, 0x43, 0x99, 0x69, 0x7d, 0x14, 0xe8, 0x6b, 0x71, 0xa6, + 0x66, 0xe4, 0x9b, 0x2f, 0x0d, 0x4c, 0x02, 0xa3, 0x15, 0xb9, 0xc4, 0x94, 0x47, 0xeb, 0x90, 0x7a, + 0x03, 0xcd, 0x9c, 0x5e, 0x51, 0x3b, 0xf4, 0x7f, 0x49, 0xbd, 0xc1, 0xdc, 0x2b, 0x4a, 0xc4, 0xa2, + 0xaf, 0x01, 0x28, 0xef, 0x38, 0xd8, 0xf5, 0x3a, 0x6c, 0x5f, 0xb3, 0x4e, 0xb7, 0x87, 0xf2, 0x1d, + 0xec, 0x7a, 0xdb, 0xfb, 0x73, 0xb6, 0x27, 0x0e, 0x43, 0x8f, 0x41, 0xb4, 0x4a, 0xf2, 0x6b, 0xf6, + 0xd9, 0x90, 0x9f, 0x1b, 0x60, 0x19, 0x57, 0xed, 0xbe, 0x6e, 0x2e, 0x2c, 0x40, 0xae, 0xc5, 0xb9, + 0x4f, 0xc2, 0xc1, 0xf0, 0x21, 0x71, 0xfb, 0xa4, 0x4d, 0x9e, 0xfa, 0x84, 0x7b, 0x6a, 0x16, 0x2d, + 0x43, 0x61, 0x7c, 0xd2, 0xc2, 0xe9, 0xf0, 0x33, 0x87, 0xf6, 0xd4, 0x45, 0x11, 0xf5, 0xc8, 0x63, + 0xee, 0x33, 0x35, 0x27, 0x8c, 0x1b, 0xd8, 0x35, 0xd4, 0x7c, 0xb5, 0x21, 0x8c, 0xe2, 0x06, 0x51, + 0xa1, 0x14, 0x25, 0x91, 0xcf, 0xe1, 0xf4, 0xb9, 0xed, 0x10, 0x5b, 0x55, 0xc4, 0x90, 0xb8, 0x61, + 0x32, 0x4e, 0x0c, 0x35, 0x5b, 0x3d, 0xca, 0x43, 0x6e, 0x97, 0x39, 0xb4, 0xf7, 0x61, 0x2e, 0xfc, + 0xcb, 0xbf, 0x72, 0x65, 0x1f, 0xde, 0xcb, 0x60, 0x38, 0x19, 0xe7, 0x4a, 0x67, 0x33, 0xce, 0xdd, + 0x82, 0x5c, 0x8f, 0x99, 0x2c, 0x1c, 0x0f, 0x67, 0x15, 0x22, 0xbd, 0xc9, 0x42, 0xa4, 0xe1, 0xf4, + 0x84, 0x7a, 0xfe, 0xdd, 0x27, 0xd4, 0x3f, 0xf7, 0x9b, 0xae, 0xfa, 0x86, 0xb3, 0x2b, 0x85, 0x5d, + 0x55, 0xaa, 0xdf, 0x2a, 0x90, 0x6b, 0x62, 0xaf, 0x37, 0x40, 0x35, 0xc8, 0x79, 0x98, 0x0f, 0xb9, + 0xa6, 0x54, 0x16, 0x6a, 0xc5, 0x1b, 0x68, 0x7a, 0x20, 0x6c, 0x87, 0x00, 0xf4, 0x11, 0xe4, 0x65, + 0xc5, 0x5c, 0xcb, 0x4a, 0xe8, 0x85, 0x19, 0x9f, 0xcf, 0xed, 0x08, 0x22, 0xc0, 0x9e, 0xd8, 0x22, + 0x5c, 0x5b, 0x98, 0x05, 0x96, 0xdb, 0xa7, 0x1d, 0x41, 0xfe, 0x7f, 0x13, 0xf2, 0x61, 0x1b, 0xd1, + 0x2a, 0x2c, 0x47, 0x35, 0x87, 0x86, 0xf0, 0x33, 0xf1, 0x3e, 0xf5, 0x1e, 0xf8, 0xdd, 0x50, 0x0d, + 0x76, 0x5d, 0x62, 0x9a, 0x4c, 0xcd, 0x36, 0x5b, 0x47, 0xaf, 0xca, 0x99, 0x5f, 0x5f, 0x95, 0x33, + 0xdf, 0x1f, 0x97, 0x33, 0x47, 0xc7, 0x65, 0xe5, 0xe5, 0x71, 0x59, 0xf9, 0xe5, 0xb8, 0xac, 0xbc, + 0x38, 0x29, 0x67, 0x7e, 0x38, 0x29, 0x2b, 0x2f, 0x4f, 0xca, 0x99, 0x9f, 0x4e, 0xca, 0x99, 0xc7, + 0xba, 0xc5, 0x7c, 0xb3, 0x4e, 0x59, 0x23, 0x2c, 0xa1, 0x41, 0x6d, 0x8f, 0xb8, 0x36, 0x36, 0x1b, + 0xd1, 0x5f, 0x74, 0xdd, 0xbc, 0x3c, 0x80, 0x37, 0x7f, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x79, 0xdd, + 0x79, 0xb7, 0xb4, 0x13, 0x00, 0x00, } func (m *Owner) Marshal() (dAtA []byte, err error) { diff --git a/internal/dvparser/target.go b/internal/dvparser/target.go index c24dfd97a..8ec4b4819 100644 --- a/internal/dvparser/target.go +++ b/internal/dvparser/target.go @@ -4,7 +4,8 @@ import "moul.io/multipmuri" func ParseTargets(args []string) ([]multipmuri.Entity, error) { targets := []multipmuri.Entity{} - defaultContext := multipmuri.NewGitHubService("") + // defaultContext := multipmuri.NewGitHubService("") + defaultContext := multipmuri.NewTrelloService() for _, arg := range args { entity, err := defaultContext.RelDecodeString(arg) if err != nil { @@ -16,6 +17,7 @@ func ParseTargets(args []string) ([]multipmuri.Entity, error) { } func ParseTarget(arg string) (multipmuri.Entity, error) { - defaultContext := multipmuri.NewGitHubService("") + // defaultContext := multipmuri.NewGitHubService("") + defaultContext := multipmuri.NewTrelloService() return defaultContext.RelDecodeString(arg) } diff --git a/internal/dvserver/api.go b/internal/dvserver/api.go index 3f723c0d0..ab1db08c4 100644 --- a/internal/dvserver/api.go +++ b/internal/dvserver/api.go @@ -138,25 +138,25 @@ func (s *service) Graph(ctx context.Context, in *Graph_Input) (*Graph_Output, er // load tasks if filters.WithFetch && gitHubToken != "" { - _, err := dvcore.PullAndSave(filters.Targets, s.h, s.schema, gitHubToken, false, s.opts.Logger) + _, err := dvcore.PullAndSave(filters.Targets, s.h, s.schema, gitHubToken, s.opts.TrelloToken, s.opts.TrelloApiKey, false, s.opts.Logger) if err != nil { return nil, fmt.Errorf("pull: %w", err) } } var tasks dvmodel.Tasks - tasks, err = dvstore.LoadTasks(s.h, s.schema, filters, s.opts.Logger) + tasks, err = dvstore.LoadTasks(s.h, s.schema, s.opts.TrelloToken, s.opts.TrelloApiKey, filters, s.opts.Logger) if err != nil { return nil, fmt.Errorf("load tasks: %w", err) } // fetch if not already in db if len(tasks) == 0 { - _, err := dvcore.PullAndSave(filters.Targets, s.h, s.schema, s.opts.GitHubToken, false, s.opts.Logger) + _, err := dvcore.PullAndSave(filters.Targets, s.h, s.schema, s.opts.GitHubToken, s.opts.TrelloToken, s.opts.TrelloApiKey, false, s.opts.Logger) if err != nil { return nil, fmt.Errorf("pull: %w", err) } - tasks, err = dvstore.LoadTasks(s.h, s.schema, filters, s.opts.Logger) + tasks, err = dvstore.LoadTasks(s.h, s.schema, s.opts.TrelloToken, s.opts.TrelloApiKey, filters, s.opts.Logger) if err != nil { return nil, fmt.Errorf("load tasks: %w", err) } diff --git a/internal/dvserver/server.go b/internal/dvserver/server.go index 08ea9a7a2..af23e1b42 100644 --- a/internal/dvserver/server.go +++ b/internal/dvserver/server.go @@ -50,6 +50,8 @@ type Opts struct { Auth string Realm string GitHubToken string + TrelloToken string + TrelloApiKey string NoAutoUpdate bool AutoUpdateTargets []multipmuri.Entity AutoUpdateInterval time.Duration @@ -275,7 +277,7 @@ func New(ctx context.Context, h *cayley.Handle, schema *schema.Config, opts Opts func (s *service) autoUpdate(targets []multipmuri.Entity) { s.opts.Logger.Debug("pull and save", zap.Any("targets", targets)) - changed, err := dvcore.PullAndSave(targets, s.h, s.schema, s.opts.GitHubToken, false, s.opts.Logger) + changed, err := dvcore.PullAndSave(targets, s.h, s.schema, s.opts.GitHubToken, s.opts.TrelloToken, s.opts.TrelloApiKey, false, s.opts.Logger) if err != nil { s.opts.Logger.Warn("pull and save", zap.Error(err)) } diff --git a/internal/dvstore/query.go b/internal/dvstore/query.go index a0bbdcb5e..86a0676d3 100644 --- a/internal/dvstore/query.go +++ b/internal/dvstore/query.go @@ -13,6 +13,7 @@ import ( "go.uber.org/zap" "moul.io/depviz/v3/internal/dvmodel" "moul.io/multipmuri" + trello "moul.io/depviz/v3/internal/trelloprovider" ) func LastUpdatedIssueInRepo(ctx context.Context, h *cayley.Handle, entity multipmuri.Entity) (time.Time, error) { // nolint:interfacer @@ -62,7 +63,7 @@ type LoadTasksFilters struct { WithFetch bool } -func LoadTasks(h *cayley.Handle, schema *schema.Config, filters LoadTasksFilters, logger *zap.Logger) (dvmodel.Tasks, error) { +func LoadTasks(h *cayley.Handle, schema *schema.Config, trelloToken string, trelloApiKey string, filters LoadTasksFilters, logger *zap.Logger) (dvmodel.Tasks, error) { if (filters.Targets == nil || len(filters.Targets) == 0) && !filters.TheWorld { return nil, fmt.Errorf("missing filter.targets") } @@ -75,13 +76,30 @@ func LoadTasks(h *cayley.Handle, schema *schema.Config, filters LoadTasksFilters paths = append(paths, path.StartPath(h)) } else { for _, target := range filters.Targets { - // FIXME: handle different target types (for now only repo) - p := path.StartPath(h, quad.IRI(target.String())). - Both(). - Has(quad.IRI("rdf:type"), quad.IRI("dv:Task")) - - // FIXME: reverse depends/blocks - paths = append(paths, p) + switch target.Provider() { + case multipmuri.GitHubProvider: + // FIXME: handle different target types (for now only repo) + p := path.StartPath(h, quad.IRI(target.String())). + Both(). + Has(quad.IRI("rdf:type"), quad.IRI("dv:Task")) + + // FIXME: reverse depends/blocks + paths = append(paths, p) + + case multipmuri.TrelloProvider: + cardsId, err := trello.GetCardsId(target.LocalID()[1:], trelloToken, trelloApiKey) + if err != nil { + return nil, fmt.Errorf("load cards id failed: %w", err) + } + for _, id := range cardsId { + p := path.StartPath(h, quad.IRI("https://trello.com/c/" + id)). + Both(). + Has(quad.IRI("rdf:type"), quad.IRI("dv:Task")) + + // FIXME: reverse depends/blocks + paths = append(paths, p) + } + } } } p := paths[0] diff --git a/internal/trelloprovider/model.go b/internal/trelloprovider/model.go new file mode 100644 index 000000000..7a0077fda --- /dev/null +++ b/internal/trelloprovider/model.go @@ -0,0 +1,69 @@ +package trelloprovider + +import ( + "fmt" + "github.com/cayleygraph/quad" + "github.com/adlio/trello" + "moul.io/depviz/v3/internal/dvmodel" + "moul.io/depviz/v3/internal/dvparser" +) + +func fromCards(cards []*trello.Card) dvmodel.Batch { + batch := dvmodel.Batch{} + for _, issue := range cards { + err := fromCard(&batch, issue) + if err != nil { + fmt.Println("error") + continue + } + } + return batch +} + +func fromCard(batch *dvmodel.Batch, input *trello.Card) error { + + entity, err := dvparser.ParseTarget(input.URL) + if err != nil { + return fmt.Errorf("parse target: %w", err) + } + + card := dvmodel.Task{ + ID: quad.IRI(entity.String()), + LocalID: entity.LocalID(), + Description: input.Desc, + Driver: dvmodel.Driver_Trello, + CreatedAt: input.DateLastActivity, + UpdatedAt: input.DateLastActivity, + Title: input.Desc , + State: dvmodel.Task_Open, + Kind: dvmodel.Task_Card, + HasOwner: quad.IRI(entity.String()), + } + + owner := dvmodel.Owner{ + ID: quad.IRI(entity.String()), + LocalID: entity.LocalID(), + Kind: dvmodel.Owner_User, + FullName: "bob t", + ShortName: "bob", + Driver: dvmodel.Driver_Trello, + Homepage: "homepage", + AvatarURL: "avatar-url", + ForkStatus: dvmodel.Owner_UnknownForkStatus, + Description: "description_owner", + } + + topic := dvmodel.Topic{ + ID: quad.IRI(entity.String()), + LocalID: entity.LocalID(), + Title: input.Name, + Description: input.Desc, + Kind: dvmodel.Topic_Label, + Driver: dvmodel.Driver_Trello, + } + + batch.Tasks = append(batch.Tasks, &card) + batch.Owners = append(batch.Owners, &owner) + batch.Topics = append(batch.Topics, &topic) + return nil +} \ No newline at end of file diff --git a/internal/trelloprovider/trello.go b/internal/trelloprovider/trello.go new file mode 100644 index 000000000..00d0a999d --- /dev/null +++ b/internal/trelloprovider/trello.go @@ -0,0 +1,65 @@ +package trelloprovider + +import ( + "context" + "fmt" + "github.com/adlio/trello" + "moul.io/multipmuri" + "moul.io/depviz/v3/internal/dvmodel" + "net/http" + "io/ioutil" + "strconv" + "github.com/tidwall/gjson" +) + +func FetchCard(ctx context.Context, entity multipmuri.Entity, token string, apikey string, boardid string, out chan<- dvmodel.Batch) { + client := trello.NewClient(apikey, token) + board, err := client.GetBoard(boardid) + if err != nil { + fmt.Println() + } + cards, _ := board.GetCards() + size := len(cards) + allcards := make([]string, size) + for i := range cards { + allcards[i] = cards[i].Name + ": " + cards[i].Desc + } + batch := fromCards(cards) + out <- batch +} + +func GetCardsId(BoardId string, token string, apikey string) ([]string, error) { + url := `https://api.trello.com/1/boards/`+ BoardId + `/cards?key=` + apikey + `&token=` + token + var cardsId []string + req, err := http.NewRequest("GET", url, nil) + + if (err != nil) { + return nil, err + } + + req.Header.Add("Content-Type", "application/json") + req.Header.Add("Accept", "application/json") + BoardGetResponse, err := http.DefaultClient.Do(req) + + if err != nil { + return nil, err + } + + defer BoardGetResponse.Body.Close() + resp, err := ioutil.ReadAll(BoardGetResponse.Body) + + if err != nil { + return nil, err + } + i := 0 + var value gjson.Result + for { + value = gjson.Get(string(resp), strconv.Itoa(i) + `.shortLink`) + if value.String() == "" { + break + } + cardsId = append(cardsId, value.String()) + i++ + } + return cardsId, nil +} \ No newline at end of file From aa48fb5e36f93136403e5032072538e4bf101b9c Mon Sep 17 00:00:00 2001 From: Abdelkarim Bengrine Date: Fri, 2 Dec 2022 20:08:21 +0100 Subject: [PATCH 02/15] del : testing code --- internal/trelloprovider/trello.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/internal/trelloprovider/trello.go b/internal/trelloprovider/trello.go index 00d0a999d..9dde557ca 100644 --- a/internal/trelloprovider/trello.go +++ b/internal/trelloprovider/trello.go @@ -19,11 +19,6 @@ func FetchCard(ctx context.Context, entity multipmuri.Entity, token string, apik fmt.Println() } cards, _ := board.GetCards() - size := len(cards) - allcards := make([]string, size) - for i := range cards { - allcards[i] = cards[i].Name + ": " + cards[i].Desc - } batch := fromCards(cards) out <- batch } From 0ece2f70cfea8dbd363720d73433be17842ad8d0 Mon Sep 17 00:00:00 2001 From: Skwyz <72012939+AbdelkarimBENGRINE@users.noreply.github.com> Date: Fri, 2 Dec 2022 20:10:34 +0100 Subject: [PATCH 03/15] Update internal/trelloprovider/trello.go clean code Co-authored-by: Isma <71719097+Doozers@users.noreply.github.com> --- internal/trelloprovider/trello.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/trelloprovider/trello.go b/internal/trelloprovider/trello.go index 9dde557ca..90240cce2 100644 --- a/internal/trelloprovider/trello.go +++ b/internal/trelloprovider/trello.go @@ -28,7 +28,7 @@ func GetCardsId(BoardId string, token string, apikey string) ([]string, error) { var cardsId []string req, err := http.NewRequest("GET", url, nil) - if (err != nil) { + if err != nil { return nil, err } From ac72d4f8e0d2b8c1a93a5a19dc17888043eafd14 Mon Sep 17 00:00:00 2001 From: Skwyz <72012939+AbdelkarimBENGRINE@users.noreply.github.com> Date: Fri, 2 Dec 2022 20:12:06 +0100 Subject: [PATCH 04/15] Update internal/trelloprovider/trello.go fix : clean code Co-authored-by: Isma <71719097+Doozers@users.noreply.github.com> --- internal/trelloprovider/trello.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/trelloprovider/trello.go b/internal/trelloprovider/trello.go index 90240cce2..dd6c3e233 100644 --- a/internal/trelloprovider/trello.go +++ b/internal/trelloprovider/trello.go @@ -35,7 +35,6 @@ func GetCardsId(BoardId string, token string, apikey string) ([]string, error) { req.Header.Add("Content-Type", "application/json") req.Header.Add("Accept", "application/json") BoardGetResponse, err := http.DefaultClient.Do(req) - if err != nil { return nil, err } From 92adc66541898b43b08d7f90cc4f95f7d7f21db2 Mon Sep 17 00:00:00 2001 From: Skwyz <72012939+AbdelkarimBENGRINE@users.noreply.github.com> Date: Fri, 2 Dec 2022 20:13:08 +0100 Subject: [PATCH 05/15] Update internal/trelloprovider/trello.go fix : clean order lines Co-authored-by: Isma <71719097+Doozers@users.noreply.github.com> --- internal/trelloprovider/trello.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/trelloprovider/trello.go b/internal/trelloprovider/trello.go index dd6c3e233..a5c5dd331 100644 --- a/internal/trelloprovider/trello.go +++ b/internal/trelloprovider/trello.go @@ -40,8 +40,8 @@ func GetCardsId(BoardId string, token string, apikey string) ([]string, error) { } defer BoardGetResponse.Body.Close() + resp, err := ioutil.ReadAll(BoardGetResponse.Body) - if err != nil { return nil, err } From 038054dea50a62eaaa3ee6930fd2eac3d1d031a0 Mon Sep 17 00:00:00 2001 From: Skwyz <72012939+AbdelkarimBENGRINE@users.noreply.github.com> Date: Fri, 2 Dec 2022 20:13:29 +0100 Subject: [PATCH 06/15] Update api/dvmodel.proto fix : reorder next provider Co-authored-by: Mikael VALLENET --- api/dvmodel.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/dvmodel.proto b/api/dvmodel.proto index 842c45ea6..c25344ff8 100644 --- a/api/dvmodel.proto +++ b/api/dvmodel.proto @@ -146,7 +146,7 @@ enum Driver { UnknownDriver = 0; GitHub = 1; Trello = 2; - //GitLab = 2; + //GitLab = 3; //Jira = 4; } From d3456fc6d47dc7f43f250431126c76a80deb939c Mon Sep 17 00:00:00 2001 From: Skwyz <72012939+AbdelkarimBENGRINE@users.noreply.github.com> Date: Fri, 2 Dec 2022 23:43:29 +0100 Subject: [PATCH 07/15] Update internal/trelloprovider/model.go fix : comment non-provided fields Co-authored-by: Manfred Touron <94029+moul@users.noreply.github.com> --- internal/trelloprovider/model.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/trelloprovider/model.go b/internal/trelloprovider/model.go index 7a0077fda..b02018ce6 100644 --- a/internal/trelloprovider/model.go +++ b/internal/trelloprovider/model.go @@ -44,13 +44,13 @@ func fromCard(batch *dvmodel.Batch, input *trello.Card) error { ID: quad.IRI(entity.String()), LocalID: entity.LocalID(), Kind: dvmodel.Owner_User, - FullName: "bob t", - ShortName: "bob", + // FullName: "bob t", + // ShortName: "bob", Driver: dvmodel.Driver_Trello, - Homepage: "homepage", - AvatarURL: "avatar-url", + // Homepage: "homepage", + // AvatarURL: "avatar-url", ForkStatus: dvmodel.Owner_UnknownForkStatus, - Description: "description_owner", + // Description: "description_owner", } topic := dvmodel.Topic{ From 08e4f07319de51fb984fbbcb4a8c8bbadad52efe Mon Sep 17 00:00:00 2001 From: Abdelkarim Bengrine Date: Sat, 3 Dec 2022 23:21:59 +0100 Subject: [PATCH 08/15] fix : setup native json --- internal/trelloprovider/trello.go | 33 ++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/internal/trelloprovider/trello.go b/internal/trelloprovider/trello.go index a5c5dd331..22c93e44d 100644 --- a/internal/trelloprovider/trello.go +++ b/internal/trelloprovider/trello.go @@ -2,16 +2,20 @@ package trelloprovider import ( "context" + "encoding/json" "fmt" + "io/ioutil" + "net/http" + "github.com/adlio/trello" - "moul.io/multipmuri" "moul.io/depviz/v3/internal/dvmodel" - "net/http" - "io/ioutil" - "strconv" - "github.com/tidwall/gjson" + "moul.io/multipmuri" ) +type Card struct { + ShortLink string +} + func FetchCard(ctx context.Context, entity multipmuri.Entity, token string, apikey string, boardid string, out chan<- dvmodel.Batch) { client := trello.NewClient(apikey, token) board, err := client.GetBoard(boardid) @@ -45,15 +49,20 @@ func GetCardsId(BoardId string, token string, apikey string) ([]string, error) { if err != nil { return nil, err } - i := 0 - var value gjson.Result - for { - value = gjson.Get(string(resp), strconv.Itoa(i) + `.shortLink`) - if value.String() == "" { + + var allCards []Card + err = json.Unmarshal(resp, &allCards) + if err != nil { + return nil, err + } + + var value string + for i := 0; i < len(allCards); i++ { + value = allCards[i].ShortLink + if value == "" { break } - cardsId = append(cardsId, value.String()) - i++ + cardsId = append(cardsId, value) } return cardsId, nil } \ No newline at end of file From 2a6e0f0a38985c0fbe6f9c34baee87c731dca45d Mon Sep 17 00:00:00 2001 From: Abdelkarim Bengrine Date: Sat, 3 Dec 2022 23:52:04 +0100 Subject: [PATCH 09/15] add : logger for error handling --- internal/dvcore/run.go | 6 +++++- internal/trelloprovider/model.go | 12 ++++++------ internal/trelloprovider/trello.go | 18 ++++++++++++++---- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/internal/dvcore/run.go b/internal/dvcore/run.go index 401749922..5d4656bd8 100644 --- a/internal/dvcore/run.go +++ b/internal/dvcore/run.go @@ -203,7 +203,11 @@ func pullBatches(targets []multipmuri.Entity, h *cayley.Handle, githubToken stri case multipmuri.TrelloProvider: go func(board multipmuri.Entity) { defer wg.Done() - trelloprovider.FetchCard(ctx, board, trelloToken, trelloApiKey, target.LocalID()[1:], out) + ghOpts := trelloprovider.Opts{ + Logger: logger.Named("trello"), + } + + trelloprovider.FetchCard(ctx, board, trelloToken, trelloApiKey, target.LocalID()[1:], out, ghOpts) }(target) default: // FIXME: clean context-based exit diff --git a/internal/trelloprovider/model.go b/internal/trelloprovider/model.go index b02018ce6..1089ddd4c 100644 --- a/internal/trelloprovider/model.go +++ b/internal/trelloprovider/model.go @@ -1,19 +1,19 @@ package trelloprovider import ( - "fmt" "github.com/cayleygraph/quad" "github.com/adlio/trello" "moul.io/depviz/v3/internal/dvmodel" "moul.io/depviz/v3/internal/dvparser" + "go.uber.org/zap" ) -func fromCards(cards []*trello.Card) dvmodel.Batch { +func fromCards(cards []*trello.Card, logger *zap.Logger) dvmodel.Batch { batch := dvmodel.Batch{} - for _, issue := range cards { - err := fromCard(&batch, issue) + for _, card := range cards { + err := fromCard(&batch, card) if err != nil { - fmt.Println("error") + logger.Warn("parse card", zap.String("url", card.URL), zap.Error(err)) continue } } @@ -24,7 +24,7 @@ func fromCard(batch *dvmodel.Batch, input *trello.Card) error { entity, err := dvparser.ParseTarget(input.URL) if err != nil { - return fmt.Errorf("parse target: %w", err) + return err } card := dvmodel.Task{ diff --git a/internal/trelloprovider/trello.go b/internal/trelloprovider/trello.go index 22c93e44d..0b02f6e8f 100644 --- a/internal/trelloprovider/trello.go +++ b/internal/trelloprovider/trello.go @@ -6,24 +6,34 @@ import ( "fmt" "io/ioutil" "net/http" - + "time" "github.com/adlio/trello" "moul.io/depviz/v3/internal/dvmodel" "moul.io/multipmuri" + "go.uber.org/zap" ) type Card struct { ShortLink string } -func FetchCard(ctx context.Context, entity multipmuri.Entity, token string, apikey string, boardid string, out chan<- dvmodel.Batch) { +type Opts struct { + Since *time.Time `json:"since"` + Logger *zap.Logger `json:"-"` +} + +func FetchCard(ctx context.Context, entity multipmuri.Entity, token string, apikey string, boardid string, out chan<- dvmodel.Batch, opts Opts) { client := trello.NewClient(apikey, token) board, err := client.GetBoard(boardid) if err != nil { fmt.Println() } - cards, _ := board.GetCards() - batch := fromCards(cards) + cards, err := board.GetCards() + if err != nil { + opts.Logger.Error(err.Error(), zap.Error(err)) + return + } + batch := fromCards(cards, opts.Logger) out <- batch } From 7722b96efa13f480ec9428ca31d5bf7dceb3a144 Mon Sep 17 00:00:00 2001 From: Abdelkarim Bengrine Date: Sat, 3 Dec 2022 23:58:07 +0100 Subject: [PATCH 10/15] fix : rename proprely variable --- internal/trelloprovider/trello.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/trelloprovider/trello.go b/internal/trelloprovider/trello.go index 0b02f6e8f..e0c9af633 100644 --- a/internal/trelloprovider/trello.go +++ b/internal/trelloprovider/trello.go @@ -48,14 +48,14 @@ func GetCardsId(BoardId string, token string, apikey string) ([]string, error) { req.Header.Add("Content-Type", "application/json") req.Header.Add("Accept", "application/json") - BoardGetResponse, err := http.DefaultClient.Do(req) + response, err := http.DefaultClient.Do(req) if err != nil { return nil, err } - defer BoardGetResponse.Body.Close() + defer response.Body.Close() - resp, err := ioutil.ReadAll(BoardGetResponse.Body) + resp, err := ioutil.ReadAll(response.Body) if err != nil { return nil, err } From 6e514364b7b75ec151087c83471c5889a403001b Mon Sep 17 00:00:00 2001 From: Abdelkarim Bengrine Date: Sun, 4 Dec 2022 00:41:10 +0100 Subject: [PATCH 11/15] add : error logger --- internal/trelloprovider/trello.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/trelloprovider/trello.go b/internal/trelloprovider/trello.go index e0c9af633..2f9a1db2b 100644 --- a/internal/trelloprovider/trello.go +++ b/internal/trelloprovider/trello.go @@ -26,7 +26,8 @@ func FetchCard(ctx context.Context, entity multipmuri.Entity, token string, apik client := trello.NewClient(apikey, token) board, err := client.GetBoard(boardid) if err != nil { - fmt.Println() + opts.Logger.Error(err.Error(), zap.Error(err)) + return } cards, err := board.GetCards() if err != nil { From 1229cc476b0615bc26548c8b7c2a69deb3c031f0 Mon Sep 17 00:00:00 2001 From: Abdelkarim Bengrine Date: Sun, 4 Dec 2022 00:46:51 +0100 Subject: [PATCH 12/15] fix : clean code with gofumpt --- internal/dvcore/run.go | 21 +++++++++++---------- internal/trelloprovider/trello.go | 1 - 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/internal/dvcore/run.go b/internal/dvcore/run.go index 5d4656bd8..525245dbf 100644 --- a/internal/dvcore/run.go +++ b/internal/dvcore/run.go @@ -154,7 +154,7 @@ func Run(h *cayley.Handle, args []string, opts RunOpts) error { return nil } -func PullAndSave(targets []multipmuri.Entity, h *cayley.Handle, schema *schema.Config, githubToken string, trelloToken string, trelloApiKey string,resync bool, logger *zap.Logger) (bool, error) { +func PullAndSave(targets []multipmuri.Entity, h *cayley.Handle, schema *schema.Config, githubToken string, trelloToken string, trelloApiKey string, resync bool, logger *zap.Logger) (bool, error) { batches := pullBatches(targets, h, githubToken, trelloToken, trelloApiKey, resync, logger) if len(batches) > 0 { err := saveBatches(h, schema, batches) @@ -200,15 +200,16 @@ func pullBatches(targets []multipmuri.Entity, h *cayley.Handle, githubToken stri githubprovider.FetchRepo(ctx, repo, githubToken, out, ghOpts) }(target) - case multipmuri.TrelloProvider: - go func(board multipmuri.Entity) { - defer wg.Done() - ghOpts := trelloprovider.Opts{ - Logger: logger.Named("trello"), - } - - trelloprovider.FetchCard(ctx, board, trelloToken, trelloApiKey, target.LocalID()[1:], out, ghOpts) - }(target) + case multipmuri.TrelloProvider: + go func(board multipmuri.Entity) { + defer wg.Done() + + ghOpts := trelloprovider.Opts{ + Logger: logger.Named("trello"), + } + + trelloprovider.FetchCard(ctx, board, trelloToken, trelloApiKey, target.LocalID()[1:], out, ghOpts) + }(target) default: // FIXME: clean context-based exit panic(fmt.Sprintf("unsupported provider: %v", provider)) diff --git a/internal/trelloprovider/trello.go b/internal/trelloprovider/trello.go index 2f9a1db2b..4dc260781 100644 --- a/internal/trelloprovider/trello.go +++ b/internal/trelloprovider/trello.go @@ -3,7 +3,6 @@ package trelloprovider import ( "context" "encoding/json" - "fmt" "io/ioutil" "net/http" "time" From 374f3749e33c916996d9f2446b12cdfa49512986 Mon Sep 17 00:00:00 2001 From: abdelkarim Date: Mon, 6 Feb 2023 15:20:37 +0100 Subject: [PATCH 13/15] feat : remove unused import --- internal/trelloprovider/trello.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/trelloprovider/trello.go b/internal/trelloprovider/trello.go index 4dc260781..8b987f009 100644 --- a/internal/trelloprovider/trello.go +++ b/internal/trelloprovider/trello.go @@ -6,10 +6,11 @@ import ( "io/ioutil" "net/http" "time" + "github.com/adlio/trello" + "go.uber.org/zap" "moul.io/depviz/v3/internal/dvmodel" "moul.io/multipmuri" - "go.uber.org/zap" ) type Card struct { @@ -21,7 +22,7 @@ type Opts struct { Logger *zap.Logger `json:"-"` } -func FetchCard(ctx context.Context, entity multipmuri.Entity, token string, apikey string, boardid string, out chan<- dvmodel.Batch, opts Opts) { +func FetchCard(ctx context.Context, entity multipmuri.Entity, token string, apikey string, boardid string, out chan<- dvmodel.Batch, opts Opts) { client := trello.NewClient(apikey, token) board, err := client.GetBoard(boardid) if err != nil { From 2a0c6cabb227b3f80039e374234d99db725c4ed5 Mon Sep 17 00:00:00 2001 From: abdelkarim Date: Mon, 6 Feb 2023 15:21:30 +0100 Subject: [PATCH 14/15] add : trello token input in front --- web/src/ui/components/Header/Menu.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/src/ui/components/Header/Menu.js b/web/src/ui/components/Header/Menu.js index 1601949a3..6ebf05287 100644 --- a/web/src/ui/components/Header/Menu.js +++ b/web/src/ui/components/Header/Menu.js @@ -15,7 +15,7 @@ const gitHubClientId = process.env.GITHUB_CLIENT_ID const baseURL = process.env.API_URL const Menu = ({ - authToken, handleShowToken, urlParams = {}, + authToken, trelloApiKey, trelloAuthToken, handleShowToken, urlParams = {}, }) => { const { updateApiData, updateLayout, updateLoadingGraph, layout, setShowInfoBox, updateUrlData, @@ -316,13 +316,13 @@ const Menu = ({ github From 0eb4e4a15e36cd84ef81a54286831b6e53ef8b21 Mon Sep 17 00:00:00 2001 From: abdelkarim Date: Mon, 6 Feb 2023 15:22:00 +0100 Subject: [PATCH 15/15] add : trello token input in front --- web/src/App.js | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/web/src/App.js b/web/src/App.js index c830a3ba4..fc4b56207 100644 --- a/web/src/App.js +++ b/web/src/App.js @@ -21,6 +21,9 @@ const defaultTargets = process.env.DEFAULT_TARGETS const App = () => { const [showAuthModal, setShowAuthModal] = useState(false) // !store.getItem('auth_token')) const [authToken, setAuthToken] = useState(store.getItem('auth_token') || '') + const [trelloApiKey, setTrelloApiKey] = useState(store.getItem('trello_api_key') || '') + const [trelloAuthToken, setTrelloAuthToken] = useState(store.getItem('trello_auth_token') || '') + const searchParams = new URLSearchParams(window.location.search) let targets = '' if (defaultTargets) { @@ -35,7 +38,7 @@ const App = () => { layout: searchParams.get('layout') || '', } - const handleChange = (e) => { + const handleChangeGit = (e) => { e.preventDefault() const token = event.target.value || '' store.setItem('auth_token', token) @@ -43,6 +46,22 @@ const App = () => { // setShowAuthModal(!token) } + const handleChangeTrelloApi = (e) => { + e.preventDefault() + const trelloApiToken = event.target.value || '' + store.setItem('trello_api_key', trelloApiToken) + setTrelloApiKey(trelloApiToken) + // setShowAuthModal(!token) + } + + const handleChangeTrelloAuth = (e) => { + e.preventDefault() + const trelloToken = event.target.value || '' + store.setItem('trello_auth_token', trelloToken) + setTrelloAuthToken(trelloToken) + // setShowAuthModal(!token) + } + const handleClose = (e) => { e.preventDefault() setShowAuthModal(false) @@ -53,7 +72,8 @@ const App = () => {
- setShowAuthModal(true)} urlParams={urlData} /> + setShowAuthModal(true)} urlParams={urlData} /> + @@ -82,9 +102,13 @@ const App = () => {
-

Enter your auth token below.

+

Enter your auth tokens below.

- + +
+ +
+