diff --git a/src/adminserver/systemcfg/systemcfg.go b/src/adminserver/systemcfg/systemcfg.go index 40d2ffff4..213a60647 100644 --- a/src/adminserver/systemcfg/systemcfg.go +++ b/src/adminserver/systemcfg/systemcfg.go @@ -256,13 +256,13 @@ func parseStringToBool(str string) (interface{}, error) { // Init system configurations. If env RESET is set or configurations // read from storage driver is null, load all configurations from env func Init() (err error) { - //init database + // init database envCfgs := map[string]interface{}{} if err := LoadFromEnv(envCfgs, true); err != nil { return err } db := GetDatabaseFromCfg(envCfgs) - //Initialize the schema, then register the DB. + // Initialize the schema, then register the DB. if err := dao.UpgradeSchema(db); err != nil { return err } @@ -273,7 +273,7 @@ func Init() (err error) { return err } - //Use reload key to avoid reset customed setting after restart + // Use reload key to avoid reset customed setting after restart curCfgs, err := CfgStore.Read() if err != nil { return err @@ -282,8 +282,8 @@ func Init() (err error) { if curCfgs == nil { curCfgs = map[string]interface{}{} } - //restart: only repeatload envs will be load - //reload_config: all envs will be reload except the skiped envs + // restart: only repeatload envs will be load + // reload_config: all envs will be reload except the skiped envs if err = LoadFromEnv(curCfgs, loadAll); err != nil { return err } @@ -312,7 +312,7 @@ func initCfgStore() (err error) { if err != nil { return err } - //migration check: if no data in the db , then will try to load from path + // migration check: if no data in the db , then will try to load from path m, err := CfgStore.Read() if err != nil { return err @@ -453,7 +453,7 @@ func validLdapScope(cfg map[string]interface{}, isMigrate bool) { } -//AddMissedKey ... If the configure key is missing in the cfg map, add default value to it +// AddMissedKey ... If the configure key is missing in the cfg map, add default value to it func AddMissedKey(cfg map[string]interface{}) { for k, v := range common.HarborStringKeysMap { diff --git a/src/adminserver/systemcfg/systemcfg_test.go b/src/adminserver/systemcfg/systemcfg_test.go index 70c036f19..1d75e719a 100644 --- a/src/adminserver/systemcfg/systemcfg_test.go +++ b/src/adminserver/systemcfg/systemcfg_test.go @@ -199,7 +199,7 @@ func TestLoadFromEnvWithReloadConfigSkipPattern(t *testing.T) { if err != nil { t.Fatalf("failed to load From env: %v", err) } - assert.Equal(t, "ldap_url", cfgsReload[common.LDAPURL]) //env value ignored + assert.Equal(t, "ldap_url", cfgsReload[common.LDAPURL]) // env value ignored os.Clearenv() diff --git a/src/chartserver/base_handler.go b/src/chartserver/base_handler.go index b3df173ae..2cd55e2d1 100644 --- a/src/chartserver/base_handler.go +++ b/src/chartserver/base_handler.go @@ -4,14 +4,14 @@ import ( "net/http" ) -//BaseHandler defines the handlers related with the chart server itself. +// BaseHandler defines the handlers related with the chart server itself. type BaseHandler struct { - //Proxy used to to transfer the traffic of requests - //It's mainly used to talk to the backend chart server + // Proxy used to to transfer the traffic of requests + // It's mainly used to talk to the backend chart server trafficProxy *ProxyEngine } -//GetHealthStatus will return the health status of the backend chart repository server +// GetHealthStatus will return the health status of the backend chart repository server func (bh *BaseHandler) GetHealthStatus(w http.ResponseWriter, req *http.Request) { bh.trafficProxy.ServeHTTP(w, req) } diff --git a/src/chartserver/base_test.go b/src/chartserver/base_test.go index 6d5167d23..ab7bc4c72 100644 --- a/src/chartserver/base_test.go +++ b/src/chartserver/base_test.go @@ -15,7 +15,7 @@ import ( "github.com/goharbor/harbor/src/ui/promgr/metamgr" ) -//The backend server +// The backend server var mockServer = httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.RequestURI { case "/health": @@ -70,10 +70,10 @@ var mockServer = httptest.NewUnstartedServer(http.HandlerFunc(func(w http.Respon w.Write([]byte("not supported")) })) -//Chart controller reference +// Chart controller reference var mockController *Controller -//The frontend server +// The frontend server var frontServer = httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.RequestURI == "/health" && r.Method == http.MethodGet { mockController.GetBaseHandler().GetHealthStatus(w, r) @@ -140,10 +140,10 @@ var frontServer = httptest.NewUnstartedServer(http.HandlerFunc(func(w http.Respo w.Write([]byte(fmt.Sprintf("no handler to handle %s", r.RequestURI))) })) -//Http client +// Http client var httpClient = NewChartClient(nil) -//Mock project manager +// Mock project manager type mockProjectManager struct{} func (mpm *mockProjectManager) Get(projectIDOrName interface{}) (*models.Project, error) { @@ -191,8 +191,8 @@ func (mpm *mockProjectManager) GetMetadataManager() metamgr.ProjectMetadataManag return nil } -//Utility methods -//Start the mock frontend and backend servers +// Utility methods +// Start the mock frontend and backend servers func startMockServers() error { mockServer.Start() backendURL, err := url.Parse(getTheAddrOfMockServer()) @@ -209,23 +209,23 @@ func startMockServers() error { return nil } -//Stop the mock frontend and backend servers +// Stop the mock frontend and backend servers func stopMockServers() { frontServer.Close() mockServer.Close() } -//Get the address of the backend mock server +// Get the address of the backend mock server func getTheAddrOfMockServer() string { return mockServer.URL } -//Get the address of the frontend server +// Get the address of the frontend server func getTheAddrOfFrontServer() string { return frontServer.URL } -//Mock content +// Mock content var harborChartV = ` { "name": "harbor", @@ -369,7 +369,7 @@ entries: generated: "2018-07-10T13:45:05+08:00" ` -//Mocker binary data +// Mocker binary data var chartListContent = []byte{0x7b, 0x22, 0x68, 0x61, 0x72, 0x62, 0x6f, 0x72, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x22, 0x68, 0x61, 0x72, 0x62, 0x6f, 0x72, 0x22, 0x2c, 0x22, 0x68, 0x6f, 0x6d, 0x65, 0x22, 0x3a, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x2f, 0x68, 0x61, 0x72, 0x62, 0x6f, 0x72, 0x22, 0x2c, 0x22, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x2f, 0x68, 0x61, 0x72, 0x62, 0x6f, 0x72, 0x2f, 0x74, 0x72, 0x65, 0x65, 0x2f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x2f, 0x68, 0x65, 0x6c, 0x6d, 0x2f, 0x68, 0x61, 0x72, 0x62, 0x6f, 0x72, 0x22, 0x5d, 0x2c, 0x22, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x30, 0x2e, 0x32, 0x2e, 0x30, 0x22, 0x2c, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x41, 0x6e, 0x20, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x2d, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x44, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x20, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x20, 0x62, 0x79, 0x20, 0x56, 0x4d, 0x77, 0x61, 0x72, 0x65, 0x22, 0x2c, 0x22, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x76, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x22, 0x2c, 0x22, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x22, 0x2c, 0x22, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x22, 0x2c, 0x22, 0x68, 0x61, 0x72, 0x62, 0x6f, 0x72, 0x22, 0x5d, 0x2c, 0x22, 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x22, 0x4a, 0x65, 0x73, 0x73, 0x65, 0x20, 0x48, 0x75, 0x22, 0x2c, 0x22, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x3a, 0x22, 0x68, 0x75, 0x68, 0x40, 0x76, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x22, 0x7d, 0x2c, 0x7b, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x22, 0x70, 0x61, 0x75, 0x6c, 0x63, 0x7a, 0x61, 0x72, 0x22, 0x2c, 0x22, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x3a, 0x22, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x2e, 0x74, 0x61, 0x6b, 0x65, 0x6e, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x22, 0x7d, 0x5d, 0x2c, 0x22, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x22, 0x3a, 0x22, 0x67, 0x6f, 0x74, 0x70, 0x6c, 0x22, 0x2c, 0x22, 0x69, 0x63, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x2f, 0x68, 0x61, 0x72, 0x62, 0x6f, 0x72, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x64, 0x6f, 0x63, 0x73, 0x2f, 0x69, 0x6d, 0x67, 0x2f, 0x68, 0x61, 0x72, 0x62, 0x6f, 0x72, 0x5f, 0x6c, 0x6f, 0x67, 0x6f, 0x2e, 0x70, 0x6e, 0x67, 0x22, 0x2c, 0x22, 0x61, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x31, 0x2e, 0x35, 0x2e, 0x30, 0x22, 0x2c, 0x22, 0x75, 0x72, 0x6c, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x63, 0x68, 0x61, 0x72, 0x74, 0x73, 0x2f, 0x68, 0x61, 0x72, 0x62, 0x6f, 0x72, 0x2d, 0x30, 0x2e, 0x32, 0x2e, 0x30, 0x2e, 0x74, 0x67, 0x7a, 0x22, 0x5d, 0x2c, 0x22, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x3a, 0x22, 0x32, 0x30, 0x31, 0x38, 0x2d, 0x30, 0x37, 0x2d, 0x30, 0x35, 0x54, 0x31, 0x39, 0x3a, 0x34, 0x38, 0x3a, 0x32, 0x30, 0x2e, 0x31, 0x36, 0x39, 0x38, 0x30, 0x36, 0x35, 0x31, 0x39, 0x2b, 0x30, 0x38, 0x3a, 0x30, 0x30, 0x22, 0x2c, 0x22, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x22, 0x37, 0x35, 0x38, 0x61, 0x65, 0x34, 0x32, 0x39, 0x66, 0x33, 0x36, 0x32, 0x32, 0x30, 0x30, 0x61, 0x37, 0x39, 0x34, 0x31, 0x63, 0x36, 0x30, 0x30, 0x63, 0x38, 0x31, 0x31, 0x32, 0x63, 0x63, 0x33, 0x31, 0x32, 0x32, 0x37, 0x32, 0x33, 0x62, 0x39, 0x39, 0x66, 0x66, 0x61, 0x35, 0x37, 0x31, 0x33, 0x61, 0x30, 0x39, 0x30, 0x32, 0x39, 0x30, 0x32, 0x64, 0x61, 0x39, 0x39, 0x34, 0x39, 0x62, 0x61, 0x22, 0x7d, 0x5d, 0x2c, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2d, 0x68, 0x65, 0x6c, 0x6d, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2d, 0x68, 0x65, 0x6c, 0x6d, 0x22, 0x2c, 0x22, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x30, 0x2e, 0x31, 0x2e, 0x38, 0x22, 0x2c, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x41, 0x20, 0x48, 0x65, 0x6c, 0x6d, 0x20, 0x63, 0x68, 0x61, 0x72, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x22, 0x2c, 0x22, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x76, 0x31, 0x22, 0x2c, 0x22, 0x61, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x31, 0x2e, 0x32, 0x22, 0x2c, 0x22, 0x75, 0x72, 0x6c, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x63, 0x68, 0x61, 0x72, 0x74, 0x73, 0x2f, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2d, 0x68, 0x65, 0x6c, 0x6d, 0x2d, 0x30, 0x2e, 0x31, 0x2e, 0x38, 0x2e, 0x74, 0x67, 0x7a, 0x22, 0x5d, 0x2c, 0x22, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x3a, 0x22, 0x32, 0x30, 0x31, 0x38, 0x2d, 0x30, 0x37, 0x2d, 0x31, 0x30, 0x54, 0x31, 0x33, 0x3a, 0x34, 0x34, 0x3a, 0x35, 0x30, 0x2e, 0x33, 0x35, 0x30, 0x32, 0x32, 0x32, 0x36, 0x39, 0x35, 0x2b, 0x30, 0x38, 0x3a, 0x30, 0x30, 0x22, 0x2c, 0x22, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x22, 0x30, 0x61, 0x30, 0x61, 0x62, 0x33, 0x65, 0x62, 0x39, 0x35, 0x64, 0x36, 0x33, 0x34, 0x66, 0x37, 0x61, 0x31, 0x39, 0x66, 0x63, 0x63, 0x30, 0x39, 0x30, 0x35, 0x31, 0x34, 0x39, 0x63, 0x32, 0x65, 0x61, 0x64, 0x31, 0x38, 0x31, 0x32, 0x65, 0x64, 0x62, 0x62, 0x64, 0x37, 0x65, 0x35, 0x63, 0x61, 0x38, 0x31, 0x35, 0x36, 0x35, 0x36, 0x64, 0x37, 0x35, 0x35, 0x35, 0x33, 0x62, 0x65, 0x34, 0x65, 0x22, 0x7d, 0x2c, 0x7b, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2d, 0x68, 0x65, 0x6c, 0x6d, 0x22, 0x2c, 0x22, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x30, 0x2e, 0x31, 0x2e, 0x30, 0x22, 0x2c, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x41, 0x20, 0x48, 0x65, 0x6c, 0x6d, 0x20, 0x63, 0x68, 0x61, 0x72, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x22, 0x2c, 0x22, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x76, 0x31, 0x22, 0x2c, 0x22, 0x61, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x31, 0x2e, 0x30, 0x22, 0x2c, 0x22, 0x75, 0x72, 0x6c, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x63, 0x68, 0x61, 0x72, 0x74, 0x73, 0x2f, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2d, 0x68, 0x65, 0x6c, 0x6d, 0x2d, 0x30, 0x2e, 0x31, 0x2e, 0x30, 0x2e, 0x74, 0x67, 0x7a, 0x22, 0x5d, 0x2c, 0x22, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x3a, 0x22, 0x32, 0x30, 0x31, 0x38, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x31, 0x54, 0x31, 0x37, 0x3a, 0x35, 0x31, 0x3a, 0x34, 0x30, 0x2e, 0x31, 0x39, 0x34, 0x33, 0x37, 0x35, 0x34, 0x31, 0x37, 0x2b, 0x30, 0x38, 0x3a, 0x30, 0x30, 0x22, 0x2c, 0x22, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x22, 0x66, 0x61, 0x62, 0x39, 0x32, 0x33, 0x65, 0x61, 0x65, 0x33, 0x36, 0x36, 0x38, 0x65, 0x30, 0x64, 0x34, 0x38, 0x30, 0x65, 0x39, 0x64, 0x65, 0x63, 0x31, 0x31, 0x30, 0x64, 0x38, 0x31, 0x34, 0x61, 0x37, 0x35, 0x39, 0x39, 0x37, 0x38, 0x39, 0x63, 0x33, 0x32, 0x37, 0x64, 0x39, 0x30, 0x37, 0x61, 0x65, 0x31, 0x61, 0x66, 0x62, 0x37, 0x61, 0x62, 0x35, 0x37, 0x35, 0x64, 0x63, 0x36, 0x30, 0x64, 0x22, 0x7d, 0x5d, 0x7d} var helmChartContent = []byte{0x1f, 0x8b, 0x8, 0x14, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x29, 0x0, 0x2b, 0x61, 0x48, 0x52, 0x30, 0x63, 0x48, 0x4d, 0x36, 0x4c, 0x79, 0x39, 0x35, 0x62, 0x33, 0x56, 0x30, 0x64, 0x53, 0x35, 0x69, 0x5a, 0x53, 0x39, 0x36, 0x4f, 0x56, 0x56, 0x36, 0x4d, 0x57, 0x6c, 0x6a, 0x61, 0x6e, 0x64, 0x79, 0x54, 0x51, 0x6f, 0x3d, 0x48, 0x65, 0x6c, 0x6d, 0x0, 0xec, 0xfd, 0x7b, 0x77, 0xe2, 0x38, 0xb3, 0x28, 0xe, 0xef, 0xbf, 0xf9, 0x14, 0x7a, 0xd3, 0xe7, 0x9c, 0x99, 0xee, 0x34, 0x60, 0xee, 0x97, 0x77, 0xcf, 0xde, 0xf, 0xb7, 0x0, 0xe1, 0x1a, 0x2e, 0x49, 0xc8, 0x9c, 0x59, 0x89, 0xb0, 0x5, 0x28, 0xd8, 0x96, 0x63, 0xd9, 0x10, 0x32, 0x3d, 0xe7, 0xb3, 0xff, 0x96, 0x24, 0xdb, 0x18, 0x30, 0x21, 0xf7, 0x9e, 0x79, 0x76, 0xb4, 0xd6, 0x4c, 0x7, 0x5b, 0x55, 0x2a, 0xc9, 0x55, 0xa5, 0x52, 0xa9, 0x54, 0x9a, 0x41, 0x73, 0x4c, 0xcc, 0x68, 0x69, 0x6, 0x4d, 0x2b, 0xb2, 0x82, 0x9a, 0xfa, 0x1f, 0x6f, 0x5f, 0x24, 0x49, 0x92, 0x32, 0xa9, 0x14, 0xff, 0x57, 0x92, 0xa4, 0xed, 0x7f, 0xa5, 0x4c, 0x2c, 0xe3, 0xfd, 0xcd, 0x9f, 0xc7, 0xe2, 0x89, 0x44, 0xe6, 0x3f, 0xc0, 0x3b, 0x90, 0xb2, 0x5b, 0x6c, 0x6a, 0x41, 0xf3, 0x3f, 0x24, 0xe9, 0xb5, 0x78, 0xb6, 0x3b, 0xf7, 0xf, 0x29, 0xd0, 0x30, 0xce, 0x91, 0x49, 0x31, 0xd1, 0xf3, 0x20, 0x16, 0x49, 0x45, 0xa4, 0x90, 0x82, 0xa8, 0x6c, 0x62, 0xc3, 0xe2, 0x8f, 0xa, 0x3a, 0xa8, 0xe8, 0x16, 0x32, 0xd, 0x13, 0x53, 0x14, 0x96, 0x55, 0x48, 0x29, 0x28, 0x13, 0x79, 0x8e, 0x4c, 0xd0, 0x43, 0x53, 0x4c, 0x2d, 0x73, 0x5, 0xc6, 0x2b, 0x70, 0xde, 0x5a, 0x42, 0x13, 0x85, 0x90, 0x3e, 0xc5, 0x3a, 0xca, 0x83, 0x29, 0xb1, 0xc, 0x35, 0x34, 0x23, 0x1a, 0xca, 0x83, 0x99, 0x65, 0x19, 0x34, 0x1f, 0x8d, 0x4e, 0xb1, 0x35, 0xb3, 0xc7, 0x11, 0x99, 0x68, 0xd1, 0x85, 0xc6, 0x6a, 0x47, 0x5, 0xeb, 0x85, 0xb0, 0xcc, 0x1a, 0x3a, 0x54, 0x2d, 0x3a, 0x56, 0xc9, 0x38, 0xaa, 0x41, 0x6a, 0x21, 0x33, 0xaa, 0x10, 0x99, 0x46, 0xb1, 0x36, 0x75, 0xde, 0x5d, 0xab, 0x64, 0x4a, 0x22, 0x86, 0x3e, 0xd, 0xcd, 0xd1, 0x6a, 0x49, 0x4c, 0x85, 0xe6, 0x43, 0x61, 0x20, 0xc0, 0x43, 0x61, 0xa0, 0x70, 0x7a, 0x43, 0x61, 0x60, 0x3a, 0x14, 0x87, 0xc2, 0xc0, 0x69, 0x5b, 0x83, 0x58, 0xb7, 0x20, 0xd6, 0x91, 0xc9, 0x41, 0x90, 0x6, 0xb1, 0x9a, 0x7, 0x33, 0x7b, 0xf6, 0x2f, 0x1, 0xcd, 0xe8, 0x8, 0x1, 0xa0, 0x43, 0xd6, 0x93, 0x53, 0x44, 0x29, 0x2, 0x35, 0x7b, 0x5d, 0xd1, 0xa6, 0xc8, 0x64, 0xef, 0x22, 0x16, 0x9c, 0x23, 0xfd, 0x5f, 0x53, 0xf6, 0x74, 0x3, 0xc4, 0x80, 0xb6, 0x2a, 0x3f, 0x40, 0x33, 0x24, 0x7e, 0x3a, 0xad, 0x52, 0x62, 0x9b, 0x32, 0xe2, 0x2d, 0x1e, 0xec, 0xb6, 0x65, 0x22, 0xe4, 0x76, 0x5b, 0x26, 0xba, 0x65, 0xe2, 0x71, 0x74, 0x86, 0x54, 0xcd, 0x1d, 0xbd, 0x85, 0xfb, 0xf1, 0xa4, 0x48, 0x3c, 0x22, 0x85, 0x9e, 0xfd, 0xfd, 0x9d, 0x66, 0x16, 0x50, 0xb5, 0x11, 0x7d, 0x27, 0x5, 0xf0, 0xb8, 0xfc, 0xc7, 0xd3, 0x99, 0xf4, 0x8e, 0xfc, 0xa7, 0x63, 0xf1, 0x4f, 0xf9, 0xff, 0x88, 0xf2, 0x5, 0x94, 0x88, 0x3e, 0xc1, 0x53, 0xdb, 0x44, 0xc0, 0x60, 0xbc, 0x44, 0x2d, 0xa4, 0x83, 0x73, 0xa2, 0xda, 0x1a, 0xa2, 0xec, 0x9, 0x80, 0x86, 0xa1, 0x62, 0x19, 0x32, 0x7d, 0x10, 0xfa, 0xf2, 0x5, 0x14, 0xd6, 0x3f, 0x29, 0xb0, 0x66, 0xd0, 0x2, 0x26, 0xba, 0xb3, 0xb1, 0x89, 0x0, 0xb5, 0x88, 0x9, 0xa7, 0x8, 0xcc, 0xe0, 0x2, 0x1, 0x8, 0x6e, 0x16, 0x2, 0xc9, 0xd, 0x50, 0xd0, 0x4, 0xeb, 0x98, 0x41, 0x80, 0xe5, 0xc, 0xcb, 0x33, 0xb0, 0xc4, 0xaa, 0xa, 0xc6, 0x88, 0xc9, 0x8f, 0xc2, 0x70, 0x2e, 0x67, 0x48, 0x7, 0x37, 0x5e, 0xf3, 0x32, 0x8a, 0x20, 0x1d, 0x8e, 0x55, 0xa4, 0xdc, 0x0, 0x4c, 0x1, 0x45, 0x16, 0xb0, 0x8, 0xb0, 0x4c, 0x1b, 0x45, 0x58, 0x6d, 0x74, 0xf, 0x35, 0x43, 0x45, 0xa1, 0x2f, 0x40, 0x5b, 0xd1, 0x3b, 0x35, 0x1f, 0xfa, 0x2, 0x0, 0x70, 0x1a, 0x13, 0x3f, 0x0, 0x50, 0xa0, 0x5, 0xf3, 0xac, 0x72, 0xd7, 0x45, 0x6a, 0x39, 0x9d, 0x2, 0x7d, 0x87, 0xcc, 0x12, 0x53, 0x66, 0xac, 0x4a, 0x7d, 0x22, 0x28, 0x44, 0xca, 0x77, 0xb7, 0xf, 0xfc, 0x5d, 0x9b, 0xcb, 0xec, 0x7f, 0xfa, 0x1f, 0xfd, 0x97, 0x53, 0xdf, 0x21, 0xe9, 0x28, 0x7c, 0x14, 0x4, 0x72, 0x74, 0xf4, 0xdd, 0xe9, 0xa8, 0x82, 0x29, 0xeb, 0x7, 0x5, 0xca, 0x4a, 0x87, 0x1a, 0x96, 0x81, 0x61, 0x92, 0x5, 0x66, 0x2, 0x8b, 0xf5, 0xa9, 0x83, 0xcb, 0xd6, 0x9d, 0xd6, 0xc1, 0xaf, 0xd6, 0xc, 0x31, 0x52, 0xa0, 0xad, 0x5a, 0x5f, 0x1, 0x31, 0xdd, 0x66, 0x74, 0x5b, 0x55, 0xbf, 0x3, 0x9d, 0xec, 0x34, 0x5, 0xa8, 0x81, 0x64, 0x80, 0x79, 0x2f, 0x0, 0xab, 0xfd, 0x1d, 0xc8, 0x33, 0x42, 0x28, 0xd6, 0xa7, 0xc0, 0x87, 0x6b, 0xdd, 0x2a, 0x32, 0x23, 0x0, 0xfc, 0x3a, 0x35, 0xe2, 0x80, 0xe8, 0xa0, 0x70, 0xd1, 0x67, 0xd4, 0x43, 0x5d, 0x81, 0xa6, 0x2, 0xc4, 0xd7, 0x5, 0xa0, 0xda, 0xa8, 0x7c, 0x67, 0xaf, 0xc0, 0xff, 0x1, 0x1d, 0x3, 0xe9, 0x7d, 0xb, 0xca, 0xf3, 0xaf, 0xa1, 0x2f, 0x5f, 0x9c, 0x81, 0xf5, 0x93, 0x90, 0x67, 0x3, 0xe0, 0x3c, 0x87, 0xb2, 0x8c, 0x28, 0x6d, 0x11, 0x5, 0xe5, 0x41, 0xf, 0x41, 0xe5, 0xc2, 0xc4, 0x16, 0xea, 0xe8, 0x32, 0x72, 0xe1, 0xf0, 0x3, 0xca, 0x83, 0x58, 0x15, 0x87, 0x58, 0x33, 0x6b, 0x9e, 0x33, 0x91, 0xd0, 0x86, 0x9c, 0x8b, 0x10, 0xb5, 0x28, 0x80, 0xba, 0x2, 0x54, 0xac, 0x61, 0x2b, 0x90, 0xfd, 0x4c, 0x34, 0x11, 0x93, 0x45, 0x3e, 0x1a, 0x9d, 0xdb, 0x63, 0x64, 0xea, 0xc8, 0x42, 0x34, 0x82, 0x89, 0x98, 0x14, 0x98, 0x46, 0xe, 0x4f, 0x6d, 0xac, 0xa0, 0xa8, 0x4c, 0x34, 0xc3, 0xb6, 0x50, 0xd8, 0x6d, 0x81, 0x46, 0x45, 0x2f, 0x7c, 0x4c, 0xe3, 0xbd, 0x72, 0xd9, 0xc6, 0x25, 0xc2, 0xfd, 0xd, 0x80, 0x86, 0x34, 0x62, 0xae, 0xf2, 0x20, 0x9e, 0x4a, 0xb7, 0xb0, 0xf7, 0x54, 0x36, 0xec, 0x3c, 0x88, 0x49, 0x92, 0x16, 0xa, 0xf9, 0xb8, 0x36, 0x1f, 0x2, 0xc0, 0x61, 0xdc, 0x3c, 0x67, 0xd7, 0x50, 0xe8, 0xb, 0x18, 0xcc, 0x10, 0xb0, 0xe0, 0x14, 0x4c, 0x88, 0x9, 0x6a, 0x5c, 0xd9, 0x3a, 0x13, 0x12, 0xc0, 0x1a, 0x9c, 0x22, 0x1a, 0x9, 0x9, 0x15, 0x5c, 0x67, 0xbf, 0x6, 0x70, 0x9a, 0x7, 0xff, 0xc7, 0x99, 0xd5, 0xf8, 0xfb, 0x6b, 0x6, 0xbb, 0xe0, 0x33, 0x73, 0x58, 0x66, 0x46, 0x5a, 0xd8, 0x80, 0x96, 0x3c, 0x73, 0x31, 0x9f, 0x9c, 0x95, 0xdb, 0x7e, 0xd4, 0x14, 0x99, 0xb, 0x2c, 0xa3, 0x48, 0x8, 0xdd, 0x5b, 0x6c, 0x6e, 0x52, 0xcb, 0x84, 0xcd, 0x71, 0xee, 0xd4, 0x13, 0xd1, 0x56, 0x11, 0x85, 0x3f, 0x9, 0x31, 0x39, 0x12, 0x55, 0xba, 0xc4, 0xb4, 0x98, 0x9c, 0x31, 0x8e, 0xe1, 0x7f, 0xef, 0xe2, 0xfb, 0xe, 0x54, 0xc4, 0xa4, 0x1a, 0x69, 0x86, 0xb5, 0x2, 0x78, 0xc2, 0xeb, 0x3a, 0xef, 0x38, 0x28, 0x61, 0xe2, 0x3c, 0x26, 0xb6, 0xae, 0x0, 0x8b, 0x84, 0xbe, 0x0, 0x83, 0xe1, 0xc9, 0x4a, 0xd1, 0x64, 0x32, 0x11, 0xf2, 0xb7, 0x93, 0x7, 0x89, 0x78, 0x46, 0x92, 0x42, 0x7e, 0x29, 0x62, 0x23, 0xf5, 0x1d, 0xac, 0x88, 0xd, 0x14, 0xa2, 0xff, 0x62, 0x1, 0x1d, 0x21, 0x86, 0x45, 0xbc, 0x56, 0x69, 0xc9, 0xb4, 0xa2, 0x96, 0x4a, 0x1b, 0x68, 0x15, 0x95, 0x61, 0xc9, 0xb4, 0xbe, 0x83, 0xb1, 0x6d, 0x1, 0xcd, 0xa6, 0x16, 0x80, 0x8a, 0x12, 0xfa, 0xe2, 0x92, 0xca, 0x87, 0x2, 0x52, 0x80, 0x75, 0x8a, 0x64, 0xdb, 0x64, 0x1f, 0x9e, 0x4f, 0xf7, 0x18, 0x51, 0xde, 0xa3, 0x15, 0xb1, 0xbd, 0xa1, 0x97, 0x55, 0x8c, 0x74, 0x2b, 0x12, 0x72, 0xeb, 0xba, 0xb6, 0x4c, 0x1e, 0x4c, 0xa0, 0x4a, 0x51, 0x68, 0x8a, 0x74, 0x64, 0x42, 0xb, 0x95, 0x90, 0x69, 0xe1, 0x9, 0x63, 0x3f, 0x44, 0x9d, 0x4f, 0x2a, 0xc6, 0x7d, 0xd0, 0xec, 0x3, 0x79, 0xfd, 0xd2, 0x37, 0x64, 0x11, 0xfe, 0x5e, 0x26, 0x9a, 0x46, 0x74, 0x6e, 0x5, 0x0, 0x32, 0x71, 0xba, 0x21, 0x88, 0xd6, 0xd8, 0xf7, 0xe3, 0x3, 0xb8, 0xf9, 0x8d, 0x0, 0x1c, 0x93, 0x5, 0x8a, 0x84, 0x44, 0xdd, 0x7c, 0x48, 0xf4, 0x39, 0x1f, 0xe2, 0x9d, 0xce, 0xbb, 0x1f, 0x9c, 0x22, 0xd9, 0x44, 0x16, 0x98, 0xa3, 0x15, 0xd7, 0x9e, 0xbc, 0x61, 0xa4, 0xcb, 0xe6, 0x8a, 0x1b, 0x6c, 0x11, 0xd0, 0x62, 0x4d, 0x8c, 0x99, 0xfe, 0x65, 0x5d, 0xd7, 0xa7, 0xac, 0xf5, 0x58, 0x1a, 0x30, 0xd6, 0xa1, 0x91, 0x90, 0x80, 0x66, 0x68, 0x81, 0x4e, 0xac, 0x30, 0xc, 0x3b, 0x43, 0x35, 0x47, 0x2b, 0xa7, 0x1, 0x8a, 0x0, 0xd4, 0x75, 0x62, 0x39, 0xa, 0x1e, 0xaa, 0x2a, 0x59, 0x72, 0x62, 0x5d, 0xe3, 0x89, 0x7d, 0x99, 0x25, 0x31, 0xe7, 0x60, 0x8c, 0x66, 0x98, 0x7d, 0xee, 0x19, 0x2, 0xcc, 0xec, 0xbb, 0xf, 0x7d, 0x1, 0x58, 0x9f, 0x9a, 0x88, 0x52, 0xc0, 0xd, 0x15, 0xa2, 0xaa, 0xc8, 0x64, 0x43, 0xcc, 0x9f, 0xed, 0xca, 0x6, 0xf0, 0x37, 0xc4, 0x5e, 0x3, 0x17, 0x3e, 0xb2, 0x29, 0xd8, 0x94, 0xaa, 0x61, 0x13, 0x29, 0xd8, 0x44, 0xb2, 0x95, 0x7, 0x47, 0xc, 0xf8, 0xe8, 0x91, 0xea, 0x86, 0x49, 0xee, 0x57, 0xe1, 0x31, 0x51, 0x56, 0x61, 0xa1, 0x74, 0x8e, 0x24, 0x51, 0x9d, 0x53, 0x19, 0x79, 0x6, 0x50, 0x8, 0x2a, 0x1a, 0xe3, 0x10, 0x73, 0x81, 0x4c, 0x46, 0x20, 0x17, 0x48, 0x41, 0xa9, 0x89, 0xc, 0x42, 0xb1, 0xc5, 0x55, 0xc3, 0x86, 0xc1, 0x16, 0xf6, 0xc1, 0xf0, 0x9a, 0x16, 0x13, 0xe9, 0x6f, 0xdb, 0x22, 0xcd, 0x5f, 0x19, 0xb6, 0xaa, 0x76, 0x89, 0x8a, 0xe5, 0x55, 0x1e, 0xd4, 0x27, 0x6d, 0x62, 0x75, 0x4d, 0x44, 0x91, 0x6e, 0xb1, 0xa1, 0x62, 0xa6, 0x64, 0x8d, 0x50, 0xd6, 0x61, 0xaa, 0x59, 0x46, 0x44, 0x5b, 0x9, 0xb9, 0x65, 0x26, 0xe2, 0x91, 0x5b, 0x41, 0x48, 0xd4, 0x51, 0x3c, 0xe5, 0x3d, 0x19, 0x52, 0x64, 0x32, 0x10, 0x3e, 0x43, 0x5e, 0x73, 0x5a, 0xfe, 0x15, 0x8, 0xda, 0xa7, 0x6a, 0x1e, 0x1c, 0x71, 0x6e, 0xf7, 0x9e, 0x9d, 0x98, 0x44, 0xcb, 0x83, 0x23, 0xe, 0x5, 0xfe, 0x73, 0x2f, 0x8e, 0xff, 0xf2, 0x0, 0xea, 0xa, 0xd2, 0x2d, 0x6c, 0xad, 0xd8, 0x94, 0xe7, 0x3d, 0x73, 0x44, 0x2a, 0xf, 0x8e, 0x4e, 0x36, 0xb0, 0x77, 0x97, 0xca, 0x16, 0xd7, 0x19, 0x90, 0x52, 0x66, 0xae, 0x33, 0x56, 0x60, 0xad, 0x74, 0x9d, 0xdf, 0x79, 0x47, 0x94, 0x62, 0xf1, 0x44, 0x32, 0xc5, 0x5e, 0xda, 0xd6, 0x8c, 0x35, 0x24, 0x66, 0x1, 0x31, 0xc7, 0x1c, 0x29, 0xe3, 0x6b, 0xf6, 0x9c, 0xa1, 0xa7, 0x48, 0x9d, 0x38, 0x12, 0xc, 0xc5, 0xb2, 0xe5, 0x88, 0xe8, 0xec, 0x85, 0xaa, 0x40, 0x43, 0x7c, 0x2f, 0xdb, 0x64, 0xdd, 0x65, 0xbf, 0x99, 0xb5, 0xcd, 0xff, 0xe5, 0x9f, 0x48, 0x70, 0x6, 0x45, 0xd0, 0x94, 0x67, 0xe5, 0xb6, 0xd3, 0xf, 0xf7, 0xc1, 0x9a, 0x1e, 0xe7, 0xf1, 0x18, 0x52, 0xe4, 0xab, 0x35, 0xc1, 0xaa, 0xc5, 0x87, 0xfb, 0x57, 0x32, 0xbe, 0x45, 0xb2, 0xc5, 0x27, 0xc5, 0xdf, 0xd8, 0x84, 0x40, 0xf4, 0xaf, 0xa2, 0x8a, 0x8d, 0x19, 0xb4, 0x8d, 0x15, 0x7, 0xaf, 0x4c, 0xc, 0x46, 0x7c, 0x5c, 0xfc, 0xb4, 0xb0, 0x86, 0x88, 0xcd, 0x3e, 0x61, 0x4a, 0x3c, 0x58, 0x20, 0x13, 0x4f, 0x56, 0x4c, 0xeb, 0xe4, 0xc1, 0xd1, 0xc0, 0x61, 0xf4, 0xb5, 0x15, 0xc3, 0xcd, 0x1a, 0x26, 0x80, 0x70, 0x6d, 0xab, 0x59, 0x8e, 0xe9, 0x13, 0xf2, 0xd9, 0x40, 0x7c, 0x8a, 0xe2, 0x53, 0xac, 0xf8, 0x1b, 0x80, 0x2f, 0x1, 0x13, 0x37, 0x38, 0x30, 0x71, 0x83, 0xad, 0x89, 0x9b, 0x61, 0xf1, 0xcd, 0x98, 0xec, 0xa7, 0x6f, 0xc2, 0xe4, 0x3f, 0xb7, 0xe7, 0x4b, 0xe7, 0xe1, 0x7a, 0xba, 0x4, 0x40, 0x27, 0xa, 0xea, 0x23, 0x15, 0xc9, 0x16, 0x31, 0xf3, 0xe0, 0xcf, 0xbf, 0x42, 0x0, 0x58, 0x44, 0x45, 0xa6, 0xa3, 0x7, 0xc0, 0xef, 0x7f, 0xb0, 0x2f, 0x3e, 0xe1, 0x16, 0xe3, 0x8a, 0x57, 0x60, 0xd3, 0xfe, 0x2d, 0x19, 0x3b, 0xd3, 0x4d, 0xe8, 0x4b, 0x68, 0xfd, 0xe3, 0xc9, 0x52, 0xe9, 0x83, 0x7f, 0xb9, 0x50, 0xa, 0xed, 0xb9, 0xc5, 0xc4, 0xe2, 0x61, 0x8, 0x0, 0xd, 0xde, 0x5f, 0x10, 0x73, 0xce, 0x96, 0x92, 0x20, 0xc5, 0x66, 0xb8, 0x2d, 0xeb, 0x62, 0xdb, 0xb6, 0x8, 0xb2, 0x2c, 0x5e, 0x3f, 0x50, 0xc3, 0x7a, 0xe8, 0x4b, 0xc8, 0xc6, 0x4f, 0x1e, 0x18, 0x1b, 0xbf, 0xdb, 0x80, 0x18, 0x26, 0x5e, 0x40, 0xb, 0x35, 0xd0, 0xaa, 0x8b, 0xb4, 0x3c, 0xf8, 0xc1, 0xb1, 0x85, 0x59, 0x29, 0x56, 0xaa, 0xf5, 0x36, 0xe8, 0xf5, 0xb, 0xa0, 0xdb, 0xab, 0x9f, 0x17, 0x6, 0x15, 0xd0, 0xa8, 0x8c, 0xf8, 0x1b, 0x5e, 0xa7, 0x55, 0xaf, 0x9f, 0x36, 0xa, 0xf5, 0x62, 0xa1, 0xd0, 0x28, 0x15, 0xa6, 0x95, 0x42, 0xf2, 0x62, 0x34, 0xbe, 0x57, 0xcc, 0x93, 0x6a, 0x35, 0xdd, 0xd3, 0x27, 0xab, 0x51, 0x43, 0xad, 0x8d, 0x5a, 0xcd, 0x84, 0x5a, 0xb9, 0xb3, 0xa, 0x39, 0x79, 0x74, 0x71, 0xd1, 0x59, 0xe9, 0x95, 0x5c, 0x11, 0xc1, 0x8a, 0x19, 0x95, 0x5b, 0x7a, 0x4b, 0xc8, 0x6a, 0xd1, 0x8c, 0x29, 0x4a, 0x2e, 0x16, 0x6d, 0x6b, 0xe9, 0x1e, 0x1e, 0xcd, 0xce, 0x16, 0x83, 0xf2, 0x30, 0xde, 0x90, 0xd3, 0x6d, 0x74, 0x7b, 0x77, 0xab, 0xa8, 0xf8, 0x22, 0x55, 0xcc, 0xdd, 0xf, 0xc9, 0x79, 0x3, 0xae, 0x4c, 0x9c, 0xed, 0xc, 0xb3, 0x31, 0x98, 0x3d, 0xc7, 0x97, 0xa8, 0x3d, 0x6d, 0x2c, 0x4b, 0xdd, 0x1e, 0x47, 0x52, 0xc0, 0x83, 0x81, 0xa, 0x63, 0xf, 0xe4, 0x32, 0x55, 0xd6, 0x17, 0xe4, 0xde, 0xe8, 0xe4, 0xaa, 0x9, 0xf5, 0x7e, 0xd5, 0x5e, 0xc, 0x1a, 0x97, 0xb2, 0x24, 0x2f, 0xb3, 0xed, 0xdb, 0xb3, 0x72, 0xe1, 0xd2, 0x80, 0xe5, 0xf1, 0xc3, 0xe9, 0xa8, 0x39, 0xa7, 0xb3, 0x12, 0xb2, 0x57, 0xe5, 0xdc, 0x58, 0x26, 0xd9, 0x5e, 0x2e, 0xcd, 0x91, 0x44, 0x1f, 0x4c, 0xa3, 0x58, 0xb9, 0xcc, 0x5a, 0x85, 0x72, 0x3b, 0x71, 0x9c, 0x58, 0x15, 0x12, 0x93, 0x96, 0x7c, 0xf5, 0x70, 0x7e, 0x49, 0x8b, 0x5a, 0xb2, 0x38, 0x30, 0x6a, 0xa7, 0xbd, 0x79, 0xf4, 0xae, 0x68, 0xd4, 0x46, 0x95, 0x6e, 0xbf, 0xf6, 0x70, 0xbf, 0xaa, 0x25, 0x70, 0xb5, 0xd5, 0x6e, 0xcc, 0x13, 0x8b, 0xd6, 0xb0, 0x78, 0xf5, 0xc0, 0x91, 0x20, 0xa9, 0x32, 0x9a, 0x37, 0xb2, 0xed, 0x52, 0x21, 0x5e, 0xb2, 0x2b, 0x8d, 0x96, 0x5e, 0x4a, 0x40, 0xf9, 0x3e, 0x57, 0x57, 0x7a, 0xcb, 0xf9, 0x7d, 0x4c, 0x82, 0xe3, 0xea, 0xa2, 0x76, 0x56, 0x6a, 0xf6, 0x4a, 0xe7, 0xa3, 0x8c, 0x59, 0x25, 0x70, 0x7e, 0x3c, 0x96, 0xc8, 0x55, 0x2e, 0xd7, 0x3b, 0xad, 0xf7, 0xce, 0x72, 0xf5, 0x3b, 0x8e, 0x64, 0x74, 0x49, 0xf5, 0xec, 0x84, 0xb6, 0x8a, 0x67, 0xea, 0x2a, 0x7d, 0x7f, 0xbf, 0xe8, 0xa3, 0x51, 0xea, 0xd2, 0xee, 0x77, 0x33, 0x97, 0xe3, 0xf4, 0x69, 0xa3, 0x6c, 0x25, 0x56, 0xd9, 0xbe, 0x81, 0x93, 0xd3, 0x5e, 0xac, 0x15, 0x4d, 0xc1, 0xca, 0xc3, 0xcc, 0xee, 0xac, 0xec, 0xb8, 0x14, 0x33, 0x5b, 0x3a, 0xcc, 0xf4, 0x68, 0x94, 0x23, 0xa9, 0x76, 0x27, 0xb0, 0x71, 0x5b, 0x54, 0xc7, 0x97, 0xd2, 0x2d, 0x6e, 0x96, 0x61, 0x66, 0x91, 0x7c, 0xb8, 0xa5, 0xc5, 0x2e, 0xed, 0xc2, 0x49, 0x54, 0x4e, 0xda, 0x84, 0x3c, 0x24, 0xea, 0xa5, 0x26, 0x55, 0xec, 0x39, 0x24, 0xda, 0x71, 0x25, 0x95, 0xc8, 0xf6, 0xa4, 0xa, 0xee, 0xcc, 0x2f, 0xad, 0xe8, 0x72, 0xb5, 0x8c, 0x73, 0x24, 0xf1, 0x91, 0x6, 0x2f, 0xda, 0x25, 0x3a, 0x52, 0x2b, 0xc6, 0x1c, 0x65, 0xe4, 0xf3, 0x52, 0x22, 0x81, 0xa2, 0x92, 0xd2, 0x2d, 0xde, 0x25, 0xeb, 0x35, 0x7a, 0x3e, 0x51, 0xe1, 0xb2, 0x7f, 0x92, 0xeb, 0x5c, 0xf4, 0xe3, 0x9, 0x3c, 0x3f, 0x2f, 0xd0, 0xa8, 0x7e, 0x9c, 0x49, 0x37, 0x6e, 0x6d, 0x5b, 0xae, 0x94, 0xb5, 0xf1, 0x80, 0x23, 0x81, 0x8d, 0xe1, 0xa8, 0x70, 0x7a, 0xbb, 0x28, 0x68, 0x57, 0xcd, 0x58, 0xf2, 0xf6, 0xb8, 0xd2, 0x90, 0xa3, 0x25, 0x62, 0xa8, 0xb3, 0x12, 0x4a, 0x1b, 0x8d, 0x19, 0x5c, 0xdc, 0x6a, 0xed, 0x7a, 0x67, 0x52, 0xea, 0x2b, 0xaa, 0x89, 0xea, 0xdd, 0xe2, 0xac, 0x73, 0x3e, 0x9e, 0xc4, 0x26, 0xd9, 0x58, 0x66, 0xd9, 0x20, 0xfd, 0xfa, 0x15, 0x47, 0x72, 0x77, 0xbe, 0x2a, 0x15, 0x62, 0x85, 0x51, 0x7b, 0x5e, 0xcf, 0xf5, 0x46, 0x7d, 0x49, 0x82, 0xf7, 0xd6, 0x69, 0xb5, 0x58, 0x6d, 0xa9, 0x8d, 0xb1, 0x72, 0x76, 0x57, 0x6a, 0x1b, 0xcd, 0x66, 0x2a, 0x2b, 0xa7, 0x7, 0x24, 0xe, 0x97, 0x9a, 0x3c, 0xaf, 0x5f, 0x95, 0x2a, 0x72, 0x61, 0xd0, 0xe8, 0x18, 0xc7, 0xc7, 0x6d, 0x52, 0xd5, 0x38, 0x92, 0xfa, 0x58, 0x1a, 0xcf, 0x94, 0x3e, 0xa4, 0x4a, 0xb5, 0x98, 0x3a, 0x2f, 0x59, 0xcb, 0xab, 0x73, 0xd5, 0x6e, 0x67, 0xc7, 0x4d, 0x35, 0x96, 0x78, 0x28, 0x36, 0xc8, 0xfd, 0xa0, 0x7a, 0xdb, 0x56, 0x2b, 0xd0, 0x1a, 0x56, 0xcb, 0x3d, 0xbd, 0x5c, 0xd0, 0x9b, 0xca, 0xd5, 0xf8, 0xf2, 0x72, 0x32, 0xb9, 0xa5, 0xa5, 0xc2, 0xb2, 0x52, 0x10, 0xcc, 0x76, 0xc6, 0xd8, 0xbd, 0x58, 0x19, 0xe2, 0x69, 0x27, 0x1b, 0x4d, 0xe, 0x4f, 0x29, 0x4a, 0xdf, 0x37, 0xcc, 0x44, 0xa1, 0x5b, 0x5b, 0x64, 0x2a, 0xb9, 0x64, 0xfb, 0xb6, 0x61, 0xdd, 0xb6, 0xee, 0xba, 0x83, 0x6c, 0x6f, 0x56, 0x2e, 0x35, 0x67, 0x77, 0x85, 0x5a, 0x54, 0xed, 0xd9, 0x25, 0x75, 0x70, 0x3e, 0xce, 0xce, 0xa5, 0x11, 0x47, 0xd2, 0xab, 0x37, 0x71, 0x9a, 0xd4, 0xa6, 0x53, 0xda, 0xa8, 0x96, 0x17, 0xf3, 0x7e, 0x6c, 0x71, 0x5a, 0xa9, 0xf4, 0x4b, 0xc3, 0x54, 0x73, 0x32, 0x2a, 0xde, 0x96, 0xb, 0x97, 0x51, 0x33, 0xda, 0x92, 0xea, 0x99, 0xa9, 0x91, 0x1e, 0xc, 0x63, 0x5, 0x7b, 0x5e, 0xb8, 0x6c, 0xb4, 0x94, 0xca, 0x60, 0x31, 0x9f, 0x90, 0xd6, 0x78, 0x2a, 0x3e, 0x71, 0xee, 0x36, 0x73, 0x11, 0xad, 0xc6, 0x52, 0xf1, 0xd9, 0x49, 0xb2, 0xf1, 0x60, 0x2d, 0x6e, 0x97, 0x9a, 0x5c, 0x5b, 0xd, 0x95, 0xc, 0x84, 0xab, 0xe3, 0x7e, 0x79, 0x26, 0xe9, 0x31, 0xb, 0x76, 0xb5, 0xe8, 0xc9, 0x3, 0xbc, 0x9c, 0x4c, 0x3b, 0xed, 0xa5, 0x76, 0x76, 0xa2, 0x91, 0xa4, 0x64, 0x9f, 0xc5, 0xfb, 0x93, 0xe5, 0xec, 0x52, 0x8c, 0x49, 0xc2, 0x2a, 0xa7, 0x71, 0xeb, 0xe2, 0xb6, 0xd0, 0x6f, 0x9e, 0x27, 0x51, 0x6f, 0x82, 0x52, 0xcb, 0x6c, 0xf6, 0xc2, 0x38, 0x3d, 0x4b, 0x98, 0xa9, 0x7a, 0x75, 0xd4, 0x6a, 0xdb, 0x8d, 0x93, 0x93, 0x58, 0x4f, 0x3e, 0xcf, 0xb4, 0xda, 0xcd, 0xc4, 0x7d, 0xab, 0x56, 0x2c, 0x2c, 0xd5, 0xd8, 0xdc, 0x56, 0xb4, 0xde, 0xc5, 0x28, 0xb9, 0x14, 0xca, 0x27, 0x7d, 0x9c, 0x4d, 0x54, 0x65, 0x49, 0x3b, 0x8e, 0x17, 0xce, 0xc6, 0xa3, 0x8c, 0x34, 0x98, 0x9f, 0xd9, 0xbd, 0x31, 0x1a, 0x9e, 0xcc, 0xeb, 0x45, 0x7a, 0xa1, 0xe7, 0x72, 0xab, 0xca, 0xdd, 0x65, 0xe9, 0x38, 0x33, 0x8b, 0xdb, 0xf4, 0xf8, 0xb4, 0xa9, 0xa5, 0x32, 0xb8, 0xda, 0x8e, 0x15, 0x57, 0x67, 0x8b, 0x73, 0xbd, 0xb2, 0x6c, 0x72, 0x24, 0x57, 0x34, 0xd3, 0x55, 0xa5, 0xda, 0x14, 0x25, 0x55, 0xd4, 0xbf, 0x47, 0x57, 0x17, 0xb3, 0xc5, 0x31, 0xac, 0xc4, 0x7a, 0xd1, 0x5b, 0x2d, 0x7a, 0xae, 0x54, 0x93, 0xca, 0x54, 0xad, 0xeb, 0xf6, 0xac, 0x52, 0x96, 0xec, 0x69, 0xf6, 0xa2, 0x70, 0x3a, 0x4d, 0x65, 0xeb, 0xf3, 0xf2, 0x68, 0xd2, 0x6a, 0x74, 0x3a, 0x85, 0x66, 0xed, 0x9e, 0x23, 0x39, 0x96, 0x4a, 0xed, 0x5a, 0x45, 0x8a, 0x5f, 0xde, 0xdd, 0xd, 0xeb, 0x27, 0xcb, 0x31, 0xb9, 0x3a, 0xed, 0x8f, 0x6, 0xb7, 0xad, 0xd1, 0xe2, 0xa4, 0x19, 0xc3, 0xb1, 0x64, 0x33, 0x21, 0x9d, 0x5c, 0xe8, 0x77, 0xb5, 0xa8, 0x34, 0x2f, 0xd3, 0xe4, 0x72, 0x76, 0x59, 0x1b, 0xeb, 0xd5, 0x8b, 0xd9, 0xb9, 0x4d, 0x2d, 0xda, 0xea, 0x37, 0x72, 0xc2, 0x62, 0x5d, 0xd5, 0xab, 0xc8, 0xb0, 0xab, 0xb3, 0x96, 0xbe, 0xb0, 0x86, 0x27, 0xb1, 0x25, 0x8c, 0xf6, 0xcd, 0xa2, 0x12, 0x8b, 0xdf, 0x4d, 0xca, 0xb7, 0xe9, 0xec, 0x59, 0xad, 0x7c, 0x49, 0x1b, 0x8d, 0x31, 0x4d, 0xa3, 0x41, 0x7b, 0x54, 0x9b, 0xe8, 0x89, 0xb3, 0x66, 0xce, 0xc6, 0xd4, 0x9c, 0xb4, 0xea, 0x30, 0x55, 0x2b, 0x58, 0xc2, 0x8e, 0xbd, 0x8c, 0x8f, 0x3a, 0xb4, 0x70, 0x7e, 0x3f, 0x3d, 0x5e, 0x2d, 0xee, 0xe7, 0x17, 0xe5, 0xb4, 0x1e, 0x2b, 0xf, 0x8f, 0x61, 0xf4, 0xd8, 0x28, 0xd8, 0x69, 0x5c, 0x98, 0xe2, 0xe5, 0xea, 0xbe, 0x7f, 0x85, 0x57, 0x7a, 0x7a, 0x71, 0x3a, 0xac, 0xc4, 0x1f, 0x3a, 0x69, 0xe3, 0xb4, 0x3d, 0x9e, 0xc7, 0xe6, 0xa7, 0x17, 0xe9, 0xdb, 0x61, 0x42, 0x30, 0x5b, 0x3a, 0x47, 0x4d, 0x6b, 0xdc, 0x49, 0xde, 0x9e, 0xe9, 0xc9, 0x4a, 0x2b, 0x9b, 0xca, 0x5d, 0x8e, 0xfa, 0x77, 0xca, 0xdd, 0xf2, 0x72, 0x7a, 0xda, 0x3c, 0xbe, 0x3c, 0xad, 0x8c, 0xda, 0xe3, 0xa2, 0x5c, 0x83, 0xaa, 0x86, 0xeb, 0x9d, 0x45, 0x6f, 0x9a, 0x2b, 0x95, 0x16, 0xe5, 0x7e, 0xa3, 0x9f, 0x69, 0xa5, 0xcc, 0x53, 0xa9, 0x15, 0xe3, 0x48, 0x9a, 0x19, 0x52, 0x7a, 0x50, 0xd3, 0x95, 0x8b, 0xe3, 0x87, 0xe1, 0x38, 0x79, 0x5a, 0x9b, 0xf7, 0x3b, 0x99, 0xf3, 0x94, 0x7d, 0x5f, 0xbf, 0xb2, 0xe3, 0xb4, 0xa2, 0xd8, 0xcb, 0xd4, 0x94, 0x4c, 0xce, 0x12, 0x9d, 0x41, 0xae, 0x19, 0xbd, 0x2b, 0xcf, 0xca, 0x75, 0xc6, 0xe1, 0x67, 0x95, 0x42, 0x76, 0x10, 0xcd, 0x92, 0xf9, 0x89, 0x50, 0x5, 0x67, 0x99, 0x7e, 0xe7, 0x36, 0x41, 0xed, 0x74, 0xa3, 0x71, 0x99, 0xae, 0x45, 0xe1, 0x38, 0x11, 0xeb, 0x2f, 0x6a, 0x95, 0xd2, 0x24, 0x4a, 0xd0, 0xa9, 0x55, 0xcb, 0x5e, 0x4d, 0x9a, 0xc5, 0x51, 0x33, 0x95, 0x1a, 0x91, 0x89, 0x64, 0x5c, 0x2d, 0xef, 0xb2, 0xf8, 0xf2, 0x2c, 0x9e, 0x56, 0xb2, 0x72, 0x2d, 0x73, 0xd2, 0x6d, 0x14, 0x9, 0x47, 0x32, 0x7b, 0x90, 0x7a, 0x57, 0x39, 0x1c, 0xef, 0x27, 0xc6, 0xa3, 0xf9, 0x43, 0xe5, 0xbc, 0xd4, 0x5d, 0xe4, 0xea, 0xfd, 0x93, 0x69, 0xac, 0x5d, 0x28, 0xdd, 0x37, 0x13, 0xca, 0x50, 0xea, 0xb6, 0x8a, 0xba, 0x36, 0xd6, 0xa6, 0xf1, 0x45, 0x77, 0xd6, 0x7a, 0xa8, 0xd8, 0x67, 0xf5, 0xf8, 0x69, 0x67, 0x68, 0xa7, 0xeb, 0xcd, 0xce, 0x65, 0xa5, 0xcd, 0x91, 0x68, 0x75, 0x6d, 0x31, 0xb9, 0xbd, 0xba, 0x34, 0x68, 0x74, 0x9c, 0xed, 0xdc, 0x9e, 0x4d, 0x1f, 0xb0, 0x5c, 0x93, 0xe8, 0xbc, 0x58, 0x94, 0xc7, 0x43, 0xf5, 0x72, 0x90, 0x80, 0xc9, 0xc9, 0x49, 0x2a, 0x3e, 0xb7, 0x4a, 0xd9, 0x13, 0x7c, 0x39, 0x2d, 0x56, 0x73, 0xa7, 0xa3, 0x69, 0xaa, 0x44, 0x2f, 0xb5, 0x49, 0xb7, 0x77, 0x2f, 0x8b, 0x99, 0xb4, 0x3e, 0x80, 0xc9, 0x65, 0xf2, 0xaa, 0x59, 0xb1, 0x2b, 0x25, 0xcd, 0x3a, 0xc5, 0xa8, 0x2f, 0xb5, 0x94, 0xc6, 0x65, 0xb7, 0xb9, 0x1c, 0x9e, 0x2f, 0x12, 0x28, 0x5e, 0x54, 0xdb, 0xfd, 0xb4, 0x1c, 0x3b, 0x7d, 0xb8, 0x5c, 0x19, 0xe9, 0xca, 0xea, 0x32, 0x8a, 0xec, 0xd3, 0xac, 0x5c, 0x42, 0x9, 0x3d, 0x5a, 0xad, 0x8d, 0x7, 0x42, 0x8a, 0xe3, 0xb7, 0xb1, 0x4e, 0xe7, 0xf8, 0x7e, 0x70, 0x36, 0x39, 0x3b, 0x3d, 0x9f, 0xa4, 0xfb, 0xb9, 0x49, 0x5c, 0xeb, 0x3f, 0xdc, 0x2a, 0x35, 0x94, 0x6b, 0x5c, 0x2d, 0x2f, 0x1a, 0xd3, 0xd5, 0xfd, 0x59, 0x4e, 0xb9, 0xca, 0x9d, 0x59, 0x33, 0x12, 0x7f, 0x88, 0x4e, 0x87, 0xed, 0x5c, 0x74, 0x38, 0x6f, 0xa6, 0xe2, 0x13, 0x45, 0xbd, 0xbd, 0x55, 0x85, 0xec, 0x1c, 0x1f, 0x8f, 0xa3, 0xf, 0xb9, 0xae, 0x21, 0xab, 0xb9, 0x86, 0xe4, 0x8c, 0x7c, 0x66, 0x95, 0x3c, 0x59, 0x64, 0x95, 0xee, 0x49, 0xb3, 0xa9, 0x9b, 0x52, 0x2f, 0xda, 0xcf, 0x20, 0x52, 0x68, 0x40, 0xa9, 0x9f, 0x4b, 0xdd, 0x9f, 0xa3, 0x5c, 0xa6, 0x72, 0x5a, 0x3b, 0x1f, 0xce, 0x2e, 0x56, 0x9d, 0xba, 0x24, 0x38, 0xb6, 0x91, 0x3b, 0x57, 0xae, 0x6a, 0x46, 0x7a, 0x8c, 0xb2, 0x17, 0xd2, 0x48, 0xc9, 0xcd, 0xa2, 0xd, 0x9a, 0xbd, 0xc2, 0xc9, 0x4a, 0xb7, 0x87, 0x7, 0x3, 0x78, 0xc2, 0xa6, 0x33, 0x5c, 0x28, 0x2f, 0x95, 0xc6, 0x9, 0xba, 0xb2, 0x92, 0xb9, 0xdb, 0xea, 0x3, 0x6a, 0x1d, 0x57, 0xd5, 0xcc, 0x59, 0xbc, 0xa9, 0xe6, 0xb2, 0x17, 0x62, 0x4c, 0x52, 0xd3, 0x8e, 0x72, 0x3a, 0xaf, 0xf5, 0xcf, 0xb, 0xdd, 0xb8, 0xdd, 0xc8, 0xdc, 0xf5, 0x6f, 0xaf, 0xb2, 0x6a, 0xb7, 0x64, 0x27, 0xf1, 0x70, 0xd4, 0xa3, 0x10, 0x1d, 0x77, 0x29, 0xd4, 0x32, 0x23, 0x25, 0x7d, 0x19, 0xcb, 0xf4, 0xba, 0x52, 0x2b, 0x97, 0x4e, 0x77, 0xd5, 0xe1, 0xc9, 0x6d, 0x4c, 0xd7, 0xcd, 0xd3, 0xdb, 0x33, 0x8e, 0xa4, 0xd2, 0x4e, 0x3e, 0xa0, 0x59, 0x54, 0x93, 0x62, 0x77, 0xb9, 0xc5, 0x1d, 0x1a, 0x17, 0x73, 0xa5, 0xd8, 0x45, 0xf4, 0xa, 0x9f, 0xa6, 0x4d, 0xc3, 0x4a, 0x9f, 0x9f, 0xd7, 0xa, 0x72, 0xe7, 0xec, 0x2c, 0x9d, 0x3b, 0x89, 0xaa, 0xd, 0x65, 0x80, 0x27, 0xc9, 0xcb, 0xd2, 0x62, 0xdc, 0xaa, 0xcf, 0xea, 0x97, 0x83, 0x51, 0x1b, 0x4f, 0xe6, 0x1c, 0x49, 0x8c, 0xd4, 0x17, 0xf1, 0xbb, 0x41, 0x59, 0x9f, 0x3c, 0x3c, 0x2c, 0x8e, 0xc7, 0x53, 0x53, 0x5d, 0x18, 0xc5, 0xd3, 0xae, 0xd1, 0x1d, 0xf5, 0xa4, 0x8e, 0x9c, 0xb9, 0x20, 0x15, 0x63, 0xa5, 0xc4, 0x46, 0xb9, 0xfa, 0x3, 0x46, 0x7a, 0xf3, 0xa, 0x67, 0x7b, 0xba, 0x7d, 0x7b, 0x1e, 0x8d, 0x9e, 0x5c, 0x56, 0xb4, 0xd3, 0x64, 0xaa, 0xc2, 0x91, 0x9c, 0xe4, 0xaa, 0x95, 0x58, 0xad, 0xa3, 0x91, 0x4a, 0x4f, 0xa9, 0x5c, 0x14, 0x62, 0xe3, 0xd6, 0x68, 0xd6, 0xe9, 0xa4, 0x3a, 0x93, 0xde, 0x28, 0x56, 0xeb, 0xb7, 0xec, 0x93, 0x56, 0x21, 0x79, 0x9c, 0x22, 0xb7, 0xfd, 0xa5, 0x18, 0x74, 0x6d, 0x69, 0x8f, 0x31, 0x89, 0xc6, 0xec, 0x16, 0xd2, 0x96, 0x89, 0x9a, 0xe8, 0xce, 0xbc, 0xdb, 0xab, 0x56, 0xa9, 0x42, 0xd4, 0x72, 0x2f, 0x9a, 0xb4, 0x74, 0x7c, 0x51, 0xb5, 0x26, 0xab, 0xf8, 0xf0, 0xa1, 0x54, 0x1e, 0x1d, 0x9b, 0x99, 0x73, 0x38, 0xc9, 0xa2, 0x8e, 0x51, 0x5f, 0x65, 0x87, 0x67, 0x1a, 0xb4, 0x2a, 0x45, 0xba, 0x9a, 0x77, 0x8e, 0xb3, 0x3d, 0xb3, 0x21, 0x2f, 0x26, 0xb9, 0x91, 0x29, 0xb, 0x1, 0xbc, 0x18, 0xf6, 0xcf, 0x4f, 0xd1, 0xe2, 0x6e, 0x7c, 0x9c, 0xce, 0xd4, 0xba, 0x77, 0x39, 0x23, 0x3d, 0x19, 0x3c, 0xa4, 0xed, 0x7e, 0xf7, 0x72, 0x79, 0x75, 0xdc, 0x68, 0x5f, 0x35, 0xab, 0x97, 0xe7, 0x27, 0xe7, 0xb7, 0xf, 0x93, 0xfb, 0x8b, 0x56, 0x4c, 0x59, 0x98, 0xdd, 0xc, 0x2a, 0x66, 0x6, 0x97, 0x8d, 0xda, 0x4c, 0xab, 0x66, 0xac, 0xdc, 0x82, 0x23, 0xc9, 0xa4, 0x47, 0xcb, 0x44, 0xbf, 0x38, 0xe8, 0x8c, 0xeb, 0xb9, 0x66, 0xa9, 0x9d, 0xb8, 0x5d, 0x9d, 0x6b, 0x98, 0x96, 0xe5, 0xce, 0x71, 0x25, 0x9e, 0xa8, 0x1c, 0x9f, 0x9f, 0x8f, 0xbb, 0x1d, 0xa3, 0x14, 0x4f, 0x4b, 0x8d, 0xf8, 0x38, 0x1b, 0x23, 0xf2, 0xe5, 0xb0, 0x4b, 0xcf, 0x8e, 0xa5, 0x66, 0xfd, 0xc1, 0xb2, 0xa3, 0xc3, 0xba, 0x98, 0x1, 0x8d, 0xe4, 0x6c, 0xb5, 0xba, 0xb7, 0xa7, 0xe9, 0xe3, 0xc4, 0xc5, 0x83, 0x3e, 0xb0, 0xac, 0xcb, 0xf6, 0xa8, 0x21, 0xcf, 0x8e, 0x73, 0xf5, 0x45, 0x69, 0x6a, 0xa6, 0x9a, 0x2b, 0xa9, 0x6d, 0xf, 0x17, 0xcb, 0xe3, 0x7b, 0xa3, 0x75, 0x52, 0xb8, 0xba, 0x9d, 0x2e, 0x2f, 0x8b, 0x76, 0xa2, 0xd8, 0x30, 0xda, 0xc9, 0xca, 0x3c, 0x3b, 0x2a, 0x8, 0x1, 0x54, 0x66, 0x77, 0xfa, 0xfc, 0x7c, 0x81, 0x4a, 0x83, 0xa9, 0x5d, 0x31, 0xcf, 0x4e, 0x32, 0xd9, 0xba, 0x5a, 0x2d, 0x8e, 0xeb, 0xf3, 0xa1, 0x79, 0x9c, 0x1d, 0x14, 0xc6, 0xd, 0x7a, 0x91, 0x9c, 0x4d, 0xa7, 0x95, 0x8b, 0xfb, 0xf3, 0xe4, 0x79, 0x2c, 0xb3, 0x2a, 0xe8, 0xa7, 0xb4, 0xf2, 0x90, 0x4e, 0x8d, 0x7, 0x96, 0xaa, 0xdc, 0xd, 0x6e, 0xc5, 0x84, 0x5e, 0x5b, 0x3d, 0x50, 0xce, 0xee, 0xc5, 0xea, 0x6c, 0x91, 0x9e, 0x46, 0xe3, 0x4a, 0xae, 0x37, 0x9d, 0xc4, 0xe4, 0x71, 0xb1, 0x69, 0xe8, 0xf4, 0x78, 0x81, 0xd4, 0xf4, 0xc5, 0xf8, 0x3e, 0x71, 0x9f, 0x96, 0x63, 0x7d, 0xc3, 0x32, 0xb4, 0xe9, 0x48, 0x9a, 0xb7, 0xd4, 0x5e, 0xe6, 0x14, 0x21, 0x59, 0x6d, 0xa5, 0x4, 0x92, 0xcb, 0x68, 0xa5, 0xf8, 0xf0, 0xa0, 0x27, 0x8d, 0xd3, 0xaa, 0x11, 0xcf, 0x5c, 0xc2, 0x33, 0x9c, 0x50, 0x27, 0xe7, 0xc5, 0xfb, 0x55, 0x25, 0x19, 0xab, 0x8d, 0x6, 0x35, 0x7c, 0x75, 0x7e, 0x72, 0x76, 0x92, 0x68, 0x46, 0xb3, 0x3d, 0x1a, 0xcb, 0x5e, 0x56, 0x1b, 0xc5, 0xbb, 0xe2, 0xbd, 0x7a, 0x5b, 0x4f, 0x1a, 0x97, 0xe6, 0xc5, 0xd2, 0x51, 0xd4, 0xbd, 0xd6, 0x64, 0xb5, 0x4a, 0xa8, 0x85, 0xbb, 0xc5, 0xe9, 0x62, 0xd6, 0x92, 0xb2, 0xf1, 0x42, 0x6c, 0x86, 0xcf, 0x93, 0x27, 0xad, 0xfb, 0xa4, 0x34, 0xc1, 0xc9, 0xfb, 0xd8, 0x69, 0xa7, 0x2d, 0x49, 0xfd, 0x3a, 0xa9, 0xdb, 0xb4, 0xaf, 0x3e, 0xdc, 0x76, 0xea, 0xc9, 0x7, 0xa5, 0x59, 0xb1, 0x8c, 0xb2, 0x72, 0xd1, 0x7b, 0x80, 0x1c, 0xc9, 0xf4, 0x38, 0x35, 0x9b, 0x5b, 0xa5, 0x45, 0xb3, 0x32, 0x46, 0x9d, 0xf2, 0xe4, 0xf2, 0xfc, 0x54, 0x1b, 0xd, 0x49, 0xfb, 0xf2, 0xec, 0x42, 0x55, 0xb4, 0xcc, 0x24, 0x4b, 0x68, 0x59, 0xcb, 0xa2, 0x55, 0xb3, 0x55, 0x5f, 0xa6, 0x8e, 0x5b, 0xa5, 0x6a, 0x67, 0x4a, 0xcd, 0xab, 0xee, 0x68, 0xaa, 0xd3, 0x72, 0xe2, 0xee, 0xbe, 0x20, 0xe6, 0xe2, 0x45, 0x7f, 0xba, 0x38, 0xe9, 0xcf, 0x52, 0xe4, 0xa, 0x96, 0x71, 0x21, 0x79, 0x12, 0xb7, 0x6a, 0x28, 0x31, 0x39, 0x2b, 0x3e, 0xcc, 0xea, 0xc3, 0x55, 0xed, 0x2c, 0x6b, 0x25, 0xef, 0xd5, 0x87, 0x64, 0x32, 0x73, 0x55, 0x94, 0xc9, 0xc3, 0x22, 0xd3, 0x8c, 0x59, 0x8d, 0x8b, 0xab, 0x8b, 0x69, 0x45, 0x9a, 0xa4, 0xb4, 0xea, 0xc3, 0xd4, 0x16, 0x86, 0x5f, 0xf1, 0xae, 0x3d, 0x9e, 0x25, 0x57, 0xb1, 0xc9, 0xc5, 0x6d, 0xb6, 0xab, 0x1a, 0xd1, 0x95, 0x45, 0x6, 0xfd, 0xe2, 0x54, 0x29, 0xd6, 0xaf, 0x14, 0x7b, 0x7e, 0x5b, 0x20, 0xf5, 0x62, 0xa1, 0xd2, 0x3c, 0xed, 0xf6, 0xcf, 0x4f, 0x74, 0x75, 0x12, 0x9d, 0x2e, 0xd2, 0x9d, 0x8b, 0x5e, 0xa9, 0xb6, 0x6a, 0xdc, 0xdf, 0xd9, 0xd5, 0x5b, 0xc1, 0x6c, 0x93, 0x8a, 0x1e, 0xad, 0x64, 0xc7, 0xcb, 0xd4, 0x45, 0xff, 0xae, 0x25, 0xdf, 0x46, 0x33, 0x4b, 0xdc, 0x3f, 0x25, 0xf, 0xa6, 0x34, 0xca, 0x92, 0xd5, 0xc5, 0xad, 0x75, 0x71, 0xd9, 0x19, 0xab, 0xb8, 0xd9, 0x3b, 0xbb, 0x94, 0x2b, 0xb3, 0x52, 0x76, 0x99, 0x50, 0x9b, 0xad, 0xdb, 0xf6, 0x9d, 0x7e, 0xf2, 0x70, 0xd6, 0x29, 0xd4, 0x33, 0x94, 0x23, 0xe9, 0xc0, 0x74, 0xf1, 0xac, 0x8b, 0xa7, 0x77, 0xab, 0xcb, 0xab, 0xee, 0x65, 0x35, 0x55, 0x6d, 0x1c, 0x9f, 0x4b, 0x3, 0x75, 0x38, 0x5a, 0x5c, 0x9d, 0xe9, 0x39, 0x3a, 0x29, 0xdd, 0x25, 0x47, 0xa5, 0xfb, 0x61, 0xb1, 0x6d, 0x9d, 0x25, 0xab, 0xb5, 0x71, 0xa3, 0xa1, 0x26, 0x4e, 0xaa, 0x67, 0xcd, 0x84, 0x79, 0x8a, 0xed, 0x13, 0x33, 0x5d, 0x15, 0x94, 0x9c, 0xcb, 0xc8, 0xb2, 0xcb, 0x27, 0xed, 0x12, 0xae, 0x57, 0x47, 0xe3, 0xe1, 0xc9, 0xf1, 0x14, 0x9f, 0xc6, 0xe5, 0x4a, 0x3b, 0x1, 0xa3, 0x67, 0xc7, 0x99, 0x49, 0x2f, 0x7d, 0x9e, 0xbc, 0x2f, 0x65, 0xce, 0xcb, 0x4a, 0xf3, 0xb8, 0x78, 0xd7, 0x92, 0x72, 0xcb, 0xab, 0x74, 0x2f, 0x97, 0xad, 0x26, 0xb3, 0x97, 0xf, 0xa5, 0x46, 0xc3, 0x10, 0x66, 0xf9, 0xbc, 0x6d, 0x54, 0x26, 0xda, 0xe2, 0x14, 0xdb, 0xf3, 0x9c, 0x75, 0x72, 0x72, 0xb6, 0x2c, 0x77, 0x2f, 0xe4, 0xb3, 0xb4, 0xbd, 0xaa, 0xdd, 0x21, 0xda, 0x88, 0x5e, 0xe0, 0x25, 0x22, 0x29, 0x7d, 0x96, 0x5a, 0xc5, 0xaf, 0xba, 0xd8, 0x58, 0xca, 0x63, 0xc9, 0x2e, 0x92, 0x51, 0xe7, 0xac, 0x96, 0x96, 0xda, 0x77, 0x15, 0x61, 0x9f, 0xa4, 0x5b, 0x97, 0xbd, 0xf3, 0xb6, 0x62, 0x35, 0xec, 0xdb, 0x5b, 0x35, 0x76, 0x79, 0x35, 0xaf, 0x4a, 0xa9, 0x44, 0x7b, 0x21, 0x3f, 0x44, 0x47, 0x93, 0x93, 0xb4, 0x7a, 0x72, 0x5b, 0x46, 0xf3, 0xe5, 0x74, 0xa2, 0xe4, 0xb4, 0x64, 0x6e, 0x1c, 0xa5, 0x52, 0xa5, 0x3a, 0x30, 0xd5, 0xcc, 0x43, 0xee, 0x21, 0x3b, 0xfa, 0x6d, 0xbd, 0xa8, 0xaa, 0xb4, 0xcb, 0xc1, 0x4b, 0xaa, 0xed, 0x95, 0xe8, 0xd6, 0x42, 0x34, 0x60, 0x1d, 0xfa, 0xca, 0x65, 0xa8, 0x2, 0x2d, 0x38, 0x86, 0x14, 0x9, 0xa7, 0x0, 0x9e, 0x78, 0x8e, 0x4e, 0xe0, 0xbe, 0x1, 0x98, 0x72, 0xf7, 0xe5, 0x77, 0xee, 0xe4, 0x3d, 0xb2, 0x56, 0x6, 0x3a, 0xe2, 0x1b, 0x2a, 0x6e, 0x4d, 0xee, 0xf7, 0xe0, 0x5b, 0x1, 0x13, 0xac, 0xaa, 0xdc, 0xc9, 0x28, 0x13, 0x5d, 0x47, 0x32, 0xdf, 0x45, 0xc2, 0xfa, 0x84, 0x98, 0x9a, 0xe3, 0xa2, 0xc4, 0xba, 0xf, 0x8c, 0x2d, 0x49, 0xf9, 0x56, 0x1, 0x0, 0xc, 0x69, 0x1e, 0x60, 0x5d, 0xbc, 0x61, 0xeb, 0x61, 0xe7, 0x4f, 0xc7, 0xd7, 0xb8, 0x5e, 0x1d, 0x3f, 0xb6, 0x3e, 0x56, 0xc6, 0x4e, 0x95, 0x47, 0x56, 0xc8, 0x8f, 0xae, 0x91, 0x59, 0x3f, 0xb8, 0xb7, 0xdc, 0x36, 0x90, 0x69, 0x53, 0x64, 0x2, 0xd7, 0xed, 0x5, 0xc8, 0xc4, 0x1b, 0x10, 0xa1, 0x43, 0xd7, 0xfe, 0x26, 0x79, 0x6, 0xf5, 0x29, 0xc2, 0x96, 0xe3, 0x16, 0xf2, 0x3b, 0x76, 0xdc, 0xcd, 0x2d, 0x67, 0x2b, 0xe2, 0x11, 0xd7, 0xce, 0x61, 0xe7, 0xce, 0xa6, 0x7b, 0x67, 0xc7, 0xc1, 0xb3, 0xe3, 0xe2, 0xd9, 0xe3, 0xe4, 0x9, 0x70, 0xf3, 0x4, 0x32, 0x4e, 0x10, 0xeb, 0x6c, 0x31, 0xf, 0xf0, 0x98, 0x45, 0xb4, 0x37, 0x13, 0x3e, 0xd0, 0x58, 0x2e, 0x1e, 0x89, 0xa5, 0xb3, 0x11, 0x29, 0x12, 0x13, 0xbd, 0x33, 0x84, 0xeb, 0x33, 0x95, 0x4c, 0x38, 0xbe, 0x34, 0x77, 0x2f, 0x3e, 0xf, 0x8e, 0xd8, 0x9f, 0x47, 0xdb, 0x23, 0xea, 0xfe, 0x79, 0xe4, 0x78, 0xc7, 0x4c, 0x54, 0x76, 0xd9, 0x14, 0x1c, 0xb9, 0xce, 0x6d, 0xe7, 0xa5, 0xa, 0xb1, 0xe9, 0x7b, 0xcb, 0x7f, 0x3b, 0x3e, 0x64, 0x62, 0x41, 0x73, 0xd5, 0xe7, 0xbe, 0x43, 0x5f, 0xd, 0xf1, 0xf8, 0xda, 0xef, 0x53, 0x74, 0x6a, 0xe2, 0xa9, 0x1e, 0x58, 0x93, 0x3f, 0x3f, 0xa, 0x85, 0x42, 0x6e, 0xd3, 0x87, 0x3d, 0x36, 0x6e, 0xcd, 0xb0, 0x31, 0x23, 0x16, 0x67, 0x71, 0x87, 0x2b, 0x17, 0xf1, 0x48, 0x3a, 0x12, 0xf, 0x7, 0xec, 0x12, 0x1d, 0xe0, 0xcd, 0x99, 0x65, 0x19, 0xfd, 0x47, 0x7d, 0x38, 0x2a, 0x99, 0x36, 0xd1, 0x2, 0xa9, 0x79, 0x2e, 0x73, 0xa1, 0x2f, 0x7c, 0x63, 0x3, 0xe9, 0x16, 0x20, 0xb6, 0x5, 0x88, 0x2e, 0x36, 0x37, 0x66, 0x8, 0x8c, 0x11, 0xdf, 0x27, 0x20, 0xec, 0x33, 0x88, 0x9d, 0x16, 0x59, 0x25, 0xb6, 0xf2, 0xb, 0x5, 0xc2, 0x35, 0xea, 0xf2, 0x68, 0x84, 0x29, 0x18, 0xf1, 0xc8, 0xd9, 0x87, 0x75, 0xb4, 0xd0, 0x54, 0x5e, 0x6f, 0xba, 0xcd, 0xd1, 0x6a, 0x82, 0x55, 0xbe, 0x91, 0xea, 0x3e, 0x1a, 0xdb, 0xf2, 0x9c, 0x51, 0xb9, 0x7e, 0x22, 0xcf, 0x6c, 0x7d, 0xee, 0xf8, 0xea, 0x53, 0xf1, 0x64, 0x3c, 0x9b, 0x95, 0x9c, 0x77, 0x34, 0xe1, 0x61, 0x62, 0x43, 0xc6, 0xfd, 0xc1, 0x1e, 0x98, 0x90, 0x88, 0x39, 0x5a, 0xf9, 0x1f, 0x8a, 0xee, 0x6e, 0x3d, 0xdc, 0x6d, 0xd2, 0xd9, 0x67, 0xf1, 0xf6, 0x20, 0xf8, 0x63, 0xf8, 0x60, 0x9b, 0x28, 0xef, 0x43, 0x4f, 0x6c, 0xdd, 0x72, 0x18, 0xf1, 0x68, 0xeb, 0xf1, 0x56, 0xb, 0x32, 0x71, 0x82, 0x4f, 0x1c, 0x8f, 0xb2, 0x49, 0x88, 0x55, 0x62, 0x6c, 0xbd, 0xe3, 0x2a, 0x2b, 0x55, 0x7a, 0x83, 0xfa, 0x49, 0xbd, 0x54, 0x18, 0x54, 0x36, 0xdc, 0x64, 0x15, 0xe9, 0xa1, 0x54, 0x2a, 0x98, 0xf6, 0xb4, 0xb0, 0xac, 0x17, 0xb, 0xd3, 0xfa, 0x69, 0xa1, 0x3e, 0xa5, 0x89, 0xfe, 0xf1, 0x8c, 0xde, 0xce, 0xb4, 0x56, 0x41, 0xaa, 0x96, 0xfa, 0x77, 0xd5, 0x7e, 0x7d, 0x9c, 0x28, 0x9f, 0x55, 0x8a, 0xa5, 0xe5, 0xb0, 0xd0, 0x2a, 0x14, 0x96, 0xb5, 0x99, 0xdc, 0x6e, 0xd, 0x64, 0xb1, 0xac, 0x6d, 0xd, 0xa, 0xa9, 0xd6, 0x40, 0x5e, 0xb5, 0x1f, 0xce, 0x52, 0x17, 0xec, 0xc5, 0xad, 0x7c, 0xdf, 0x1a, 0x14, 0x12, 0xde, 0xb3, 0xdb, 0x42, 0xa1, 0x55, 0xaf, 0x97, 0xea, 0xb7, 0x85, 0x76, 0x71, 0x3a, 0xbf, 0x9b, 0xcd, 0x71, 0x35, 0xb7, 0x94, 0x8a, 0x85, 0xb3, 0xca, 0x49, 0xa1, 0xd0, 0x29, 0x89, 0xc5, 0xe4, 0x34, 0xcb, 0x2b, 0x95, 0xa6, 0x9f, 0xe, 0xbb, 0x4f, 0x87, 0xdd, 0xff, 0x1c, 0x87, 0x1d, 0x6c, 0x9f, 0xb5, 0x2a, 0xc9, 0x65, 0xed, 0x6c, 0x54, 0x3e, 0xef, 0x49, 0x9d, 0x62, 0x71, 0x54, 0x39, 0x29, 0xb5, 0x46, 0xa3, 0x56, 0xa7, 0x29, 0x55, 0xa2, 0xc3, 0xd5, 0x6d, 0x6a, 0x49, 0x51, 0x79, 0x52, 0x57, 0x33, 0x24, 0x59, 0x69, 0xd2, 0x56, 0x31, 0x5b, 0x2d, 0xc4, 0x86, 0x4a, 0x7d, 0x79, 0x36, 0x6a, 0x15, 0xa1, 0x40, 0xf2, 0x28, 0x40, 0x61, 0xc9, 0x1, 0x2a, 0xcb, 0xb3, 0x93, 0x56, 0xa1, 0x55, 0x2c, 0x4c, 0xb2, 0xcb, 0xf2, 0xd9, 0xe8, 0xb4, 0x41, 0xae, 0xea, 0xb3, 0x85, 0xdc, 0x2e, 0x9c, 0x39, 0x16, 0x64, 0xf1, 0xac, 0x50, 0x9e, 0x4e, 0xeb, 0xc5, 0x42, 0xb1, 0x9a, 0x9d, 0x74, 0x17, 0xa6, 0xd9, 0x3b, 0x46, 0xa6, 0xb1, 0x3c, 0x3b, 0xb1, 0x8b, 0xd1, 0x54, 0xfa, 0x36, 0x8e, 0xd3, 0xb4, 0x73, 0x7c, 0x47, 0x3a, 0xa7, 0x5d, 0xa3, 0xd0, 0x1a, 0x2d, 0xe7, 0xf, 0xf5, 0x92, 0x39, 0x90, 0x10, 0x32, 0x2f, 0xa, 0x70, 0xb1, 0x24, 0x2b, 0x61, 0x10, 0x4b, 0xc3, 0x42, 0xa3, 0x9d, 0x91, 0x87, 0xa8, 0x72, 0x7a, 0x79, 0x5b, 0xef, 0x65, 0x68, 0xa6, 0x44, 0xa6, 0xd5, 0x13, 0x7c, 0x7b, 0xa1, 0xc0, 0xb, 0x78, 0x46, 0x2f, 0x87, 0x65, 0xe9, 0xe1, 0xf4, 0x2e, 0x5, 0x89, 0xd5, 0x1c, 0x5d, 0x35, 0xb1, 0x56, 0x91, 0x63, 0x1d, 0xc9, 0x2e, 0x68, 0xa7, 0x15, 0x3a, 0x19, 0x9, 0x55, 0xb0, 0xc8, 0x68, 0x55, 0x29, 0x83, 0x86, 0xe9, 0x29, 0x8a, 0xc7, 0x69, 0x9f, 0xa4, 0x66, 0xf7, 0xb3, 0x73, 0x43, 0xad, 0x5a, 0xa9, 0xf8, 0x4c, 0xbf, 0xd4, 0x7, 0x52, 0x59, 0x99, 0xf6, 0x7b, 0x57, 0xc6, 0x5d, 0x5c, 0x5b, 0x4c, 0x95, 0x9c, 0x2a, 0x13, 0xa3, 0x80, 0x95, 0xd6, 0x71, 0xa3, 0xa6, 0x42, 0x48, 0x2f, 0xc5, 0x2a, 0xbd, 0x8e, 0xe4, 0x5a, 0xa3, 0x95, 0xcb, 0x35, 0x2e, 0x73, 0xe5, 0x2c, 0xd5, 0x4c, 0xa9, 0x20, 0x9f, 0xa5, 0x5b, 0xd1, 0xd1, 0x74, 0x3c, 0x89, 0xdf, 0xdd, 0x76, 0x72, 0xa3, 0x9e, 0x66, 0x14, 0xeb, 0xb7, 0xab, 0xb3, 0x8b, 0xa, 0x9c, 0xa3, 0xe4, 0x2a, 0x9a, 0x6c, 0x5e, 0x68, 0xc7, 0x89, 0xe3, 0x85, 0x94, 0x45, 0xf2, 0x34, 0x59, 0x74, 0x16, 0x4e, 0xb8, 0x55, 0x92, 0x7a, 0xcb, 0xd8, 0x99, 0xdc, 0xbd, 0x9b, 0x2e, 0x61, 0x15, 0x5e, 0xd8, 0x99, 0x58, 0xcf, 0x1a, 0xcd, 0x56, 0x83, 0x69, 0xa6, 0xaf, 0x17, 0xe6, 0xfa, 0x38, 0xa5, 0x17, 0xe5, 0x5a, 0x7d, 0xdc, 0x1c, 0x4b, 0x33, 0xa5, 0x39, 0x3d, 0x1b, 0xc0, 0xc4, 0x95, 0x62, 0x5d, 0x4e, 0xef, 0xe4, 0x59, 0x5d, 0xd8, 0x35, 0x55, 0xfb, 0x44, 0xad, 0x14, 0xb5, 0xda, 0xc9, 0x55, 0x37, 0x3d, 0x6e, 0x9e, 0x76, 0x7a, 0xbd, 0xe1, 0x99, 0x4, 0x4d, 0x9c, 0x5a, 0x1a, 0x97, 0x75, 0x3a, 0x9a, 0x98, 0xc5, 0xe4, 0x20, 0xdb, 0x5d, 0x8d, 0x7, 0xf, 0xb, 0x98, 0xe8, 0x94, 0x5a, 0x6a, 0x85, 0xb6, 0x6e, 0xed, 0x15, 0x3d, 0x31, 0x73, 0x68, 0x39, 0x7b, 0x10, 0x9a, 0x2d, 0x37, 0xac, 0x36, 0x71, 0xff, 0xac, 0x5d, 0x5e, 0x35, 0xa, 0x31, 0xe9, 0x34, 0x7b, 0xb1, 0x54, 0x1f, 0xc6, 0xa8, 0x2c, 0x15, 0xa, 0x17, 0xb9, 0x64, 0x72, 0x76, 0x91, 0x2c, 0x8f, 0xa7, 0xe9, 0xfe, 0xc5, 0x22, 0x39, 0x2d, 0x90, 0x54, 0x6c, 0x70, 0x9c, 0x2e, 0xd8, 0xf3, 0x9e, 0x62, 0x1b, 0xa9, 0x55, 0x5a, 0x9d, 0x9c, 0xa5, 0xc4, 0x3a, 0x70, 0x96, 0x6c, 0x8e, 0x49, 0xda, 0x78, 0x80, 0x85, 0x44, 0x3a, 0x57, 0xa7, 0xa7, 0x45, 0xdd, 0x5a, 0x34, 0x16, 0x18, 0xa6, 0x67, 0xc3, 0x49, 0xb4, 0x3f, 0x9d, 0xe9, 0xe3, 0x6a, 0xc6, 0x28, 0xd5, 0x2e, 0xa3, 0x85, 0xa, 0x56, 0xe5, 0xe9, 0x60, 0x1c, 0x4b, 0xd4, 0x74, 0xe5, 0x24, 0x5a, 0x3d, 0xce, 0xc0, 0xab, 0x69, 0x43, 0xa8, 0x47, 0xd, 0xe7, 0xee, 0x16, 0xed, 0x5e, 0xbf, 0x4c, 0x2b, 0xd1, 0xa2, 0x39, 0xbd, 0x82, 0x4b, 0xb2, 0x30, 0xb2, 0xb1, 0xe3, 0xdb, 0x34, 0x6c, 0x26, 0x57, 0xe9, 0xa1, 0x75, 0x39, 0xa2, 0x46, 0xcd, 0x3c, 0xee, 0xdb, 0x17, 0xb4, 0x31, 0xa2, 0xb0, 0x96, 0x31, 0xd4, 0x54, 0x8d, 0x1a, 0xed, 0xd2, 0xea, 0x34, 0xb5, 0x38, 0x17, 0xea, 0x51, 0x31, 0x4e, 0xb, 0x4b, 0x42, 0x4f, 0x8a, 0x77, 0xfd, 0x8a, 0x5e, 0x4f, 0x24, 0x12, 0xcb, 0x82, 0xad, 0x1b, 0xad, 0x91, 0x86, 0xa3, 0xb7, 0x8d, 0x5a, 0x2d, 0x7a, 0x9b, 0xbc, 0xb8, 0xbb, 0x6d, 0xea, 0xa5, 0xba, 0x6e, 0x48, 0xd1, 0x25, 0xb1, 0x1f, 0x46, 0x76, 0x32, 0xae, 0x66, 0xbb, 0xda, 0x43, 0x2a, 0x17, 0x2b, 0xf6, 0xc5, 0xc2, 0xe9, 0x14, 0x4e, 0x53, 0x92, 0x34, 0xae, 0x14, 0xef, 0xef, 0xea, 0xf1, 0x5e, 0xb3, 0xd2, 0x9c, 0xb6, 0xac, 0xe8, 0x78, 0xa8, 0xdc, 0x1a, 0xc9, 0x76, 0xbc, 0x95, 0xd1, 0xcc, 0x7b, 0xc5, 0x6c, 0x1f, 0xc7, 0x53, 0x99, 0x5c, 0x6d, 0xf0, 0x30, 0x4e, 0xd7, 0x16, 0xd8, 0xce, 0x6d, 0xae, 0x75, 0x2, 0xe6, 0xc4, 0x97, 0xed, 0x94, 0xfa, 0xcd, 0xe9, 0xd7, 0xee, 0x93, 0xa6, 0xde, 0x6c, 0x9f, 0xf4, 0xcb, 0x17, 0x50, 0xe1, 0xf1, 0x12, 0x4e, 0xf4, 0x85, 0x82, 0x29, 0x90, 0xa1, 0x3c, 0xc3, 0xfa, 0x94, 0x2d, 0x79, 0xfc, 0x21, 0x19, 0xac, 0x36, 0xaf, 0xe0, 0x60, 0x87, 0x8a, 0x62, 0x72, 0xa3, 0x56, 0xc1, 0x34, 0xcc, 0xd, 0xe8, 0x74, 0x22, 0x93, 0x13, 0x4b, 0x2a, 0xa0, 0x8c, 0xf3, 0x20, 0xfe, 0xb2, 0x75, 0x1d, 0xb7, 0x83, 0x83, 0x2, 0x39, 0xf6, 0xd8, 0xad, 0xab, 0xe5, 0x3c, 0x9e, 0x4a, 0xc4, 0x24, 0x29, 0xca, 0x21, 0x83, 0xec, 0x56, 0x29, 0x12, 0x7b, 0xb6, 0xdd, 0xfa, 0x9a, 0xf5, 0xec, 0x17, 0x60, 0x4c, 0x7b, 0xaf, 0x58, 0xd, 0x6f, 0x30, 0x8e, 0x31, 0x2d, 0xbf, 0x21, 0xeb, 0xfc, 0xec, 0x2d, 0xf6, 0x3e, 0xb2, 0x2c, 0xac, 0x4f, 0x45, 0xb0, 0x94, 0xe0, 0x37, 0x5, 0x19, 0x48, 0x57, 0x90, 0x2e, 0xaf, 0x78, 0xe0, 0x25, 0x45, 0x28, 0x28, 0x60, 0x79, 0x1d, 0x49, 0x13, 0xe5, 0xdf, 0x90, 0x6e, 0x4, 0x2d, 0x53, 0x8b, 0xf1, 0x4a, 0x94, 0x23, 0x64, 0x48, 0x18, 0xf6, 0x89, 0x6d, 0x5a, 0x33, 0x64, 0x3a, 0x31, 0xa, 0xb6, 0xc9, 0x63, 0x24, 0x23, 0x21, 0x87, 0x87, 0xbf, 0x80, 0xa1, 0xa1, 0x40, 0xb, 0xf1, 0x40, 0x30, 0xa4, 0xb8, 0xdc, 0x2e, 0x6b, 0x22, 0xdc, 0x54, 0x44, 0x4b, 0x52, 0x41, 0xe2, 0xb5, 0x6d, 0xaa, 0x0, 0x4f, 0xd8, 0xb2, 0xc3, 0x8d, 0xd6, 0xd8, 0x9, 0x19, 0x5, 0xfe, 0xb7, 0x6e, 0x84, 0x17, 0x5b, 0xe5, 0xd9, 0x8c, 0x40, 0xf1, 0xf9, 0x3c, 0x8e, 0x76, 0xdf, 0xa, 0xea, 0x9d, 0xef, 0xec, 0xf, 0xf1, 0xfb, 0x2, 0x6, 0x9d, 0x72, 0x27, 0xf, 0x6, 0x33, 0x64, 0x72, 0x3f, 0x6, 0xd7, 0x30, 0x1a, 0xc0, 0x94, 0xda, 0x28, 0xf, 0x4a, 0x50, 0xff, 0xc5, 0x2, 0xc4, 0x40, 0x82, 0x68, 0x68, 0xb0, 0x11, 0xc, 0x13, 0x5d, 0x5d, 0x1, 0xb1, 0xa6, 0xe9, 0x22, 0x53, 0xc3, 0x94, 0x62, 0xa2, 0x3, 0x5, 0xe9, 0x18, 0x29, 0x1e, 0x46, 0xe7, 0x3, 0x0, 0xcc, 0x69, 0xe7, 0x84, 0x8, 0xfc, 0x16, 0xd2, 0xc, 0x1e, 0x73, 0x5, 0x4d, 0x62, 0xeb, 0x4a, 0x4, 0x80, 0xb, 0xac, 0xaa, 0xc0, 0x44, 0xe1, 0x5, 0xa6, 0xac, 0xf6, 0xc, 0x53, 0x60, 0x98, 0x64, 0xac, 0x22, 0x2d, 0x12, 0x72, 0xd7, 0x2a, 0x1b, 0x1d, 0xa, 0x89, 0x75, 0x67, 0x90, 0xf0, 0xae, 0xe3, 0x9b, 0xe, 0x3b, 0x45, 0x4, 0x96, 0xb0, 0x0, 0xf1, 0xcb, 0xb3, 0x2b, 0xd1, 0x52, 0x24, 0xb5, 0x5f, 0xa2, 0x1f, 0x8f, 0x25, 0xe0, 0x2b, 0xe2, 0xe7, 0x91, 0xc1, 0x41, 0xde, 0x96, 0xc, 0x36, 0x3e, 0xb, 0xb7, 0xe9, 0x76, 0x67, 0x50, 0xe8, 0x8d, 0xae, 0xfb, 0xf5, 0x6a, 0xbb, 0xd2, 0xbb, 0x2e, 0x57, 0x4e, 0xa, 0xc3, 0xe6, 0xa0, 0xd0, 0xac, 0x17, 0xfa, 0x79, 0x37, 0xb6, 0x16, 0xaa, 0x18, 0x52, 0xc7, 0x5, 0xb2, 0x2f, 0x30, 0xb0, 0xcd, 0xc9, 0x5, 0xc2, 0x17, 0x10, 0x11, 0x1f, 0xf, 0xda, 0x16, 0x1, 0x6e, 0x98, 0x21, 0x63, 0x15, 0x8d, 0xb3, 0xb1, 0x4e, 0xd, 0x24, 0xe3, 0x9, 0x46, 0xa, 0x60, 0xfc, 0x25, 0xbe, 0xa6, 0x13, 0x1, 0xc8, 0xbb, 0xe7, 0x4, 0x7, 0x3a, 0x7f, 0xf3, 0x0, 0xc1, 0x97, 0x8, 0xbc, 0x17, 0xff, 0xed, 0x1e, 0x33, 0x40, 0x9a, 0xa1, 0x42, 0x26, 0xc2, 0xed, 0xce, 0xa0, 0xd2, 0x8f, 0x58, 0xf7, 0xd6, 0xdb, 0xc5, 0x98, 0x1f, 0x38, 0xff, 0x13, 0x8f, 0xa7, 0x13, 0x5b, 0xf1, 0xff, 0x49, 0xe9, 0xf3, 0xfc, 0xcf, 0xc7, 0x94, 0x50, 0x57, 0x45, 0x90, 0x22, 0xb0, 0x84, 0x58, 0x4, 0xfe, 0x52, 0xb4, 0x40, 0x26, 0x54, 0x81, 0x86, 0x75, 0xdb, 0x72, 0x42, 0x67, 0xdd, 0xb8, 0x65, 0x64, 0xa8, 0x64, 0xc5, 0xdd, 0x3f, 0x16, 0x1, 0x32, 0xd1, 0xc, 0x15, 0x59, 0x28, 0x12, 0x1a, 0xcc, 0x90, 0xe, 0x26, 0xc4, 0xb, 0x15, 0xa5, 0x16, 0x32, 0xe8, 0xa6, 0x4b, 0xc8, 0x89, 0x8d, 0xd, 0x85, 0x62, 0x11, 0x50, 0x50, 0x44, 0xd4, 0xa8, 0x83, 0xb5, 0x54, 0xd8, 0x10, 0x18, 0x8b, 0xb8, 0x7, 0x8c, 0xc6, 0x2b, 0x80, 0xee, 0x91, 0x6c, 0x5b, 0x6e, 0x38, 0xbb, 0x68, 0x82, 0xfd, 0x92, 0x89, 0xa6, 0x41, 0x5d, 0xc9, 0x87, 0x98, 0xe2, 0xb0, 0x15, 0x2, 0xb4, 0xb9, 0x82, 0x4d, 0x10, 0x36, 0x40, 0x14, 0x59, 0x72, 0x54, 0x44, 0xf9, 0x46, 0x19, 0x5a, 0x1a, 0x51, 0xa2, 0x7f, 0xfe, 0x9, 0x22, 0xe7, 0xe2, 0x80, 0xcb, 0x56, 0xc8, 0xed, 0x5f, 0x4c, 0x54, 0xd8, 0xfc, 0x25, 0x5b, 0x2a, 0x98, 0x22, 0xcb, 0xd, 0xaf, 0xfd, 0xbf, 0x8e, 0xa9, 0xa9, 0x43, 0xd, 0x51, 0x3, 0xca, 0x8, 0x30, 0x1c, 0x3d, 0xc4, 0xc7, 0x2a, 0xd2, 0xf6, 0x9e, 0xfe, 0xf5, 0x17, 0x7b, 0xe1, 0xa, 0xf, 0x38, 0x72, 0xa2, 0xac, 0x27, 0xb6, 0xaa, 0x32, 0xd0, 0x23, 0x10, 0x1, 0x7f, 0xfd, 0x15, 0x76, 0xc3, 0x62, 0x1d, 0xac, 0x4, 0xdc, 0x52, 0xa2, 0x1b, 0xd0, 0x9a, 0xfd, 0x76, 0xf4, 0x67, 0x84, 0x59, 0x9f, 0x11, 0x19, 0xfe, 0xdf, 0x88, 0x6c, 0x5a, 0x7f, 0x1d, 0x81, 0x1f, 0x3c, 0xc8, 0x30, 0x9d, 0x4, 0xe1, 0xb0, 0x82, 0x64, 0xa2, 0x20, 0xf0, 0xc3, 0x81, 0xe3, 0xfd, 0xb4, 0x10, 0x7a, 0x76, 0x17, 0xa3, 0x32, 0x64, 0xc8, 0x43, 0xa1, 0x78, 0x4, 0x54, 0x91, 0xe5, 0x8e, 0xbb, 0x8, 0xf3, 0xf4, 0x9c, 0xd1, 0x4f, 0x1c, 0xed, 0x80, 0xc1, 0x7a, 0xab, 0x61, 0xf2, 0x45, 0xce, 0x6, 0xe, 0x52, 0xad, 0xd0, 0x2b, 0x76, 0x7a, 0xd7, 0x85, 0x72, 0xab, 0xde, 0xbe, 0xee, 0x16, 0xfa, 0xfd, 0x8b, 0x4e, 0xaf, 0x1c, 0x34, 0x64, 0xff, 0x7f, 0x80, 0xe4, 0x19, 0x9, 0x85, 0x12, 0x82, 0xd7, 0xca, 0xed, 0x3e, 0x37, 0xaa, 0x54, 0x9b, 0x6f, 0x1e, 0x20, 0xdd, 0x32, 0x57, 0x7e, 0xb6, 0xe6, 0x81, 0xe3, 0x8f, 0xd, 0x20, 0xe3, 0xc9, 0x46, 0x96, 0x82, 0xba, 0xf3, 0x1d, 0x4b, 0x5e, 0x78, 0x33, 0xa8, 0x77, 0x1, 0xd1, 0x79, 0xb, 0xc2, 0x27, 0xc, 0x88, 0xc9, 0xec, 0x15, 0x36, 0xd5, 0x8b, 0xef, 0xc4, 0xcc, 0x6f, 0x1a, 0x9, 0xfd, 0xf9, 0x67, 0x98, 0xe9, 0x77, 0xb7, 0x9, 0x31, 0x81, 0xb9, 0xa7, 0x5c, 0x4, 0x1b, 0x3e, 0x4e, 0xab, 0x33, 0x87, 0xb8, 0xb4, 0xee, 0x8c, 0xa5, 0xc0, 0xc8, 0x5e, 0x8b, 0xd1, 0x7c, 0x23, 0x9a, 0x91, 0xce, 0xa9, 0xb, 0x25, 0x23, 0xa0, 0xc0, 0xad, 0x58, 0x77, 0xd0, 0x86, 0x75, 0xb0, 0xc0, 0xd0, 0x33, 0x7, 0x1f, 0x15, 0xb1, 0x50, 0x2a, 0x2, 0x9a, 0x64, 0x8a, 0x75, 0x17, 0x78, 0x89, 0xad, 0x99, 0x2b, 0xe5, 0xa5, 0x66, 0x9d, 0x33, 0x96, 0x13, 0x99, 0xaf, 0xf2, 0x7a, 0x8f, 0xa2, 0xfb, 0xd9, 0x2a, 0xf3, 0xdf, 0xaa, 0xec, 0xcc, 0xff, 0xd7, 0x33, 0xa4, 0x32, 0x83, 0x37, 0x62, 0x19, 0x6f, 0x75, 0x14, 0xf0, 0xf1, 0xf9, 0x3f, 0x16, 0x4b, 0x48, 0x3b, 0xf3, 0x7f, 0x26, 0x9e, 0xf8, 0x9c, 0xff, 0x3f, 0xa2, 0xfc, 0xf9, 0x67, 0xf4, 0x1b, 0x58, 0x60, 0x2d, 0xcf, 0xd7, 0x4c, 0x4c, 0x7, 0x58, 0x2b, 0x3, 0xfd, 0xa6, 0xb1, 0x61, 0x91, 0x67, 0x28, 0xf, 0xbe, 0x45, 0xff, 0xfa, 0x2b, 0xc4, 0x6a, 0x85, 0x2a, 0xf7, 0x6, 0x74, 0xf, 0x7c, 0xb8, 0xe7, 0x5a, 0xd8, 0xba, 0x8c, 0x1f, 0x1d, 0xf, 0x5d, 0x20, 0xb6, 0xa0, 0xd0, 0xf9, 0x1c, 0xe, 0x2d, 0x90, 0x4e, 0x88, 0x33, 0x27, 0x60, 0x8c, 0x64, 0xc8, 0x2c, 0x0, 0x4a, 0x34, 0x4, 0x1a, 0xde, 0x52, 0x51, 0xa0, 0x98, 0x60, 0xa4, 0x2a, 0x14, 0x40, 0x13, 0x89, 0x23, 0x5f, 0xe2, 0xe0, 0xf, 0x5f, 0xcf, 0xfc, 0x3a, 0x5e, 0x71, 0xf4, 0x4c, 0x4f, 0xe9, 0x50, 0x63, 0xf3, 0x10, 0xb3, 0x8d, 0xbf, 0x46, 0x42, 0xe, 0x45, 0x61, 0x67, 0x25, 0xb8, 0x56, 0x81, 0x7c, 0x2a, 0x9, 0xaf, 0x5f, 0xf2, 0xb3, 0x6f, 0xce, 0xdb, 0xa3, 0xb5, 0xee, 0x85, 0x1a, 0xea, 0x2c, 0x90, 0x69, 0x62, 0x3e, 0xb9, 0x72, 0xa2, 0x19, 0xb9, 0xec, 0x4f, 0xac, 0xf5, 0xed, 0xc9, 0x4, 0xdf, 0xb3, 0xc5, 0xbb, 0x87, 0x89, 0xe9, 0x40, 0xf6, 0xb7, 0x18, 0x85, 0x92, 0x89, 0x78, 0x17, 0xbd, 0x6, 0xd8, 0x2c, 0xb6, 0x2, 0x77, 0x36, 0x54, 0x85, 0xdd, 0xe, 0xd, 0x83, 0x77, 0xee, 0xef, 0x30, 0x24, 0xeb, 0x19, 0xd6, 0xed, 0xcc, 0xff, 0xe2, 0x8d, 0xe4, 0x7f, 0x7b, 0xe2, 0xf8, 0xb8, 0x60, 0x86, 0x89, 0x75, 0x6b, 0x2, 0x8e, 0xfe, 0x37, 0xd, 0xff, 0x6f, 0x7a, 0xb4, 0x39, 0xc7, 0x3b, 0x38, 0x9f, 0x3d, 0x94, 0xa0, 0x86, 0x54, 0xcd, 0x3d, 0x3d, 0xaa, 0x0, 0x15, 0x8e, 0x91, 0x4a, 0xc1, 0xbe, 0xae, 0x88, 0xd7, 0x2, 0xd5, 0xc, 0x99, 0xd8, 0x62, 0x4b, 0xc4, 0xd, 0x7b, 0xa3, 0xef, 0x9c, 0x47, 0xfb, 0xeb, 0xaf, 0x90, 0x29, 0x1e, 0xe5, 0x77, 0xec, 0x11, 0xf6, 0x92, 0x33, 0xac, 0x78, 0x25, 0xd2, 0x1e, 0x38, 0x2f, 0xc2, 0xeb, 0x27, 0xce, 0x91, 0x78, 0xf0, 0x83, 0xad, 0x3e, 0x55, 0x66, 0xc2, 0x1c, 0x1d, 0x1f, 0x81, 0xa3, 0xeb, 0x23, 0x6, 0xf, 0xd, 0x23, 0xf, 0x8e, 0x2, 0x27, 0x61, 0xcf, 0x98, 0x39, 0xa, 0xe8, 0x2e, 0x3f, 0xf8, 0xd5, 0x7c, 0xbc, 0x97, 0xbe, 0x3a, 0xa2, 0xab, 0x8f, 0xf6, 0xe4, 0x45, 0x94, 0xec, 0xb4, 0xe9, 0xce, 0xb0, 0xc3, 0x5e, 0x73, 0xfd, 0xa5, 0x7c, 0xc6, 0xca, 0xc6, 0x39, 0xc1, 0x5d, 0x86, 0xc8, 0x73, 0x86, 0x8, 0x9e, 0xad, 0x7f, 0xb5, 0x48, 0x5f, 0x1c, 0x43, 0xb, 0x42, 0xf6, 0x75, 0xcd, 0x17, 0x2a, 0x5d, 0xf3, 0xda, 0x1e, 0x5c, 0xdb, 0x3c, 0xb4, 0x2b, 0x9a, 0x43, 0x8a, 0xc0, 0xb7, 0xc8, 0xfa, 0xa0, 0x12, 0x80, 0xe2, 0x50, 0x63, 0x49, 0x1c, 0xc6, 0xe3, 0xa3, 0xe6, 0x3a, 0x93, 0xd6, 0x2b, 0x8e, 0xef, 0x21, 0x4a, 0x0, 0xb6, 0x80, 0xc, 0x75, 0xe7, 0x6c, 0xde, 0xe6, 0xd9, 0x47, 0xe7, 0x60, 0xa1, 0xae, 0xb8, 0x36, 0x98, 0xff, 0xf9, 0x7e, 0xd1, 0x63, 0x2d, 0x88, 0x86, 0xdb, 0x9b, 0x2, 0xa8, 0x62, 0x6a, 0x31, 0x1, 0xa4, 0x86, 0x8a, 0xad, 0x26, 0xfb, 0x71, 0x14, 0xd9, 0x3b, 0x80, 0x3b, 0x50, 0x86, 0xc9, 0x7d, 0x72, 0xe0, 0x57, 0x13, 0x51, 0x4b, 0x3c, 0xfe, 0xa, 0x8e, 0xbe, 0xf9, 0xf0, 0xcb, 0x3a, 0xab, 0x77, 0x4b, 0xb0, 0xce, 0x11, 0xb, 0xc8, 0xdd, 0xcf, 0x76, 0xc4, 0x6b, 0x6, 0xb, 0xe6, 0xc0, 0x77, 0x38, 0x51, 0x74, 0x9f, 0x4c, 0xfc, 0xbd, 0x47, 0x66, 0x64, 0x2f, 0x7, 0xfb, 0xd, 0xd1, 0xed, 0x56, 0x1d, 0xbf, 0xcd, 0x23, 0xc, 0x13, 0x40, 0xcf, 0x9e, 0x16, 0x1c, 0x69, 0xdf, 0x1c, 0x5c, 0x9f, 0x9a, 0xda, 0x70, 0x55, 0x1d, 0x81, 0x5f, 0xb1, 0x2e, 0xab, 0xb6, 0x12, 0xb8, 0xf8, 0xf8, 0xfa, 0xa4, 0x66, 0xdd, 0x50, 0x9d, 0x8, 0x33, 0x8f, 0x45, 0x93, 0x0, 0x38, 0xa2, 0x82, 0xee, 0xbc, 0xe, 0x79, 0xd5, 0xd8, 0x3c, 0xa, 0x8e, 0xdc, 0xa0, 0x23, 0x17, 0x40, 0x80, 0x1c, 0x5a, 0xa, 0xf9, 0xc2, 0x82, 0x36, 0xc4, 0xc3, 0x85, 0xdf, 0x69, 0xcc, 0x1d, 0x46, 0x4e, 0x9c, 0x8f, 0xb6, 0x3d, 0xc2, 0xb2, 0xbf, 0x73, 0x6, 0x31, 0x5f, 0xdb, 0x39, 0x3f, 0x8f, 0x89, 0x0, 0x1d, 0x3f, 0x41, 0x4f, 0xef, 0x8a, 0xe1, 0xea, 0x9b, 0x17, 0x76, 0xc5, 0x8d, 0x8, 0x7a, 0xcb, 0xee, 0x18, 0x84, 0x5a, 0x6c, 0x41, 0xf5, 0xc2, 0x2e, 0xb9, 0x24, 0xbd, 0xea, 0xb, 0xb9, 0x81, 0x4c, 0xaf, 0xeb, 0xd6, 0x4e, 0x65, 0xb7, 0x9a, 0xd7, 0x0, 0x5b, 0x58, 0xa7, 0x93, 0x48, 0x97, 0xc1, 0xf, 0x70, 0x67, 0x13, 0xb, 0xbd, 0xf0, 0x33, 0x3e, 0x5, 0xdd, 0x73, 0x7, 0xc1, 0x84, 0xcb, 0xee, 0x87, 0x8d, 0xc3, 0xeb, 0xba, 0xfd, 0x8a, 0x5e, 0xfa, 0xa3, 0xd4, 0xde, 0x92, 0x8b, 0xbd, 0x70, 0xb7, 0x97, 0x75, 0xcd, 0x4f, 0xd6, 0xab, 0xba, 0xe7, 0x8f, 0xb3, 0xfb, 0x1b, 0x49, 0xe9, 0x6, 0x5d, 0xaf, 0xe9, 0x60, 0x50, 0xb4, 0xe0, 0x5b, 0xf6, 0x53, 0xe0, 0x77, 0xa7, 0xb8, 0x17, 0xf5, 0x35, 0x88, 0xc4, 0x37, 0xe8, 0xf2, 0x46, 0xd8, 0xe3, 0x3b, 0x74, 0x59, 0x84, 0x4f, 0xbe, 0xaa, 0xcb, 0x1b, 0x24, 0xbe, 0x9a, 0x8d, 0x5, 0x2d, 0x2e, 0xe3, 0x9, 0x8f, 0xd8, 0xce, 0x2c, 0x1f, 0x30, 0x35, 0xb1, 0xe9, 0x3e, 0xff, 0x68, 0xdd, 0xd, 0x55, 0xc7, 0xaa, 0xff, 0xeb, 0xd1, 0xea, 0xc2, 0x3a, 0x39, 0x8c, 0x56, 0x4c, 0xf4, 0xac, 0xde, 0xe3, 0xa4, 0x6e, 0x9, 0x29, 0x3, 0xf8, 0x6f, 0x4a, 0x55, 0x8d, 0x28, 0xe8, 0x37, 0x27, 0xbd, 0xcd, 0xcb, 0x4, 0xe2, 0xdf, 0x76, 0xc4, 0x82, 0xa5, 0xfe, 0x4d, 0x6, 0xce, 0xc7, 0xf6, 0xff, 0xbe, 0x3, 0xb7, 0xa5, 0x3b, 0xe, 0xe, 0xdc, 0xcf, 0x76, 0xa1, 0xfd, 0xa3, 0xcb, 0x8e, 0xff, 0xd7, 0xb7, 0xb, 0xe3, 0xff, 0x3b, 0x2c, 0x6b, 0x2f, 0xce, 0xe, 0x77, 0x60, 0xff, 0x37, 0x15, 0x4b, 0x6c, 0xf9, 0x7f, 0xe3, 0x52, 0x2a, 0x9e, 0xfc, 0xf4, 0xff, 0x7e, 0x44, 0x81, 0x6, 0xf6, 0xf2, 0x3f, 0x2e, 0x62, 0xa1, 0x39, 0xd6, 0x95, 0xbc, 0x93, 0x9e, 0xab, 0x5, 0x8d, 0x90, 0x86, 0x2c, 0xe8, 0xc6, 0xc7, 0x39, 0x41, 0xed, 0xcf, 0xdb, 0xc9, 0xe3, 0x69, 0x58, 0xb8, 0x3f, 0x2b, 0x1f, 0xfa, 0xf3, 0x4f, 0xb0, 0xbd, 0xa, 0x77, 0xbd, 0x7a, 0x11, 0xf0, 0x3, 0x60, 0x5d, 0x41, 0xba, 0x5, 0x92, 0xce, 0x76, 0x18, 0xdf, 0x60, 0x26, 0x3a, 0xd2, 0xad, 0x3c, 0xf0, 0x27, 0xd5, 0x71, 0xc9, 0xe9, 0x76, 0xfa, 0x83, 0x6a, 0xaf, 0xd2, 0x3f, 0x6b, 0x5e, 0xd7, 0x3a, 0xfd, 0xc1, 0x1e, 0xca, 0x2, 0x94, 0xd5, 0xd1, 0x26, 0x70, 0xb7, 0xd3, 0x3b, 0x8, 0xbc, 0xd6, 0x60, 0x5b, 0xc0, 0xc3, 0x7e, 0xa5, 0xd7, 0x2e, 0xb4, 0x2a, 0x87, 0x10, 0x6c, 0x6a, 0xe1, 0x2d, 0x24, 0xe5, 0xc2, 0xa0, 0x50, 0x2c, 0xf4, 0xf, 0x22, 0xd9, 0x5c, 0xe, 0xb8, 0x88, 0x2a, 0xad, 0x42, 0xdd, 0x3f, 0x4, 0xae, 0xe1, 0xe3, 0x1b, 0xb3, 0x88, 0x97, 0x4e, 0x68, 0x3, 0x66, 0xdd, 0xf3, 0xbd, 0x30, 0xdc, 0xe7, 0xe7, 0x87, 0x19, 0xf6, 0x7b, 0x7, 0x40, 0x86, 0x14, 0x99, 0x1b, 0x20, 0xfd, 0x7e, 0xf3, 0x0, 0x48, 0x9f, 0xaa, 0x1b, 0x10, 0x27, 0xbd, 0x4e, 0xeb, 0x0, 0xc8, 0x89, 0x49, 0xb4, 0xd, 0x98, 0x7a, 0xb9, 0xd2, 0x1e, 0xd4, 0x7, 0xa3, 0x3, 0x70, 0x6e, 0xca, 0xa2, 0x4d, 0xd8, 0x76, 0xbf, 0x52, 0x1a, 0xf6, 0x2a, 0x87, 0x60, 0x9d, 0xd4, 0x46, 0x2e, 0xec, 0xe5, 0xe0, 0xba, 0xd2, 0x2e, 0x77, 0x3b, 0xf5, 0x36, 0x1b, 0xc6, 0xa7, 0x6c, 0x85, 0x32, 0xb0, 0x61, 0xfd, 0x7a, 0xd8, 0x6b, 0x3a, 0x0, 0x7b, 0x66, 0xef, 0x2d, 0x79, 0xb2, 0x31, 0x3, 0x3c, 0xed, 0x14, 0xfb, 0x95, 0xde, 0x79, 0xbd, 0x54, 0x79, 0x36, 0x82, 0x75, 0xfa, 0x1b, 0x86, 0xa8, 0x57, 0xa9, 0xd6, 0xfb, 0x83, 0xde, 0xe8, 0xd9, 0x68, 0xbc, 0xb3, 0x4a, 0x29, 0x49, 0xe2, 0x49, 0xb5, 0x6, 0x9d, 0x46, 0xa5, 0x7d, 0xfd, 0x52, 0xaa, 0x6c, 0x1c, 0x75, 0xa8, 0x8a, 0x5a, 0x64, 0x8e, 0x78, 0xca, 0xa6, 0x8b, 0xfa, 0xa0, 0x76, 0x2d, 0xe2, 0xae, 0x36, 0xbf, 0xc6, 0xce, 0x96, 0x39, 0xab, 0xed, 0x4, 0x68, 0x1d, 0x6c, 0x38, 0xc0, 0x65, 0xc8, 0xcd, 0x96, 0x64, 0x32, 0x99, 0x60, 0x78, 0x9a, 0x9d, 0xea, 0x75, 0xb3, 0x72, 0x5e, 0x61, 0x68, 0xb0, 0x3e, 0x21, 0xec, 0x59, 0xbd, 0x55, 0xa8, 0x56, 0xae, 0xfb, 0x83, 0x4e, 0xaf, 0x72, 0xdd, 0x2d, 0xc, 0x6a, 0x79, 0x70, 0x14, 0x3d, 0xe2, 0x51, 0x5e, 0x98, 0xae, 0xe3, 0xf2, 0x88, 0x9, 0xcd, 0x15, 0x98, 0x41, 0x79, 0x1e, 0x9, 0x1, 0x50, 0x18, 0xe, 0x6a, 0xd7, 0xad, 0x4e, 0xf9, 0x11, 0x4e, 0xda, 0x4d, 0x66, 0xe5, 0xf4, 0xa5, 0x5f, 0x69, 0x9e, 0x5c, 0x3b, 0x9f, 0xa6, 0x30, 0xa8, 0x77, 0xda, 0xfb, 0x71, 0x6c, 0x27, 0xbc, 0x72, 0x30, 0x34, 0xcb, 0x85, 0xae, 0x33, 0x16, 0x7b, 0x0, 0x55, 0x5, 0x1a, 0x11, 0xdb, 0x54, 0xfd, 0x0, 0xfd, 0x4a, 0xa1, 0x57, 0xaa, 0x5d, 0x97, 0x1f, 0x69, 0x8f, 0x83, 0xb9, 0x49, 0xb2, 0xfc, 0xb0, 0x4c, 0x6b, 0x1d, 0x86, 0x14, 0x69, 0xb3, 0xfc, 0x70, 0x27, 0xf5, 0xe6, 0xa0, 0xf2, 0x88, 0x22, 0xe1, 0x60, 0x22, 0xbd, 0xd6, 0x46, 0xdf, 0xea, 0xe5, 0x43, 0x7d, 0xc3, 0xca, 0x46, 0xdf, 0x4a, 0x9d, 0xee, 0x23, 0xdf, 0x42, 0xf4, 0x4b, 0x26, 0x6, 0xf2, 0x3, 0xd, 0xea, 0xad, 0x4a, 0x67, 0xf8, 0x88, 0x66, 0xe4, 0x60, 0x4e, 0xee, 0x2e, 0x3f, 0xe0, 0x79, 0xa5, 0x57, 0x3f, 0x19, 0x5d, 0x97, 0x2a, 0x8f, 0xa9, 0x55, 0xe, 0xbc, 0xce, 0xf3, 0xe5, 0xc0, 0xbb, 0x53, 0xc0, 0xf5, 0x60, 0xc4, 0x9, 0x76, 0xad, 0xfb, 0x3b, 0x7e, 0x12, 0xb6, 0xdb, 0xeb, 0x9c, 0x56, 0x4a, 0x83, 0xeb, 0x52, 0xaf, 0xc2, 0x39, 0xe3, 0xba, 0x57, 0xe9, 0xf, 0x7a, 0xf5, 0x92, 0xc3, 0x25, 0x68, 0x81, 0xcc, 0x15, 0xd1, 0xb9, 0x6c, 0x3b, 0x34, 0xf4, 0x2a, 0xad, 0xce, 0xa0, 0xe2, 0x92, 0x42, 0x26, 0x13, 0xf6, 0xae, 0x55, 0xb8, 0xbc, 0x3e, 0xed, 0x14, 0xaf, 0x2f, 0x3a, 0xbd, 0x46, 0xa5, 0xd7, 0xcf, 0x83, 0xa3, 0xc4, 0x5a, 0x88, 0x2b, 0x97, 0xdd, 0xba, 0xc7, 0x77, 0x9, 0x2e, 0xdd, 0xa5, 0x93, 0xea, 0xe6, 0x63, 0x9e, 0xa5, 0xac, 0xda, 0x29, 0x57, 0x8a, 0xc3, 0x6a, 0x1e, 0x1c, 0xe9, 0xc8, 0x52, 0x74, 0xfa, 0x9b, 0x3c, 0xe5, 0xf2, 0x52, 0x28, 0xb7, 0xea, 0xbd, 0x42, 0xd3, 0x61, 0xc0, 0x76, 0x41, 0x68, 0x9a, 0x7e, 0x65, 0xe0, 0xcf, 0x33, 0xc7, 0xc5, 0xbb, 0xd4, 0x2c, 0xd4, 0xb7, 0x3e, 0x3e, 0x5f, 0x65, 0x6e, 0x9, 0x37, 0xaf, 0x76, 0x5d, 0x2e, 0xbe, 0x60, 0x7a, 0xf7, 0x40, 0x9f, 0x3f, 0xb9, 0x7b, 0xa0, 0x2f, 0x9f, 0xda, 0x5d, 0x14, 0x7, 0xe7, 0xf3, 0xdd, 0xa5, 0xf5, 0x1a, 0xfc, 0xb9, 0xca, 0x54, 0x4, 0xe7, 0xa7, 0xa5, 0x34, 0xff, 0x74, 0xc3, 0x42, 0xc1, 0x3f, 0x37, 0xb9, 0x8f, 0x4a, 0xcd, 0x3a, 0x9b, 0x25, 0xcb, 0x3b, 0x8f, 0xfa, 0x95, 0x52, 0xaf, 0xe2, 0xaf, 0xb9, 0xc9, 0xcb, 0x6e, 0x2a, 0x3a, 0x6f, 0xe6, 0x60, 0x6a, 0x91, 0xa9, 0xc7, 0x6e, 0xaf, 0x73, 0x5e, 0x2f, 0x57, 0x7a, 0xd7, 0xce, 0x48, 0x4d, 0xb0, 0x8a, 0xe8, 0x8a, 0x5a, 0x48, 0x3b, 0xfa, 0x5c, 0x97, 0xfd, 0x13, 0xca, 0x93, 0xd7, 0x7f, 0x22, 0xd8, 0xef, 0x45, 0x29, 0xc2, 0xf, 0xac, 0xff, 0x62, 0xa9, 0x58, 0x7a, 0x6b, 0xfd, 0x17, 0x4b, 0x65, 0xd2, 0x9f, 0xeb, 0xbf, 0x8f, 0x28, 0x81, 0xeb, 0x3f, 0x71, 0x26, 0xfc, 0xef, 0xb8, 0xf8, 0x13, 0x49, 0x1d, 0x3a, 0x6, 0xbc, 0xb3, 0x91, 0xb7, 0x12, 0xf4, 0x65, 0xb5, 0xf5, 0x4d, 0x29, 0xde, 0xd3, 0xdd, 0x8d, 0x27, 0xde, 0x86, 0xb3, 0x6, 0xba, 0x28, 0x6f, 0x40, 0xed, 0xae, 0x80, 0x96, 0x1, 0x3b, 0x57, 0x1c, 0x41, 0x60, 0x3c, 0xea, 0x5e, 0x64, 0x1b, 0x19, 0x4e, 0xf7, 0x60, 0xf4, 0xaf, 0x4a, 0xfd, 0xf8, 0x1e, 0x99, 0xbb, 0x36, 0xdc, 0x75, 0x9b, 0x8b, 0x4, 0x57, 0xa7, 0xfb, 0x8, 0x5a, 0xaf, 0x3, 0x9c, 0xe1, 0xd9, 0x43, 0xc8, 0xb0, 0x1e, 0x4, 0x6d, 0xe3, 0xc7, 0xa0, 0x76, 0xbd, 0xfb, 0x7, 0xcc, 0x5e, 0x9e, 0x8e, 0x55, 0x24, 0x71, 0x5, 0x7f, 0xfd, 0x5, 0xb6, 0xec, 0xd1, 0xc7, 0x3e, 0x8c, 0xcf, 0x1e, 0xdd, 0xf3, 0x79, 0x80, 0x3f, 0x7a, 0x95, 0xb1, 0xde, 0x64, 0xaf, 0xa9, 0xb1, 0x61, 0x2e, 0xbc, 0x68, 0xd4, 0xff, 0xfc, 0xd3, 0x6d, 0xe9, 0x67, 0x4b, 0xf3, 0xf3, 0xcb, 0xd3, 0xf5, 0xff, 0xcb, 0x6f, 0x87, 0x38, 0xe4, 0xff, 0x8b, 0xa7, 0x92, 0x3b, 0xfe, 0xbf, 0xd4, 0xa7, 0xfe, 0xff, 0x90, 0xe2, 0xd7, 0xff, 0xd0, 0x30, 0x68, 0x74, 0x11, 0x1b, 0x23, 0xb, 0xc6, 0xdd, 0x99, 0xc0, 0x82, 0x16, 0x9a, 0xd8, 0x6a, 0xff, 0xef, 0x39, 0x1d, 0x50, 0x3, 0xc9, 0x8c, 0x1c, 0x13, 0xf1, 0x4b, 0x2, 0x68, 0x1e, 0xc4, 0x9c, 0x13, 0x6d, 0xce, 0x3a, 0xff, 0x45, 0x34, 0x52, 0xf7, 0x28, 0x95, 0x38, 0x33, 0xbd, 0xe, 0xc9, 0xb, 0x24, 0x7b, 0x23, 0x64, 0xcf, 0x47, 0x7b, 0xda, 0xa5, 0x7d, 0x2f, 0xf5, 0xc0, 0x23, 0xcc, 0x69, 0xc9, 0x37, 0xc0, 0xac, 0x3c, 0x6f, 0xac, 0xb2, 0xeb, 0xf6, 0x1e, 0x69, 0xf1, 0xd1, 0x57, 0xee, 0x70, 0x2, 0x7f, 0x72, 0x12, 0x2f, 0xed, 0x50, 0xd8, 0xf9, 0xea, 0xdb, 0x50, 0xeb, 0x13, 0x7b, 0x7b, 0x17, 0xbd, 0xfc, 0x75, 0x64, 0x7d, 0x92, 0xcf, 0xd9, 0x32, 0xda, 0x5f, 0xd5, 0x82, 0x53, 0x67, 0x35, 0xe4, 0xc3, 0xdf, 0xf5, 0x1d, 0xdb, 0x7b, 0xbc, 0xa5, 0xf5, 0x1, 0xbf, 0xd, 0x2c, 0xbe, 0xa3, 0xb5, 0x8c, 0x2b, 0xc8, 0x8, 0x6a, 0x6a, 0x20, 0x16, 0xaf, 0xe2, 0x7a, 0x78, 0x63, 0x92, 0x7f, 0x7c, 0x91, 0xbe, 0xe0, 0xd9, 0xd2, 0xbd, 0x7, 0x61, 0xe7, 0x30, 0x6b, 0xb, 0x1a, 0x3d, 0x34, 0x59, 0x3f, 0x67, 0xe5, 0xc5, 0xc2, 0xe2, 0xa2, 0x16, 0xb3, 0xee, 0x5b, 0xe3, 0xf5, 0x1d, 0x74, 0xf4, 0x7f, 0x5e, 0xb6, 0x64, 0xde, 0x68, 0x86, 0xdf, 0xd, 0x94, 0x7, 0x47, 0x59, 0x29, 0x2b, 0x1d, 0x5, 0x0, 0x9c, 0xf6, 0x3b, 0xed, 0xeb, 0xd2, 0x49, 0xd5, 0xe7, 0x2b, 0xb, 0x82, 0xe7, 0x47, 0x4b, 0xfc, 0xb3, 0x8b, 0x18, 0x30, 0xe7, 0x9f, 0xc8, 0x2d, 0xf5, 0xce, 0x70, 0xfa, 0x91, 0x37, 0x2a, 0xa3, 0xa7, 0x63, 0x9c, 0xa3, 0x95, 0x57, 0x8f, 0xad, 0xea, 0xe9, 0xd6, 0xf7, 0x11, 0xc, 0x2d, 0xb2, 0xe6, 0xb3, 0xde, 0x78, 0x6f, 0xc5, 0xb1, 0xee, 0x16, 0xb1, 0xf5, 0x4d, 0x98, 0x1d, 0x86, 0xf, 0xb, 0x6a, 0x7d, 0xd4, 0x68, 0xc, 0xa8, 0xb, 0xad, 0xd9, 0xde, 0x1e, 0x3e, 0x8a, 0xcf, 0x4f, 0xf2, 0xe3, 0xc8, 0x36, 0x6b, 0x52, 0x7b, 0x2c, 0xea, 0xad, 0x1f, 0x6f, 0x65, 0x9, 0x73, 0xec, 0x31, 0x9d, 0x58, 0x1e, 0x8b, 0x7, 0xdc, 0xb0, 0xb3, 0x66, 0xea, 0x27, 0xf4, 0x96, 0x5f, 0xff, 0x51, 0xc6, 0xeb, 0x74, 0x5e, 0xeb, 0x88, 0x89, 0x47, 0xd1, 0xf8, 0x49, 0x77, 0x72, 0x86, 0xfb, 0xbb, 0xc2, 0x9f, 0xbc, 0x58, 0x5b, 0xbb, 0x5, 0x5b, 0x48, 0xa3, 0x9b, 0xc, 0xcd, 0xf3, 0x2d, 0x79, 0xeb, 0x80, 0xd, 0x16, 0x32, 0x36, 0x6, 0x8f, 0xf5, 0x82, 0x1f, 0x4a, 0xa, 0x52, 0x6, 0xfe, 0xd3, 0xb5, 0xeb, 0x7e, 0x6e, 0x9c, 0xb9, 0xf5, 0xab, 0x93, 0x0, 0x8d, 0xbc, 0x35, 0x48, 0x8f, 0xb6, 0xe6, 0x1e, 0xd3, 0x5d, 0xb7, 0xe4, 0x1d, 0xdc, 0x7d, 0xc3, 0x56, 0x7c, 0xc7, 0x83, 0xd7, 0xd, 0xf9, 0xcf, 0xc, 0x3f, 0xa7, 0xad, 0xad, 0x78, 0xf1, 0xbd, 0x5c, 0x26, 0x18, 0xb4, 0xa4, 0x42, 0xac, 0xd, 0x5c, 0x7b, 0x93, 0x7d, 0xb0, 0xf0, 0xce, 0xcc, 0xf7, 0x28, 0x27, 0xfa, 0x67, 0xa9, 0x75, 0x6a, 0x5, 0x9a, 0x7, 0xbf, 0xef, 0x99, 0x13, 0x1c, 0xc1, 0x88, 0x38, 0x9a, 0x66, 0xd, 0xe3, 0x5b, 0x30, 0xfc, 0xb1, 0x29, 0x35, 0x4f, 0x40, 0xe3, 0xcf, 0xf6, 0xb0, 0x1e, 0x43, 0x7, 0xfe, 0x57, 0x74, 0xc7, 0xf, 0x3e, 0x3c, 0x13, 0xcf, 0xd7, 0x35, 0xa2, 0xa0, 0x6b, 0xa5, 0xfc, 0x32, 0xa7, 0x52, 0xf4, 0x68, 0xe5, 0xa7, 0x8d, 0xc5, 0x56, 0x27, 0x8e, 0xf6, 0x49, 0xf5, 0xce, 0x83, 0xad, 0x3c, 0x81, 0x0, 0x6c, 0x27, 0xa, 0xdc, 0x20, 0x6c, 0xef, 0x4a, 0x6e, 0x9b, 0x1c, 0xfc, 0x80, 0x36, 0x57, 0xa2, 0x9f, 0x81, 0x1e, 0xef, 0x5b, 0x9e, 0xbe, 0xfe, 0x5b, 0xc8, 0x2f, 0x5d, 0x0, 0x1e, 0x58, 0xff, 0x49, 0x89, 0xd4, 0x4e, 0xfc, 0x47, 0x26, 0xf6, 0x79, 0xfe, 0xff, 0x43, 0xca, 0x1e, 0xff, 0x9f, 0xb8, 0x2a, 0xe5, 0xd, 0x56, 0x7c, 0xae, 0xb2, 0xf6, 0x99, 0x63, 0x61, 0x27, 0x79, 0xa7, 0x67, 0x7f, 0x59, 0xd0, 0x9c, 0x22, 0x6b, 0xc3, 0x2c, 0xa3, 0xfe, 0x99, 0xf5, 0xa9, 0x2b, 0xae, 0x3, 0xab, 0xc5, 0x9f, 0x3d, 0xd4, 0x7f, 0xcb, 0xb2, 0x23, 0xff, 0xdc, 0x3d, 0xe6, 0x24, 0x6c, 0x7a, 0x45, 0xcc, 0x97, 0xbf, 0x1c, 0xf2, 0xff, 0xa7, 0xb7, 0xfd, 0x3f, 0xb1, 0xb4, 0xf4, 0xe9, 0xff, 0xf9, 0x98, 0x72, 0xc0, 0x37, 0xfa, 0xec, 0xf0, 0xb0, 0xa7, 0xee, 0x54, 0xbe, 0x89, 0x2b, 0x48, 0x60, 0x72, 0x9, 0x70, 0x6c, 0x8, 0xc6, 0xb1, 0x6e, 0xa, 0x55, 0x2f, 0x63, 0x19, 0x70, 0xf2, 0xbc, 0xb9, 0x69, 0xa9, 0x1d, 0xc5, 0xc3, 0x77, 0x13, 0x8c, 0x29, 0xbd, 0x53, 0xbd, 0x67, 0xc4, 0xf0, 0x5d, 0x48, 0xe7, 0x18, 0x31, 0xdc, 0xd2, 0x79, 0xd2, 0x6e, 0xee, 0x7a, 0x17, 0xd7, 0x2d, 0x5f, 0x40, 0xdb, 0xd6, 0xc6, 0xc8, 0x4, 0x64, 0x2, 0x90, 0x8a, 0x34, 0xa4, 0x5b, 0x14, 0xcc, 0x91, 0x61, 0x79, 0x47, 0x11, 0xa1, 0x3c, 0x43, 0x1b, 0x0, 0xe2, 0x63, 0x0, 0x5b, 0x57, 0xf1, 0x1c, 0xa9, 0xfc, 0xc6, 0x3d, 0x91, 0xf, 0x1a, 0xfc, 0x8a, 0x22, 0xd3, 0x8, 0xf0, 0xd2, 0x6d, 0xd0, 0xaf, 0xfc, 0x9c, 0x30, 0xc7, 0xc0, 0xf3, 0x64, 0x11, 0x53, 0x41, 0x26, 0xbf, 0x3b, 0x11, 0x2e, 0x10, 0x30, 0x4c, 0xb4, 0x60, 0x43, 0xa7, 0x23, 0xa4, 0xa8, 0x88, 0x52, 0xc0, 0xd3, 0x47, 0x59, 0x26, 0x36, 0xa8, 0x38, 0x53, 0x8c, 0xbc, 0x31, 0x89, 0xf8, 0x8, 0xe0, 0xe8, 0x9c, 0x9c, 0x64, 0xe9, 0x44, 0x36, 0x19, 0x72, 0x6d, 0x6d, 0x3, 0xfb, 0xb3, 0x4e, 0x17, 0xba, 0x75, 0xe7, 0x30, 0x20, 0xd7, 0xe7, 0x1b, 0xb, 0xef, 0x3c, 0x48, 0x4b, 0xe9, 0xf5, 0xf2, 0x7a, 0x86, 0xa0, 0x6a, 0xcd, 0xbc, 0x17, 0xb1, 0x90, 0xf, 0x4d, 0x19, 0x41, 0x45, 0xc5, 0x3a, 0x2, 0x63, 0x34, 0x21, 0x26, 0x2, 0x50, 0xe7, 0x98, 0x1d, 0x63, 0x52, 0x5c, 0x15, 0x6b, 0x22, 0x6a, 0x10, 0x5d, 0x11, 0xcb, 0x19, 0x8, 0x52, 0x52, 0x62, 0xfd, 0x9, 0xdd, 0x2b, 0xd4, 0x12, 0x92, 0x44, 0x9d, 0xa7, 0x36, 0x4f, 0x1f, 0x66, 0xae, 0x89, 0xe5, 0xe7, 0xa, 0x16, 0x50, 0xcd, 0x83, 0x58, 0x7c, 0x16, 0xf2, 0x16, 0x70, 0x16, 0x9e, 0x60, 0x7f, 0x35, 0x68, 0xb1, 0xaf, 0x6b, 0xd1, 0x3c, 0x48, 0xf8, 0x8c, 0x5a, 0x5e, 0x6f, 0xb5, 0x46, 0x11, 0x9f, 0xad, 0xfb, 0x65, 0x59, 0x86, 0x9f, 0x51, 0x90, 0xae, 0x18, 0x4, 0x33, 0xce, 0x7c, 0x59, 0x14, 0x94, 0x20, 0xc9, 0xb9, 0x5c, 0x37, 0xea, 0xa4, 0x9d, 0x7e, 0xdf, 0xdd, 0x85, 0x47, 0xf5, 0xbf, 0x62, 0xa8, 0x6f, 0x31, 0x1, 0x1c, 0xd0, 0xff, 0xf1, 0x0, 0xfd, 0x1f, 0xff, 0xcc, 0xff, 0xf4, 0x31, 0xe5, 0x19, 0xfa, 0x1f, 0xdd, 0x5b, 0x48, 0xa7, 0x9c, 0x35, 0xc5, 0x26, 0x81, 0x3b, 0x1f, 0x94, 0xbd, 0xbc, 0x50, 0x7f, 0x8f, 0x9, 0x61, 0xdf, 0xae, 0xc0, 0xfb, 0x79, 0xf5, 0xdd, 0x1e, 0x7c, 0x84, 0x3f, 0xdf, 0x6d, 0xeb, 0xa9, 0xee, 0xfa, 0x75, 0x7d, 0xb0, 0x76, 0xd4, 0xef, 0x84, 0x5e, 0x1d, 0xf0, 0xd0, 0xfb, 0x2b, 0x9, 0xdf, 0xfc, 0x7e, 0xd7, 0xfc, 0x1e, 0xb0, 0xd, 0x9f, 0xfc, 0x5a, 0xe7, 0x9a, 0x53, 0x9a, 0x7, 0xbf, 0x1f, 0x85, 0xbd, 0x6b, 0x7b, 0x2d, 0x95, 0x1e, 0x7d, 0x7, 0x47, 0x8e, 0xc7, 0x87, 0xfd, 0xc9, 0x5d, 0xa1, 0x8e, 0x5e, 0x5a, 0xcf, 0xf1, 0x47, 0x7f, 0x3c, 0xcd, 0xaf, 0x2f, 0x68, 0x38, 0xe8, 0xd1, 0x3f, 0xe4, 0x2f, 0xde, 0x98, 0xd0, 0x1e, 0xf7, 0x17, 0x3b, 0xc6, 0xf3, 0x21, 0x4f, 0xf1, 0x4e, 0x8f, 0x82, 0xdc, 0xbb, 0xbb, 0xaf, 0xb7, 0xdc, 0xbc, 0x8f, 0x36, 0xea, 0xed, 0x49, 0xf8, 0x67, 0xa9, 0xa7, 0xaf, 0xe4, 0x7c, 0x17, 0x1f, 0x38, 0xdf, 0x7a, 0xdb, 0xc7, 0xea, 0x79, 0x59, 0x83, 0xbb, 0x1, 0x3c, 0x4f, 0xeb, 0xf6, 0xfb, 0x1d, 0xef, 0xa4, 0xf8, 0x4c, 0xef, 0xef, 0x6b, 0x15, 0xed, 0xbc, 0x9f, 0x97, 0x55, 0xe0, 0x7f, 0x43, 0xff, 0xea, 0x4f, 0x9c, 0xff, 0x5f, 0xe1, 0xf3, 0xf1, 0x97, 0x43, 0xfe, 0x9f, 0x74, 0x3a, 0xbd, 0x33, 0xff, 0xa7, 0x3e, 0xcf, 0xff, 0x7c, 0x48, 0x39, 0x30, 0xff, 0x7f, 0x11, 0x7a, 0x85, 0x5f, 0xc3, 0x2, 0x30, 0xd5, 0x7f, 0xb1, 0x36, 0x92, 0xf6, 0x82, 0x15, 0xb2, 0x22, 0x40, 0x64, 0x27, 0x92, 0x79, 0x62, 0x24, 0xa, 0x20, 0xf0, 0x6e, 0xea, 0x5, 0x3c, 0xc7, 0xa9, 0x5, 0xb0, 0xc5, 0xd3, 0xd7, 0x62, 0x5d, 0x5c, 0x83, 0xaf, 0x93, 0x65, 0x24, 0xb4, 0x37, 0x9d, 0xf0, 0xc6, 0xfd, 0x3b, 0x51, 0x9e, 0x56, 0x97, 0x46, 0x13, 0xf1, 0x94, 0x14, 0xbc, 0x18, 0x7d, 0x9d, 0xaf, 0xca, 0xd3, 0x70, 0x2f, 0xb0, 0x3d, 0x1e, 0x71, 0x6d, 0x39, 0x93, 0xc5, 0x9b, 0x79, 0xb1, 0xc4, 0x1c, 0xfe, 0x1e, 0x9a, 0x60, 0x47, 0xfe, 0xdd, 0x15, 0xa1, 0xf7, 0x87, 0x13, 0xf9, 0xf9, 0xa, 0x45, 0x70, 0x48, 0xfe, 0x93, 0x49, 0x69, 0xdb, 0xff, 0x2b, 0xa5, 0xa5, 0x4f, 0xf9, 0xff, 0x88, 0xf2, 0xcc, 0x33, 0xf9, 0x6f, 0x1f, 0x2e, 0xea, 0x36, 0xf7, 0x42, 0x21, 0xc, 0xc, 0x8, 0x75, 0xe3, 0x28, 0x5f, 0x1c, 0xcf, 0xf7, 0x3f, 0x67, 0xcf, 0xe9, 0x29, 0xf2, 0xff, 0xf2, 0xc8, 0x3f, 0x51, 0xe, 0xc8, 0x7f, 0x32, 0x9e, 0x8a, 0x6d, 0xcd, 0xff, 0x99, 0xf8, 0xe7, 0xf9, 0xdf, 0x8f, 0x29, 0xaf, 0x90, 0xff, 0x77, 0x9, 0x17, 0x7c, 0xa5, 0x3a, 0xd8, 0x9a, 0x37, 0xbd, 0x3c, 0x5a, 0x6f, 0x14, 0x28, 0xe8, 0xa7, 0xee, 0x3d, 0xfd, 0x9, 0xbe, 0xfc, 0x5f, 0x1f, 0xe1, 0x52, 0xd8, 0xb8, 0x85, 0xf0, 0x69, 0x5e, 0x85, 0xd, 0x10, 0x10, 0xe8, 0x58, 0xd8, 0xcd, 0xa8, 0x74, 0xc0, 0xc9, 0xb0, 0xf, 0xe0, 0x19, 0xe, 0x87, 0x7d, 0x28, 0x82, 0x9d, 0xf, 0x8f, 0xfa, 0xd, 0x76, 0x51, 0x3d, 0x3f, 0x2a, 0xf0, 0x91, 0xe0, 0xbd, 0x97, 0xa, 0x85, 0xdf, 0x9, 0xb0, 0xcf, 0x1, 0xe1, 0xa9, 0x6e, 0xf6, 0xc7, 0x1e, 0xf, 0xc4, 0x2, 0x9a, 0x51, 0x15, 0x8f, 0xa3, 0xeb, 0x93, 0x86, 0x51, 0x5f, 0xed, 0xe7, 0x6, 0x8f, 0xed, 0x71, 0x4a, 0x1c, 0x6d, 0x50, 0x72, 0xf4, 0x94, 0x40, 0xb2, 0xf0, 0xbe, 0x85, 0xf5, 0xee, 0xf7, 0x78, 0x7f, 0x67, 0xc1, 0x6e, 0x9b, 0xef, 0xe7, 0x38, 0xd8, 0x6d, 0xeb, 0x1f, 0x11, 0xa4, 0x15, 0xfc, 0x89, 0x5f, 0xa8, 0x97, 0x9e, 0x14, 0xda, 0xb5, 0x3b, 0x50, 0x6e, 0x14, 0x11, 0x4f, 0x13, 0xff, 0x9c, 0xf0, 0xae, 0x3, 0xa8, 0x9e, 0x15, 0xe2, 0xf5, 0xc, 0x5c, 0xef, 0x13, 0xe6, 0xf5, 0xbc, 0xce, 0x7c, 0x48, 0xa8, 0xd7, 0x21, 0x92, 0x1e, 0xd, 0xf7, 0xfa, 0xc, 0xfe, 0xfa, 0x80, 0xf2, 0x14, 0xfb, 0xff, 0xb5, 0x5e, 0xc0, 0x43, 0xeb, 0xff, 0x94, 0x24, 0x6d, 0xdb, 0xff, 0x89, 0xf4, 0x67, 0xfe, 0xf7, 0xf, 0x29, 0x6f, 0xb3, 0xfe, 0x7f, 0x8d, 0xb, 0xee, 0x95, 0x16, 0xff, 0x23, 0x5e, 0xb8, 0x54, 0x32, 0x11, 0x7f, 0x4b, 0x2f, 0x9c, 0x67, 0xf3, 0xfa, 0xf4, 0xd2, 0xcf, 0xfe, 0x7e, 0xaf, 0x2d, 0x3b, 0xf2, 0xef, 0x5c, 0x56, 0xe3, 0xfe, 0xfb, 0x1, 0xfe, 0xff, 0x44, 0x2c, 0xb1, 0x2d, 0xff, 0xe9, 0x64, 0xec, 0xd3, 0xff, 0xf7, 0x21, 0x65, 0xd3, 0xff, 0xef, 0x7e, 0x74, 0xd7, 0x22, 0x7c, 0x72, 0x8, 0x80, 0x73, 0xcd, 0xcc, 0xb, 0x55, 0x80, 0xd3, 0x6c, 0xd8, 0xc6, 0x4e, 0xda, 0xee, 0x17, 0xaf, 0xfe, 0xa1, 0xce, 0x10, 0xec, 0x5a, 0xc7, 0x5b, 0xfd, 0xf3, 0x55, 0xb, 0x54, 0x27, 0x62, 0x54, 0xfc, 0xab, 0x1f, 0x77, 0x7b, 0xda, 0x49, 0xbb, 0xe3, 0xd8, 0xff, 0x96, 0xea, 0xd8, 0xc6, 0xfc, 0xca, 0x1c, 0x57, 0xfb, 0x1c, 0x1d, 0x4a, 0x1, 0xe5, 0x56, 0x3a, 0x78, 0x8b, 0x8f, 0xa8, 0xfc, 0xdc, 0x3, 0x32, 0x4e, 0x2f, 0xfd, 0xa1, 0x43, 0x0, 0x98, 0xb6, 0x8a, 0x7c, 0xc4, 0xe6, 0x9f, 0x42, 0xa5, 0x3f, 0xbe, 0xc9, 0x80, 0xd6, 0xcc, 0xb7, 0xbe, 0x13, 0xbb, 0xba, 0x51, 0xcf, 0xfe, 0x1b, 0x43, 0x79, 0x8e, 0x74, 0x65, 0xf3, 0x5c, 0x8f, 0xcf, 0xbb, 0xf2, 0xa4, 0x40, 0xa8, 0x5d, 0xe0, 0xee, 0x3a, 0x52, 0xd8, 0x4f, 0xf7, 0x13, 0x7, 0xee, 0x9d, 0xe9, 0xdf, 0x93, 0x55, 0x6a, 0x5f, 0x2f, 0x92, 0xc9, 0x64, 0x22, 0x14, 0xa, 0x87, 0xc3, 0x1f, 0x29, 0x52, 0x5e, 0xaa, 0xe7, 0x9f, 0x26, 0x51, 0x7c, 0xa9, 0x38, 0xc5, 0xfa, 0xbd, 0x57, 0x77, 0x7d, 0x61, 0x68, 0x4, 0x93, 0xa8, 0x89, 0x96, 0x26, 0xb6, 0x50, 0x58, 0x44, 0x81, 0xe7, 0x41, 0xd4, 0x25, 0xd9, 0x30, 0xc9, 0xfd, 0x2a, 0xba, 0x10, 0xf7, 0x8f, 0xbf, 0x14, 0xf6, 0x83, 0xe4, 0xf9, 0x6f, 0x2c, 0xa2, 0xce, 0x0, 0x7e, 0x84, 0x90, 0x86, 0xd6, 0xdd, 0xf9, 0xd9, 0xf3, 0xda, 0x67, 0x79, 0x5a, 0xd9, 0x6b, 0xff, 0xbd, 0x7a, 0xd7, 0x77, 0x5d, 0xe, 0xd8, 0x7f, 0xb1, 0x58, 0x7c, 0xc7, 0xfe, 0x8b, 0xc7, 0x3f, 0xed, 0xbf, 0xf, 0x29, 0x4f, 0xd3, 0x8c, 0x9b, 0x56, 0xa2, 0x7b, 0x6d, 0x6d, 0x69, 0x7d, 0x89, 0xe, 0x75, 0x6a, 0xfd, 0x2f, 0x19, 0x82, 0xfc, 0x6f, 0x60, 0x8a, 0xf4, 0x52, 0xc1, 0x55, 0x21, 0x61, 0x19, 0x1e, 0x81, 0x44, 0x3a, 0x25, 0x79, 0x75, 0x90, 0x69, 0x39, 0xb5, 0x78, 0xb2, 0x67, 0x85, 0x27, 0xc2, 0xdb, 0xb9, 0xa1, 0x65, 0xfb, 0x6, 0x9d, 0xc8, 0x57, 0xa0, 0x63, 0x95, 0xff, 0xc7, 0xb1, 0xb1, 0xb6, 0xde, 0x65, 0x4b, 0xda, 0x53, 0xce, 0xaf, 0xd8, 0x91, 0xde, 0x9c, 0xa7, 0x2c, 0x95, 0x7a, 0x9b, 0xd3, 0x96, 0x4a, 0x23, 0xb2, 0x7b, 0x1, 0x95, 0x33, 0xa2, 0xe2, 0x5a, 0x5f, 0xf0, 0xc3, 0xbb, 0x95, 0x8b, 0x8f, 0x51, 0x84, 0x8f, 0x4b, 0x70, 0x86, 0x1e, 0x86, 0x65, 0xbe, 0x95, 0xf1, 0x48, 0x5c, 0x8, 0xbc, 0x83, 0x65, 0x7f, 0xa, 0x24, 0x71, 0x31, 0xe8, 0x66, 0xc4, 0x26, 0xdc, 0x26, 0x4, 0xee, 0x27, 0x63, 0x3d, 0x79, 0x7d, 0xea, 0xfd, 0x7f, 0x68, 0xd9, 0xd1, 0xff, 0xeb, 0x14, 0x51, 0xbe, 0x3f, 0x5f, 0x77, 0x12, 0xec, 0xa0, 0xfe, 0xdf, 0x3d, 0xff, 0x19, 0x4b, 0xc5, 0x3f, 0xf5, 0xff, 0x47, 0x94, 0x77, 0xc9, 0xff, 0xbd, 0x99, 0x6e, 0xf8, 0x5, 0x3a, 0x74, 0xfb, 0x48, 0x17, 0x3f, 0xd1, 0x75, 0xcc, 0x2d, 0x4f, 0xc3, 0x24, 0x16, 0x91, 0x89, 0xea, 0x9c, 0xb1, 0x11, 0x56, 0xb0, 0xb1, 0x99, 0xd2, 0x63, 0x49, 0xcc, 0x39, 0x32, 0xaf, 0xd, 0x42, 0x54, 0xd7, 0xd6, 0x15, 0x8f, 0xe8, 0xbe, 0x6c, 0x68, 0x1a, 0xbc, 0xbf, 0x10, 0x35, 0xd6, 0xb, 0x38, 0xd7, 0x5a, 0x6, 0x47, 0x26, 0x52, 0x30, 0x3d, 0xf2, 0xb6, 0x43, 0x14, 0x4c, 0x37, 0x70, 0xbb, 0xcf, 0x6c, 0x53, 0x75, 0x6c, 0xf6, 0xad, 0x8b, 0xfa, 0xc2, 0xfc, 0x7d, 0x58, 0x83, 0xd4, 0x42, 0xa6, 0x7f, 0xc7, 0x9b, 0x3f, 0x8f, 0x88, 0xe7, 0xe2, 0xbe, 0x2b, 0xff, 0xe1, 0x31, 0xef, 0x9c, 0x57, 0xde, 0x1d, 0xb0, 0xeb, 0x5b, 0x32, 0xbe, 0x76, 0x68, 0xbe, 0xf6, 0x5e, 0xb, 0x8, 0x95, 0x4c, 0xa7, 0xeb, 0xd3, 0x4c, 0xc2, 0xf8, 0x3f, 0x12, 0xdb, 0xbc, 0x64, 0xca, 0x65, 0xd9, 0xdb, 0x9c, 0x43, 0xb, 0xc4, 0x28, 0xad, 0xb7, 0x4f, 0x3a, 0xee, 0x33, 0x68, 0xca, 0x33, 0xbc, 0x40, 0xd7, 0x6, 0x32, 0x31, 0x51, 0xf2, 0x20, 0x96, 0x4, 0x5f, 0x14, 0xb8, 0x12, 0x47, 0xaa, 0xf8, 0x21, 0xda, 0x6b, 0x71, 0xd8, 0xeb, 0x59, 0x67, 0x9b, 0x36, 0x8e, 0x2, 0xff, 0x6c, 0x56, 0xff, 0x2c, 0x1, 0xe5, 0x89, 0xfa, 0xff, 0x55, 0x27, 0xc1, 0xe, 0xf9, 0x7f, 0xe3, 0xb1, 0x9d, 0xf8, 0xcf, 0x44, 0xfc, 0xf3, 0xfc, 0xef, 0x87, 0x94, 0xd7, 0x1f, 0xf0, 0xfa, 0x90, 0x9, 0x61, 0x6b, 0x27, 0x66, 0x8d, 0xef, 0x27, 0x1c, 0xf6, 0xf2, 0x35, 0xfe, 0x31, 0xe1, 0x59, 0x1b, 0xd, 0x3e, 0x35, 0x40, 0x6b, 0xb, 0x8, 0x4, 0x86, 0x68, 0xf9, 0x66, 0xc0, 0x3, 0xb1, 0x59, 0x3b, 0x35, 0x9f, 0x11, 0x94, 0xb5, 0x3, 0xfb, 0x82, 0x68, 0x2c, 0x1f, 0x8e, 0x97, 0x24, 0x67, 0x7b, 0x75, 0x6, 0xb5, 0x4d, 0xe, 0xf6, 0xda, 0x9, 0x4a, 0xa0, 0xe6, 0x5d, 0x26, 0xb0, 0xd1, 0x94, 0x93, 0xb3, 0x4c, 0x41, 0x63, 0x7b, 0x1a, 0x0, 0xe4, 0x64, 0x55, 0xf, 0x2, 0x59, 0xa7, 0x59, 0xf7, 0xde, 0xbe, 0x61, 0x72, 0x33, 0xbf, 0x91, 0x7f, 0xe8, 0xc4, 0x9a, 0x6f, 0x6e, 0x58, 0x5b, 0x66, 0x7e, 0x7f, 0xe0, 0xf6, 0xa9, 0x35, 0xdf, 0x5b, 0x5f, 0x7b, 0x61, 0x95, 0x4c, 0xe9, 0x63, 0x61, 0x69, 0x8e, 0xbd, 0xf2, 0x78, 0x6c, 0xd9, 0x7e, 0xc2, 0x5f, 0x79, 0xea, 0x6d, 0xf7, 0x53, 0xef, 0xa5, 0x7d, 0x27, 0x8e, 0x6d, 0x27, 0xaa, 0xcb, 0xc7, 0xb7, 0xef, 0x1f, 0xae, 0xe6, 0x6b, 0xec, 0xfd, 0xe2, 0xd4, 0x7c, 0x8d, 0xbc, 0x61, 0x80, 0xda, 0xcf, 0x9e, 0x7, 0xff, 0xa7, 0x96, 0x27, 0xda, 0x7f, 0xaf, 0xc8, 0xfe, 0xfe, 0x84, 0xf8, 0x9f, 0x78, 0x66, 0x3b, 0xff, 0x7b, 0x3c, 0xfe, 0x79, 0xfe, 0xff, 0x43, 0xca, 0xdb, 0x7b, 0x4f, 0x5f, 0x6d, 0xeb, 0xbd, 0x61, 0x8e, 0xf7, 0x9f, 0x96, 0xd, 0xfd, 0x67, 0x7f, 0xd6, 0x27, 0x97, 0xa7, 0xca, 0xff, 0x6b, 0x62, 0x0, 0xf, 0xc9, 0x7f, 0x32, 0xb1, 0x2d, 0xff, 0x52, 0xe2, 0xd3, 0xff, 0xf7, 0x31, 0xe5, 0x1d, 0x2, 0xfa, 0x5e, 0xad, 0x0, 0x7e, 0x76, 0xce, 0x38, 0xdf, 0xd2, 0xe9, 0x67, 0x7f, 0x9e, 0x77, 0x2f, 0x3b, 0xf2, 0x2f, 0x82, 0x5a, 0x9c, 0x7f, 0xde, 0x26, 0x3, 0xdc, 0x21, 0xff, 0x4f, 0x2a, 0xbe, 0x73, 0xfe, 0x3f, 0x15, 0xff, 0x94, 0xff, 0xf, 0x29, 0x9b, 0x3b, 0xbb, 0x3b, 0x97, 0xec, 0xbd, 0x4b, 0x2, 0x38, 0xd1, 0xca, 0x9b, 0x38, 0x82, 0x1c, 0x54, 0x2e, 0x9, 0xfb, 0x76, 0xa0, 0x5d, 0x6e, 0xf6, 0x6d, 0x44, 0x3b, 0x95, 0x83, 0xb7, 0xa2, 0xd7, 0x57, 0x8e, 0xbb, 0xa0, 0xee, 0x8d, 0xe3, 0x3b, 0xbb, 0xd4, 0xbe, 0xbe, 0x7d, 0xd, 0xde, 0xa0, 0x6, 0x60, 0x3, 0x47, 0xd8, 0xdd, 0x75, 0xfd, 0x11, 0xda, 0xbd, 0xde, 0x50, 0x54, 0x71, 0x76, 0x61, 0x83, 0xb6, 0x61, 0xc1, 0xce, 0x78, 0x6c, 0x20, 0x3f, 0x88, 0xf9, 0xf1, 0x9d, 0xe6, 0xc7, 0x30, 0xf3, 0xdd, 0xe6, 0xc7, 0x31, 0xef, 0xdb, 0x7d, 0xde, 0xc1, 0xbc, 0x91, 0xd4, 0x39, 0xe2, 0x1e, 0x41, 0xe3, 0x39, 0xe0, 0xdd, 0xd4, 0x7d, 0x7f, 0x3a, 0x8a, 0xfe, 0xc8, 0xd9, 0x3e, 0xc8, 0x7b, 0x4f, 0x80, 0xd8, 0x81, 0xb8, 0x86, 0x8a, 0xc2, 0x1e, 0x1f, 0x79, 0xb7, 0x38, 0xb2, 0xf2, 0xd7, 0x77, 0x17, 0xce, 0x32, 0x6d, 0x6a, 0xb9, 0x9b, 0x25, 0x9b, 0xe0, 0xcc, 0xc2, 0x3c, 0xe2, 0xfb, 0x3a, 0x1a, 0xb1, 0xd0, 0xd1, 0x77, 0x1f, 0x62, 0x42, 0x2d, 0xfe, 0x35, 0x9f, 0x36, 0xd5, 0x6d, 0x32, 0x87, 0xf, 0xf, 0xbf, 0x53, 0x2e, 0xf, 0x8e, 0x32, 0xd9, 0x5c, 0xce, 0xff, 0xdc, 0x52, 0xe9, 0xb5, 0xc, 0xaf, 0x27, 0x58, 0xe5, 0x4d, 0x44, 0xa2, 0x41, 0xac, 0xe1, 0x7, 0x98, 0xa3, 0xd5, 0x35, 0x54, 0xa7, 0xc4, 0xc4, 0xd6, 0x4c, 0x63, 0x20, 0x48, 0x56, 0x28, 0xdc, 0xed, 0xad, 0x4a, 0xa6, 0x53, 0xac, 0x4f, 0x37, 0xfb, 0xc9, 0x37, 0x7a, 0x18, 0x10, 0xf7, 0x3a, 0xed, 0x2, 0x39, 0x47, 0x76, 0x36, 0x81, 0x9c, 0x6d, 0xaf, 0x23, 0xdf, 0x2d, 0x84, 0x7e, 0x82, 0x94, 0xf1, 0xb5, 0x6d, 0xaa, 0xfb, 0xc6, 0x67, 0xcf, 0x4d, 0xef, 0xfe, 0xa4, 0x88, 0xeb, 0xe6, 0xf9, 0xd5, 0x3f, 0xfe, 0xb6, 0x7d, 0x9f, 0x46, 0x5c, 0x8, 0xfa, 0xdd, 0xff, 0xca, 0xc9, 0xcc, 0xb8, 0x5, 0xc1, 0x5f, 0x99, 0x8, 0xaa, 0x7c, 0x74, 0x7c, 0x97, 0xb0, 0xee, 0xd0, 0xe6, 0x46, 0xd0, 0xd, 0x7b, 0x4d, 0xe7, 0x36, 0xf2, 0xcd, 0xdb, 0x47, 0xbf, 0x6f, 0x63, 0x5d, 0xf3, 0xce, 0xa6, 0x1e, 0xd9, 0xad, 0xc9, 0xb3, 0x94, 0x98, 0xbe, 0x8a, 0x1c, 0x63, 0xd8, 0x79, 0xbc, 0x53, 0xdd, 0x24, 0xc4, 0x62, 0xc2, 0x31, 0xb6, 0x75, 0x45, 0x30, 0x42, 0x94, 0x3d, 0xe2, 0xdf, 0xde, 0x57, 0xd7, 0xf5, 0xa8, 0x88, 0x7f, 0xb9, 0xdc, 0x38, 0x6c, 0xf2, 0x52, 0xb9, 0x99, 0x9a, 0x86, 0xbc, 0x96, 0x9b, 0x40, 0xe6, 0x44, 0xa6, 0xb5, 0x8f, 0x3d, 0xb7, 0x79, 0x93, 0xd5, 0x67, 0xfc, 0xb9, 0xaf, 0xfa, 0x1c, 0xad, 0xfe, 0x31, 0x8c, 0xea, 0xa8, 0x77, 0xce, 0xa8, 0x7e, 0x24, 0x42, 0x97, 0x5d, 0x43, 0x15, 0x43, 0x2a, 0x8, 0xe4, 0xf, 0xc4, 0xef, 0xad, 0xef, 0xf3, 0x4f, 0xbc, 0x7, 0xea, 0x80, 0xfd, 0xe7, 0xa4, 0x69, 0x7f, 0xd7, 0xfc, 0xf, 0x89, 0x78, 0x7c, 0x27, 0xff, 0x43, 0x32, 0x1e, 0xfb, 0xb4, 0xff, 0x3e, 0xa2, 0x3c, 0xc7, 0xfe, 0x7b, 0xb7, 0x4, 0x90, 0x1b, 0xcc, 0xf6, 0x86, 0x76, 0x61, 0xf8, 0xc0, 0x35, 0x51, 0xef, 0xb7, 0x47, 0xb8, 0xdd, 0xa3, 0x8f, 0xd8, 0x26, 0xdc, 0x6e, 0xf3, 0xa9, 0x3b, 0x85, 0xbb, 0x70, 0x20, 0x70, 0xb3, 0xd0, 0x35, 0xf7, 0x9e, 0x74, 0xa5, 0x53, 0x50, 0xe5, 0x67, 0x6c, 0x19, 0x6, 0x81, 0xbf, 0x60, 0xd7, 0x70, 0x13, 0xcd, 0x53, 0x36, 0xe, 0x77, 0x37, 0xc8, 0x5a, 0xf5, 0xaa, 0xb8, 0x0, 0xb9, 0xbf, 0x7d, 0x11, 0x91, 0xb3, 0x3f, 0xa7, 0xe1, 0xa9, 0xb3, 0xdf, 0x11, 0x75, 0xee, 0x4d, 0x58, 0xe7, 0x54, 0xd8, 0xc1, 0x56, 0x2e, 0x5e, 0xf, 0x7b, 0xcd, 0x5d, 0x24, 0xcf, 0x34, 0xa6, 0x9e, 0xb8, 0xb9, 0xe7, 0xae, 0x7b, 0xe, 0x6d, 0xec, 0x79, 0x2b, 0xb2, 0x4d, 0x70, 0x66, 0x94, 0x84, 0xe5, 0x75, 0x94, 0xef, 0x1e, 0xc, 0xae, 0xed, 0x12, 0xb4, 0x13, 0xb8, 0xf5, 0x6e, 0xcf, 0x5e, 0x5e, 0x30, 0x9d, 0xaf, 0xdc, 0xc7, 0x5b, 0x1f, 0x25, 0x7b, 0x52, 0x9f, 0x5e, 0x7f, 0x31, 0x91, 0xff, 0xac, 0x4d, 0xc0, 0xc6, 0x99, 0xc3, 0x8c, 0xef, 0xbf, 0xd, 0xe8, 0x34, 0xf4, 0x7e, 0x5b, 0x80, 0x4e, 0x3, 0xff, 0x98, 0x24, 0x97, 0x9f, 0x65, 0x6f, 0x39, 0x64, 0xff, 0x9, 0x4b, 0xfe, 0x5d, 0xed, 0xbf, 0x78, 0x72, 0x3b, 0xfe, 0x2b, 0x96, 0x49, 0x4a, 0x9f, 0xf6, 0xdf, 0x87, 0x94, 0xbf, 0x95, 0xfd, 0xc7, 0x99, 0xed, 0x4d, 0xed, 0x3f, 0x81, 0xf1, 0xe7, 0xd9, 0x7f, 0x6e, 0x8f, 0x3e, 0xd2, 0xfe, 0x73, 0xdb, 0x7c, 0xae, 0xfd, 0xb7, 0x86, 0x3, 0x8f, 0xda, 0x7f, 0x42, 0x25, 0x3c, 0xd1, 0xfe, 0xf3, 0x57, 0x7e, 0x81, 0xfd, 0xe7, 0x7, 0x7f, 0x85, 0xfd, 0x27, 0xd0, 0x7c, 0x80, 0xfd, 0xc7, 0x1b, 0x7a, 0x2f, 0xfb, 0xcf, 0xe7, 0xa3, 0xd8, 0xc1, 0xdb, 0xee, 0xc, 0xa, 0xbd, 0xd1, 0x75, 0xbf, 0x5e, 0x6d, 0x57, 0x7a, 0xd7, 0xe5, 0xca, 0x49, 0x61, 0xd8, 0x1c, 0x14, 0x9a, 0xf5, 0x42, 0x3f, 0xb0, 0xad, 0xe0, 0x1, 0x42, 0xfa, 0x22, 0xb2, 0x1f, 0xd1, 0x3b, 0x9b, 0x9d, 0x3f, 0xc3, 0x34, 0xfc, 0x34, 0x3b, 0xe, 0xcd, 0xff, 0x6f, 0x91, 0x1, 0xfc, 0xc0, 0xfc, 0x1f, 0x8b, 0x49, 0xdb, 0xfe, 0x9f, 0x74, 0xe6, 0x73, 0xfe, 0xff, 0x98, 0xf2, 0xa2, 0xfd, 0xbf, 0xfd, 0xf1, 0x1, 0xcf, 0x4b, 0x93, 0xf0, 0x16, 0xb1, 0x1, 0x6e, 0x64, 0x0, 0xcf, 0xae, 0xf0, 0x86, 0x41, 0x0, 0x9b, 0x5e, 0x91, 0x9d, 0xb4, 0xd, 0x2f, 0x1c, 0x8b, 0xb7, 0x37, 0x7c, 0xf6, 0xe, 0x48, 0x26, 0x9b, 0xcb, 0xbd, 0xc7, 0x80, 0x8, 0x5a, 0x3f, 0xf, 0x7c, 0xfe, 0x7b, 0x94, 0x1d, 0xfd, 0xef, 0x3a, 0x31, 0xbc, 0x3f, 0x5e, 0x1f, 0x3, 0x72, 0x70, 0xfd, 0x97, 0xce, 0xec, 0xac, 0xff, 0x62, 0xa9, 0x4f, 0xfd, 0xff, 0x11, 0xe5, 0x5d, 0xce, 0x7f, 0xbe, 0x32, 0xe9, 0xcc, 0x23, 0xa7, 0x3f, 0x17, 0x2e, 0xad, 0x52, 0x24, 0xc6, 0x1f, 0xa8, 0x64, 0xea, 0xad, 0xa2, 0xc4, 0xb1, 0xc6, 0x8d, 0xe3, 0x95, 0x82, 0x8e, 0x88, 0x4a, 0xa6, 0x4d, 0xf6, 0x76, 0x6d, 0xc2, 0x4e, 0x30, 0x52, 0x15, 0x9f, 0xe9, 0xea, 0xec, 0xf5, 0xe6, 0x81, 0xb, 0x23, 0x16, 0x50, 0x4e, 0x4e, 0x4b, 0xa7, 0xda, 0x56, 0xf6, 0x50, 0xf, 0x3d, 0x19, 0xdf, 0x22, 0xd9, 0xea, 0x8b, 0xca, 0x8e, 0x3b, 0x6b, 0x6b, 0x25, 0xb2, 0xa7, 0x6e, 0xd0, 0x32, 0x72, 0x37, 0xef, 0xe7, 0x4, 0xab, 0x88, 0xae, 0xa8, 0x85, 0x7c, 0x67, 0x5a, 0x4c, 0x42, 0x2c, 0x5, 0x9b, 0x5c, 0xb7, 0xaf, 0x7c, 0xf9, 0x7c, 0x37, 0xe8, 0xf, 0xc8, 0xe6, 0xc9, 0x6f, 0xf7, 0x5b, 0xa3, 0x51, 0xe1, 0xa, 0x99, 0x58, 0x9f, 0x90, 0x3c, 0xc0, 0xba, 0x86, 0x34, 0xe2, 0x41, 0x6a, 0x10, 0xeb, 0x16, 0xd2, 0xa1, 0x2e, 0xfb, 0xaa, 0xdb, 0x86, 0x4a, 0xa0, 0x62, 0xd8, 0xe6, 0x14, 0xeb, 0xd3, 0xcd, 0xab, 0xef, 0xb8, 0xc9, 0x90, 0x7, 0x13, 0xa8, 0x7a, 0x59, 0xa1, 0x15, 0xa4, 0x22, 0xcb, 0x7, 0xed, 0x55, 0xb2, 0x4c, 0x1b, 0x85, 0x1e, 0x1b, 0x51, 0x7e, 0x30, 0xd6, 0x25, 0x9a, 0xff, 0x8, 0x5a, 0xde, 0x6d, 0x55, 0xdf, 0x1d, 0xcc, 0xad, 0xde, 0xfb, 0x93, 0xe5, 0x40, 0x45, 0x31, 0xf3, 0x20, 0x9f, 0x92, 0x24, 0x37, 0xa4, 0xf0, 0xb, 0xa0, 0xc8, 0x2, 0xb, 0xc, 0xd9, 0x3a, 0x10, 0x9b, 0x44, 0xd7, 0x18, 0xae, 0x5, 0x34, 0x31, 0xa3, 0xda, 0x57, 0x89, 0xfb, 0x89, 0x81, 0xa1, 0x42, 0x19, 0xcd, 0x88, 0xaa, 0x78, 0x8b, 0x66, 0xbe, 0x79, 0xed, 0xbb, 0x4e, 0x90, 0xb7, 0xa0, 0x12, 0x19, 0xaa, 0x3c, 0x9d, 0x4f, 0x4a, 0x92, 0x4, 0xcf, 0x42, 0xdb, 0x9a, 0xe5, 0x3d, 0x77, 0xe9, 0x1c, 0xe9, 0xbe, 0x9b, 0xa, 0x79, 0xc4, 0x40, 0x1e, 0x4, 0x84, 0x11, 0xf8, 0x56, 0xbc, 0x50, 0xd5, 0x5e, 0x19, 0xeb, 0xb0, 0xc1, 0x46, 0xeb, 0x50, 0x4, 0x67, 0x5d, 0xb6, 0x9e, 0x3, 0xb6, 0x3d, 0xfb, 0x9e, 0x98, 0x38, 0x4, 0x7a, 0xdc, 0xc6, 0x6b, 0x6c, 0xdc, 0x5f, 0xe8, 0x76, 0xca, 0xbd, 0x14, 0x31, 0x60, 0x9d, 0x28, 0x90, 0xf8, 0xb8, 0x48, 0xc1, 0x34, 0x80, 0x8d, 0x38, 0xe3, 0x99, 0x6a, 0x1e, 0xbc, 0xfe, 0x52, 0x45, 0x1f, 0x46, 0xff, 0xcd, 0x91, 0x92, 0xb6, 0xf1, 0x66, 0x66, 0x22, 0xca, 0xbe, 0x6c, 0x1e, 0xa4, 0x7c, 0x8f, 0xc7, 0x50, 0x9e, 0x93, 0xc9, 0x24, 0xf, 0x62, 0xf4, 0xdf, 0x67, 0xb9, 0xf8, 0x84, 0xf9, 0xff, 0x67, 0xdc, 0xff, 0x12, 0xcf, 0x7c, 0xe6, 0xff, 0xf9, 0x90, 0xf2, 0xf6, 0xe7, 0x3f, 0x5e, 0x39, 0xf9, 0x7, 0x9e, 0xfe, 0x60, 0x82, 0xdf, 0x77, 0xf4, 0x6e, 0xd0, 0xfc, 0xbe, 0x7e, 0xbf, 0xe7, 0x8, 0x87, 0xab, 0xc8, 0x82, 0xc1, 0xd9, 0xdb, 0x52, 0x70, 0x8e, 0x9b, 0x9f, 0xfd, 0x7d, 0xde, 0xbb, 0x3c, 0x45, 0xfe, 0xdf, 0xf9, 0xfe, 0x97, 0x54, 0x3c, 0xb5, 0x1d, 0xff, 0x9d, 0x49, 0x26, 0x3f, 0xe3, 0xbf, 0x3f, 0xa4, 0xbc, 0xfb, 0x85, 0x2e, 0xaf, 0x4e, 0x40, 0xb9, 0xe1, 0x84, 0xf0, 0xec, 0x8d, 0x37, 0xba, 0xd0, 0xc5, 0x4f, 0xdd, 0x7b, 0xee, 0x7, 0xf9, 0xac, 0xf2, 0x8f, 0xd8, 0xa, 0xda, 0x5c, 0xc4, 0x3c, 0x69, 0x17, 0x68, 0x6b, 0xdd, 0x10, 0xb4, 0x1, 0xe4, 0xe9, 0xcb, 0x3, 0x7b, 0x3f, 0x5b, 0xf5, 0x9e, 0xb1, 0xed, 0xb3, 0x5, 0xf9, 0x82, 0x1d, 0x1f, 0xdf, 0x92, 0xe0, 0xc0, 0x66, 0x8f, 0x7b, 0xf3, 0x2c, 0xf7, 0xf0, 0x79, 0xd7, 0xcc, 0x7a, 0xea, 0x6f, 0xbd, 0xf8, 0xf4, 0x5d, 0x34, 0xbb, 0xe7, 0xc4, 0x7f, 0xaf, 0x52, 0xad, 0xf7, 0x7, 0xbd, 0xd1, 0x75, 0x6d, 0x30, 0xe8, 0x3a, 0x67, 0x5, 0x7d, 0xd5, 0x9c, 0x8d, 0x97, 0xed, 0xab, 0x61, 0x0, 0xf0, 0x1d, 0x6b, 0xc, 0xb8, 0x1f, 0xe6, 0xa5, 0x52, 0xb6, 0x59, 0x78, 0xd8, 0xfe, 0x7a, 0x7e, 0xf4, 0xde, 0x1f, 0x4a, 0x21, 0xe0, 0x5b, 0x18, 0x5, 0xbf, 0x8d, 0xed, 0xd9, 0xc, 0x72, 0x96, 0x74, 0x50, 0x57, 0xc0, 0xaf, 0xfe, 0xbc, 0x82, 0xc1, 0x2b, 0xe0, 0xaf, 0x4f, 0xbb, 0x5f, 0x66, 0x97, 0x4f, 0x9f, 0x72, 0xb7, 0x8d, 0xc7, 0xd3, 0x3b, 0xab, 0xe0, 0x0, 0x7c, 0x4f, 0xc, 0x76, 0x7a, 0x7c, 0x7d, 0xb4, 0x3f, 0xf2, 0x29, 0xa0, 0xc5, 0x83, 0xfb, 0x63, 0x1, 0xcc, 0x18, 0xd4, 0xd2, 0xce, 0xdb, 0x3d, 0x5b, 0x69, 0x87, 0xbb, 0xfa, 0xd6, 0x31, 0x50, 0x87, 0x3b, 0xfd, 0xca, 0x8d, 0xbc, 0x3, 0x21, 0x57, 0x1e, 0xcf, 0xbd, 0x7f, 0xd0, 0x95, 0xd7, 0xd4, 0xfb, 0x85, 0x5d, 0x79, 0x4d, 0xbc, 0xc7, 0xc5, 0x40, 0x6f, 0x27, 0xaf, 0xcf, 0xbd, 0x41, 0x28, 0x48, 0xa2, 0xdf, 0xf3, 0xfe, 0x20, 0xaf, 0x63, 0x2f, 0xbe, 0x36, 0x28, 0x18, 0xc3, 0xb3, 0x6e, 0xb, 0x3a, 0x8c, 0xe2, 0x7d, 0x2e, 0x9, 0x7a, 0x12, 0xe9, 0x1f, 0x72, 0x37, 0xd0, 0x1e, 0x4a, 0x1e, 0xbd, 0x12, 0xe8, 0x67, 0x5b, 0xcb, 0xff, 0x7e, 0xe5, 0x29, 0xeb, 0xbf, 0xf7, 0xbe, 0xff, 0x27, 0x29, 0xa5, 0xb6, 0xd7, 0x7f, 0xa9, 0xcc, 0x67, 0xfe, 0x8f, 0xf, 0x29, 0xef, 0x70, 0xfe, 0xff, 0x95, 0x2b, 0xbe, 0xc7, 0x2e, 0xf4, 0x11, 0x36, 0xe9, 0x9b, 0x6d, 0x69, 0xbb, 0x94, 0xfe, 0xec, 0x8f, 0xf0, 0x13, 0xcb, 0x8e, 0xfc, 0xdb, 0x38, 0x6a, 0xe3, 0xb7, 0x39, 0xf7, 0xef, 0x96, 0xc3, 0xf2, 0xbf, 0x1d, 0xff, 0x93, 0xcc, 0xc4, 0x3e, 0xe3, 0x7f, 0x3e, 0xa4, 0xbc, 0xcb, 0xfe, 0xaf, 0x8d, 0x5f, 0xb9, 0xf3, 0xb, 0xd, 0x23, 0xc2, 0x56, 0x6, 0xde, 0xbe, 0x2f, 0x34, 0xc, 0x86, 0x1f, 0xfc, 0x6, 0x6a, 0xeb, 0x3d, 0x23, 0xd3, 0xd6, 0x35, 0x66, 0xaf, 0xfd, 0x6, 0xc, 0x93, 0x28, 0xfc, 0x91, 0x30, 0x44, 0xa7, 0xf, 0xd8, 0x0, 0xbf, 0x89, 0x5d, 0x46, 0xfe, 0xf8, 0x77, 0x56, 0xe1, 0xf, 0x6f, 0xf, 0x90, 0x67, 0xda, 0xfd, 0x4d, 0xe4, 0xd, 0xf9, 0xd9, 0x1f, 0xe0, 0x27, 0x97, 0x3d, 0xf2, 0xff, 0xaa, 0x7c, 0xaf, 0xdb, 0xe5, 0x90, 0xff, 0x37, 0x95, 0x8c, 0x6f, 0xc9, 0x7f, 0x2a, 0x26, 0x7d, 0xde, 0xff, 0xfd, 0x21, 0xe5, 0x63, 0xf2, 0xbf, 0xbe, 0x58, 0x21, 0x6c, 0x4d, 0xd8, 0x36, 0xde, 0xe3, 0xf8, 0x7d, 0xb1, 0x53, 0x75, 0x9f, 0xb9, 0xb0, 0xcf, 0xb3, 0xea, 0xdc, 0x7f, 0xf3, 0x34, 0x9f, 0xaa, 0xef, 0xb2, 0x9c, 0x5d, 0x6f, 0xaa, 0x8d, 0xf, 0xf9, 0x51, 0xbd, 0x1a, 0xcf, 0xf0, 0xa0, 0x7a, 0x30, 0xc1, 0xbe, 0xd3, 0x3d, 0xe, 0x4c, 0x2f, 0xc3, 0xd9, 0xc7, 0x7a, 0x2d, 0x5, 0x5b, 0x6c, 0x16, 0xee, 0xaf, 0xa4, 0x9b, 0xbe, 0xca, 0x35, 0xa1, 0x3b, 0x9, 0xdd, 0xfe, 0x26, 0x4, 0xaf, 0x53, 0x46, 0xf5, 0xf7, 0x91, 0xfe, 0xbc, 0xc, 0xaf, 0xaf, 0x4c, 0x27, 0x5b, 0xea, 0xb4, 0x4f, 0xea, 0xd5, 0xed, 0x3, 0xb, 0x1e, 0x18, 0xf7, 0x2e, 0xda, 0x38, 0xea, 0xce, 0xb3, 0x1, 0x18, 0x2a, 0xed, 0x42, 0xb1, 0x59, 0xb9, 0xae, 0x15, 0x7a, 0xc5, 0x4e, 0xef, 0xba, 0x5f, 0x2a, 0xb4, 0xaf, 0x3b, 0xed, 0xeb, 0xee, 0xb0, 0x1f, 0x88, 0xf0, 0x28, 0x76, 0x14, 0x80, 0xa3, 0x50, 0x6e, 0xd5, 0xdb, 0xec, 0x7b, 0x55, 0x7a, 0x5b, 0xa7, 0x1e, 0xd6, 0x80, 0x2f, 0x4c, 0x26, 0xef, 0xa2, 0x79, 0xc3, 0x4c, 0xb8, 0xcc, 0xec, 0x3d, 0xe4, 0x91, 0xd, 0x1e, 0x33, 0xcf, 0x13, 0xbb, 0xf3, 0xce, 0x87, 0xdb, 0x49, 0xa1, 0x19, 0x9e, 0xa3, 0xd5, 0xe3, 0xd, 0x6c, 0x56, 0xf0, 0x70, 0xfb, 0x1f, 0x7, 0xa0, 0x35, 0x4c, 0xbc, 0x80, 0x16, 0x3a, 0x8c, 0xde, 0xa9, 0x78, 0x3d, 0x47, 0xab, 0x88, 0x81, 0xb4, 0xa0, 0xa6, 0xf6, 0x55, 0xd9, 0xe7, 0x2a, 0xdc, 0xbe, 0x32, 0xe8, 0xeb, 0xde, 0xb, 0x25, 0x3, 0x1c, 0xf0, 0x32, 0xc, 0x2b, 0x64, 0xa9, 0xab, 0x4, 0x2a, 0x8f, 0x13, 0x2e, 0xc3, 0xa8, 0xc8, 0x8f, 0x13, 0xe8, 0x3, 0xdf, 0x7c, 0xf3, 0x88, 0xc3, 0xdf, 0xa0, 0xf2, 0xe3, 0xed, 0xf0, 0x8, 0xa9, 0xc7, 0x3d, 0xe9, 0xbb, 0xac, 0xf2, 0x4a, 0x3f, 0xf6, 0x5a, 0xb1, 0x1c, 0xe0, 0x98, 0xd7, 0x7b, 0xe8, 0x37, 0x75, 0x18, 0xb6, 0x90, 0x46, 0x37, 0x55, 0x62, 0xd8, 0xaf, 0x83, 0x1b, 0x1b, 0xec, 0x4, 0xbc, 0x9b, 0x25, 0xd6, 0x34, 0x3d, 0x91, 0x17, 0x3f, 0x8e, 0xf0, 0xfd, 0xc, 0xbe, 0x26, 0x3f, 0xb8, 0xce, 0x1b, 0xf2, 0xf7, 0x63, 0xdc, 0xfd, 0xfa, 0xa1, 0xf0, 0xdd, 0x50, 0x75, 0x78, 0x3c, 0x76, 0x84, 0x66, 0x3d, 0xc, 0x1b, 0xaf, 0x76, 0x64, 0x26, 0x48, 0x62, 0xe, 0x67, 0xbc, 0xb6, 0xf1, 0x7, 0xec, 0xb6, 0xd8, 0xf8, 0x1d, 0xf7, 0x59, 0x6c, 0xfc, 0x3f, 0x27, 0xb3, 0xf5, 0x9e, 0xf5, 0xdf, 0xab, 0xf2, 0x3d, 0x6f, 0x97, 0x43, 0xfe, 0x9f, 0x74, 0x6c, 0x3b, 0xfe, 0x27, 0x95, 0xc9, 0x7c, 0xc6, 0xff, 0x7c, 0x48, 0x79, 0xfb, 0xf8, 0xbf, 0x17, 0xaf, 0xf5, 0xde, 0x30, 0xef, 0x33, 0xdd, 0x8d, 0x15, 0x7c, 0x34, 0x5d, 0x73, 0x8, 0x6c, 0xcf, 0x8, 0xdb, 0xb0, 0xce, 0xeb, 0x6, 0x5a, 0x75, 0x91, 0xb6, 0x7, 0xc5, 0xf6, 0x22, 0xe0, 0xf9, 0xc9, 0xa6, 0x3f, 0xfe, 0xfb, 0xef, 0x93, 0xff, 0xb7, 0x38, 0xf7, 0xe9, 0x96, 0x83, 0xfe, 0xdf, 0xd8, 0xf6, 0xf9, 0x9f, 0x54, 0x2c, 0xf6, 0xe9, 0xff, 0xf9, 0x90, 0xf2, 0xe, 0xfb, 0x3f, 0x2f, 0x56, 0x0, 0x3f, 0x3b, 0xef, 0xb3, 0x8d, 0xff, 0xe6, 0x93, 0xf5, 0x3b, 0x14, 0x47, 0xfe, 0x23, 0x33, 0xa4, 0x6a, 0x78, 0xaa, 0x13, 0x13, 0xbd, 0x7d, 0x1b, 0x87, 0xe4, 0x3f, 0x15, 0xdb, 0xde, 0xff, 0x8d, 0xa7, 0x92, 0x9f, 0xf1, 0xff, 0x1f, 0x52, 0xbe, 0x80, 0x2e, 0xb4, 0x2c, 0x64, 0xea, 0x14, 0x58, 0x4, 0x8, 0xe, 0x0, 0xcb, 0x19, 0xd2, 0xc1, 0xd8, 0xc6, 0xaa, 0x82, 0xf5, 0x29, 0x30, 0xa0, 0x3c, 0x87, 0x53, 0x44, 0x23, 0xa1, 0x2f, 0x60, 0x30, 0xc3, 0x14, 0x50, 0x9b, 0xef, 0xa0, 0x50, 0x40, 0x67, 0x48, 0x55, 0xc1, 0x54, 0x25, 0x63, 0x11, 0x2e, 0x8b, 0xf5, 0xe9, 0x77, 0x60, 0x22, 0x15, 0x5a, 0x78, 0x81, 0xf8, 0x12, 0xc3, 0xf7, 0x1c, 0xea, 0x4a, 0xe8, 0xb, 0xd0, 0xd1, 0x94, 0x5b, 0xd0, 0xe0, 0x57, 0xc3, 0x44, 0x13, 0x7c, 0x8f, 0x14, 0x61, 0x7b, 0xff, 0xff, 0xbe, 0x46, 0x40, 0x47, 0x57, 0x57, 0x80, 0xe8, 0x1c, 0x92, 0x91, 0x4, 0xc, 0x64, 0x2, 0x15, 0xeb, 0x28, 0x12, 0x8a, 0x94, 0xfb, 0xd7, 0x7d, 0x8b, 0x98, 0x28, 0xf4, 0x5, 0x88, 0x3b, 0x81, 0xc1, 0x79, 0xa9, 0xf, 0x14, 0x6c, 0xd2, 0x50, 0x64, 0x8a, 0xad, 0x28, 0xff, 0xbf, 0x20, 0x3f, 0x14, 0x19, 0x3f, 0x98, 0x51, 0xfe, 0x7f, 0xf7, 0xc1, 0x6c, 0x1a, 0x65, 0xff, 0x73, 0x7f, 0xd2, 0x85, 0x1e, 0x5d, 0x23, 0x1a, 0x43, 0x79, 0x6e, 0x1b, 0xe2, 0x90, 0x5d, 0xe8, 0x5b, 0x84, 0x2e, 0x8d, 0xd0, 0xb7, 0xc8, 0x18, 0xce, 0x43, 0xdf, 0x22, 0x96, 0x66, 0x84, 0xbe, 0xfd, 0xbf, 0xd0, 0x17, 0x70, 0xe, 0x4d, 0x4c, 0x6c, 0xa, 0xea, 0xe5, 0xa, 0xd, 0x45, 0xc, 0x93, 0xdc, 0x22, 0xd9, 0xa, 0x45, 0xb0, 0x82, 0x60, 0x54, 0xd4, 0x33, 0xc9, 0xed, 0x3f, 0x51, 0x7b, 0x38, 0xf2, 0x5f, 0xea, 0xb4, 0x7, 0xbd, 0x7a, 0x71, 0x38, 0xa8, 0xb7, 0xab, 0x11, 0x4d, 0x79, 0xdb, 0x36, 0xe, 0xc8, 0x7f, 0x4c, 0xca, 0x6c, 0xcf, 0xff, 0xf1, 0x74, 0x32, 0xf1, 0x29, 0xff, 0x1f, 0x51, 0x98, 0x14, 0xe8, 0x96, 0x89, 0xc7, 0xb6, 0xc5, 0x64, 0xdd, 0x22, 0xa0, 0x86, 0x54, 0xd, 0x94, 0x66, 0xd0, 0xb4, 0xc0, 0x84, 0x98, 0xee, 0x7e, 0x6b, 0xa8, 0xcb, 0x6f, 0x34, 0x5, 0x13, 0xa2, 0xaa, 0x64, 0x9, 0x7e, 0x17, 0x8f, 0xb9, 0xb7, 0xd5, 0x3, 0x9e, 0xda, 0x58, 0x41, 0x7f, 0xfc, 0xea, 0x9e, 0x4b, 0x9c, 0x62, 0x6b, 0x66, 0x8f, 0x23, 0x32, 0xd1, 0xa2, 0xb, 0x6d, 0x9, 0x4d, 0x14, 0x75, 0x98, 0x6d, 0xac, 0x92, 0x71, 0x54, 0x5c, 0x7a, 0xba, 0xcd, 0x78, 0x5f, 0x19, 0x5, 0x2a, 0x82, 0xa6, 0xe, 0x66, 0x64, 0xc9, 0x7e, 0x68, 0x70, 0x8e, 0x80, 0x4c, 0x14, 0xe4, 0x6b, 0x8b, 0xe8, 0x91, 0x50, 0xc8, 0x47, 0x39, 0x32, 0x69, 0x28, 0x34, 0x98, 0x41, 0x7d, 0x4e, 0xc1, 0x2, 0x99, 0x2b, 0xa0, 0xd9, 0xf2, 0x8c, 0x1, 0x43, 0x55, 0x5d, 0x83, 0x21, 0x93, 0x82, 0xe5, 0x8c, 0x0, 0x6a, 0x8f, 0x35, 0x6c, 0x59, 0x48, 0x1, 0x86, 0xad, 0xaa, 0x5e, 0xbc, 0xda, 0xde, 0xbe, 0x47, 0x42, 0xa1, 0x30, 0xf8, 0xbd, 0xb, 0x6d, 0x15, 0x94, 0x1e, 0xa0, 0x39, 0x27, 0x4b, 0x3a, 0xc7, 0xe0, 0x5f, 0x6, 0xb4, 0x55, 0xf9, 0x1, 0x9a, 0x81, 0x1d, 0x76, 0x5f, 0x7e, 0x65, 0xa0, 0x4d, 0x5b, 0x86, 0xa0, 0xae, 0xeb, 0x44, 0x46, 0xba, 0x85, 0x41, 0xb, 0x9b, 0x26, 0x6, 0xff, 0x52, 0x6d, 0x19, 0x62, 0x2d, 0x10, 0x5a, 0xbc, 0xe2, 0xb0, 0x7d, 0xb, 0x2d, 0x90, 0xe, 0xa, 0xa6, 0x4e, 0x2c, 0xb, 0xfc, 0xab, 0x60, 0xca, 0x16, 0x96, 0xfb, 0x3a, 0x59, 0x6a, 0x50, 0xf, 0x84, 0xdd, 0xa8, 0xc1, 0x51, 0x14, 0x54, 0x74, 0xf, 0x5a, 0xe0, 0x5f, 0x8a, 0x9, 0x91, 0x49, 0x82, 0xa1, 0x9c, 0x77, 0xa2, 0x49, 0xa8, 0x4f, 0x4f, 0x6d, 0x1d, 0x8c, 0xec, 0xe0, 0xba, 0x23, 0x5b, 0x77, 0xaa, 0x7c, 0xfd, 0x27, 0x6a, 0xbc, 0xcf, 0xe2, 0x2f, 0x8e, 0x48, 0xf6, 0x2a, 0x85, 0x72, 0xab, 0xf2, 0xe6, 0x9a, 0x5f, 0x94, 0xc7, 0xf5, 0x7f, 0x22, 0x96, 0x49, 0x24, 0xb7, 0xf4, 0x7f, 0x2c, 0x9d, 0xf9, 0x5c, 0xff, 0x7d, 0x48, 0xf9, 0xb2, 0x4f, 0xdf, 0x7f, 0xf9, 0x2, 0xea, 0xba, 0x65, 0x12, 0xc5, 0x96, 0x99, 0xc2, 0x65, 0xfa, 0x15, 0x53, 0xf0, 0x3b, 0xab, 0x1d, 0xa8, 0x15, 0xe6, 0xf6, 0x18, 0x99, 0x3a, 0xb2, 0x10, 0x8d, 0xb2, 0xb5, 0xc4, 0x57, 0x20, 0x73, 0x94, 0x58, 0xa7, 0x16, 0x54, 0x55, 0xea, 0xce, 0x18, 0x2, 0x36, 0x1f, 0x75, 0xa6, 0x84, 0x88, 0x83, 0x1, 0x13, 0x77, 0x72, 0xf8, 0xa, 0xb0, 0xe, 0x20, 0x68, 0x78, 0xe8, 0x80, 0xac, 0xda, 0xfc, 0x7e, 0x6c, 0x50, 0xb2, 0x4d, 0x13, 0xe9, 0x96, 0xba, 0x2, 0x16, 0xa3, 0x45, 0x34, 0xe0, 0x19, 0xa3, 0xce, 0x8c, 0xb4, 0x88, 0x45, 0x92, 0x11, 0x89, 0x59, 0xa1, 0xfc, 0x6, 0x6e, 0x70, 0x81, 0x54, 0x99, 0x68, 0x88, 0x69, 0xf7, 0xdf, 0xd7, 0x53, 0xc1, 0x1f, 0xbf, 0x6, 0x4d, 0x3c, 0xfb, 0xd4, 0xff, 0x97, 0x2f, 0xa0, 0x6b, 0x22, 0x36, 0x51, 0x60, 0x8a, 0x2d, 0x44, 0xd9, 0x84, 0xb0, 0x4b, 0x20, 0x88, 0x45, 0xb2, 0xc7, 0xc2, 0x9a, 0x2d, 0x22, 0xb, 0x82, 0x42, 0xb7, 0x4e, 0xdd, 0x94, 0x7, 0x9b, 0x0, 0x75, 0xe1, 0xbe, 0x17, 0x13, 0x18, 0x51, 0x55, 0x64, 0x2, 0xec, 0xaf, 0xca, 0xc6, 0x52, 0xb6, 0x54, 0x50, 0x6a, 0xd6, 0x39, 0xd2, 0x50, 0xd8, 0x21, 0xad, 0x59, 0x7, 0xf1, 0x48, 0x36, 0x22, 0x1d, 0x73, 0x9a, 0x1a, 0x3a, 0x59, 0xea, 0xa0, 0x4e, 0xa9, 0x2d, 0x48, 0x1a, 0xac, 0x47, 0x45, 0x21, 0x88, 0xea, 0xbf, 0x58, 0xfc, 0xda, 0x73, 0x41, 0x92, 0xaf, 0x79, 0xbe, 0x99, 0x81, 0xad, 0x15, 0xb0, 0xd, 0x85, 0xad, 0xe3, 0x9d, 0xb1, 0x62, 0x4d, 0x45, 0x72, 0xc7, 0x7c, 0xfb, 0x23, 0x16, 0xc9, 0x45, 0x92, 0xc7, 0x11, 0xd0, 0x43, 0x13, 0x64, 0xf2, 0xb1, 0xe3, 0x49, 0x8, 0x40, 0x32, 0x99, 0x4b, 0x3f, 0x61, 0x86, 0xe7, 0x95, 0x69, 0x94, 0xd5, 0xfe, 0x2a, 0xc6, 0xaf, 0x8f, 0x2c, 0xdb, 0x8, 0xfc, 0xae, 0xa1, 0xd0, 0x88, 0xd8, 0x40, 0x86, 0x3a, 0xb0, 0x29, 0x2, 0x50, 0x5f, 0x1, 0x8b, 0x10, 0x95, 0x4f, 0xc7, 0xd4, 0x5, 0xca, 0xae, 0xb9, 0x20, 0x54, 0xd7, 0xc5, 0xe7, 0xe7, 0xd6, 0xc6, 0x77, 0xb0, 0x44, 0x1c, 0xee, 0x77, 0xd, 0xeb, 0x98, 0x8d, 0xdb, 0x21, 0xe6, 0x74, 0xeb, 0x7d, 0x5, 0x52, 0x24, 0x9e, 0x8a, 0x48, 0x7b, 0xda, 0x1, 0x90, 0x2, 0x6b, 0x86, 0x80, 0x82, 0x16, 0x51, 0xb, 0x51, 0xb, 0x20, 0x7d, 0x11, 0x9, 0xdd, 0xdc, 0xdc, 0x8c, 0x21, 0x9d, 0x85, 0xbe, 0x80, 0xbe, 0xc5, 0x86, 0xd9, 0x45, 0x16, 0x72, 0xff, 0x0, 0x94, 0x3f, 0xf, 0x87, 0x17, 0x5a, 0x58, 0x31, 0xf1, 0x2, 0x99, 0xbf, 0xe9, 0x44, 0x67, 0xab, 0x96, 0xa, 0xff, 0xba, 0x1, 0x9f, 0x7e, 0xd, 0xb, 0x15, 0x85, 0xe8, 0x2e, 0x1f, 0x0, 0x67, 0x8f, 0x87, 0xb5, 0x29, 0x84, 0x91, 0xb, 0x12, 0x37, 0xd2, 0x66, 0x48, 0x70, 0x69, 0x28, 0x74, 0x82, 0x4d, 0xea, 0x9, 0x99, 0x90, 0x4e, 0xc6, 0x25, 0x4f, 0x91, 0xd0, 0x2f, 0xe, 0xd4, 0xd7, 0xef, 0xc, 0xa1, 0xe, 0xb0, 0x8e, 0x2d, 0xc, 0x55, 0xfc, 0x80, 0x38, 0xb3, 0xad, 0x3b, 0xcb, 0x2a, 0xf3, 0xb7, 0x9c, 0x94, 0xb2, 0xb3, 0x9b, 0xe5, 0xca, 0x1b, 0x7f, 0x2b, 0x98, 0x8e, 0x59, 0x69, 0x6b, 0xb0, 0x29, 0xb6, 0x80, 0xac, 0xb2, 0xe5, 0xdc, 0x21, 0x76, 0x9, 0xc9, 0x8a, 0x6b, 0xa5, 0x71, 0xca, 0xdc, 0xc7, 0x1b, 0xcd, 0xb9, 0x19, 0x2d, 0x80, 0x82, 0xc, 0x24, 0x7c, 0x38, 0xbc, 0x55, 0xca, 0xd, 0x38, 0x6c, 0x22, 0x5, 0x8c, 0x57, 0x2e, 0x51, 0xfc, 0xcd, 0x56, 0xf, 0x5c, 0x38, 0xd9, 0xe5, 0x7b, 0x67, 0x64, 0x19, 0x6f, 0xca, 0xb6, 0x89, 0x80, 0xbb, 0xbb, 0x7, 0x5a, 0x44, 0x41, 0xa1, 0x50, 0x71, 0xe5, 0xdd, 0x64, 0xe3, 0x53, 0x37, 0x4b, 0xcc, 0x56, 0xbc, 0x48, 0x47, 0x26, 0x93, 0x1c, 0xc8, 0x4f, 0x79, 0x81, 0x52, 0x81, 0xb, 0x4d, 0xbf, 0xdf, 0x4, 0xbe, 0x53, 0x55, 0x5c, 0x87, 0xac, 0x88, 0xbd, 0x56, 0x24, 0x2e, 0xa3, 0x43, 0x95, 0x12, 0xce, 0xb5, 0xfc, 0x2d, 0x13, 0xe2, 0x52, 0x41, 0xdc, 0xed, 0xa1, 0xf8, 0x11, 0xe4, 0x43, 0x21, 0x62, 0x20, 0x5d, 0x84, 0x4a, 0x88, 0xbd, 0x98, 0xef, 0x3c, 0x47, 0x9, 0x63, 0x0, 0xfe, 0x10, 0x90, 0x9, 0xf8, 0xc5, 0x1d, 0x99, 0x32, 0xd1, 0x20, 0xd6, 0x7f, 0x61, 0xc, 0xed, 0x6b, 0x15, 0x9c, 0x9c, 0x95, 0xdb, 0x62, 0xf5, 0xcd, 0xd3, 0x9b, 0x78, 0x60, 0xe2, 0x26, 0xa0, 0x5f, 0xbe, 0xf3, 0xbf, 0x1a, 0x68, 0xc5, 0xfe, 0xe2, 0xf7, 0xe, 0xfd, 0x12, 0x1, 0x83, 0x19, 0x33, 0xb7, 0xf9, 0xea, 0x98, 0x87, 0x5d, 0x92, 0x9, 0x6f, 0xd3, 0xdf, 0x39, 0xcd, 0xa6, 0x96, 0x58, 0xdd, 0xef, 0xb4, 0x16, 0x9, 0x85, 0x1c, 0x6e, 0xe5, 0x50, 0xbb, 0x8c, 0xc2, 0x15, 0x12, 0xf4, 0xf4, 0xe, 0x6f, 0xe2, 0x46, 0x5b, 0x85, 0x9d, 0x7, 0x37, 0xf9, 0x6d, 0xde, 0x13, 0xc8, 0x22, 0x20, 0x1c, 0xe6, 0x1, 0x2f, 0x20, 0x1c, 0xe6, 0x30, 0x6b, 0x10, 0x10, 0xe, 0xb3, 0xde, 0x6d, 0xe, 0xc5, 0x6f, 0xae, 0xf, 0x70, 0x15, 0x51, 0xf8, 0x3, 0xfe, 0xc5, 0xbf, 0x7d, 0x6b, 0xb1, 0x25, 0x5, 0xb5, 0x4d, 0xf4, 0xed, 0x1b, 0xb8, 0xd9, 0xae, 0x73, 0xc3, 0xcf, 0xb4, 0xa8, 0xb, 0xc4, 0x35, 0x10, 0xa3, 0x9f, 0x69, 0x85, 0x0, 0x8d, 0x5d, 0xef, 0x2, 0xa2, 0xf3, 0xa, 0x1a, 0x94, 0x67, 0x58, 0x47, 0x6c, 0x75, 0x81, 0x4c, 0xfe, 0x51, 0x81, 0x69, 0xeb, 0x40, 0x21, 0xf2, 0x1c, 0x99, 0x80, 0x98, 0xce, 0x51, 0x24, 0x77, 0x20, 0x86, 0x75, 0x1f, 0x27, 0x28, 0x4a, 0x10, 0x9, 0x8c, 0x9b, 0xea, 0x5d, 0xa0, 0x41, 0xc3, 0x60, 0x2, 0x8f, 0x45, 0x3b, 0xe5, 0x76, 0xdf, 0xb9, 0x39, 0xe9, 0x3b, 0xc3, 0x8a, 0x75, 0x11, 0xb2, 0x30, 0x23, 0xd4, 0xa2, 0xfc, 0x9, 0x63, 0x29, 0x56, 0x91, 0x7d, 0x4, 0xf, 0xed, 0x7f, 0xd6, 0xbb, 0xff, 0x15, 0xb9, 0xc7, 0x46, 0x4, 0x93, 0x9b, 0x48, 0x28, 0x74, 0x22, 0x16, 0x70, 0xac, 0xda, 0x4d, 0xbb, 0x33, 0xa8, 0xf4, 0x6f, 0xd8, 0x7c, 0xc0, 0x5d, 0x32, 0x4e, 0x33, 0xec, 0xc3, 0x33, 0x2, 0x88, 0x6d, 0x19, 0xb6, 0xc5, 0x46, 0x61, 0x8a, 0x2c, 0x97, 0x78, 0x1e, 0x84, 0x3, 0xc, 0x48, 0xe9, 0x92, 0x98, 0xa, 0x27, 0xf4, 0xdb, 0x37, 0xd6, 0xb, 0xe7, 0xbd, 0x2b, 0xf, 0x58, 0xb7, 0x88, 0x3b, 0x2, 0xfc, 0x26, 0xa6, 0x4d, 0xd6, 0xa6, 0xdf, 0xbe, 0x31, 0x2e, 0x99, 0xf0, 0xc1, 0x82, 0x26, 0xd3, 0xe1, 0xac, 0xa3, 0x50, 0x5f, 0xcb, 0xb9, 0xb3, 0x5b, 0x2, 0x54, 0x3c, 0x47, 0xe0, 0x77, 0x6, 0x1b, 0xd6, 0xa0, 0xe, 0xa7, 0x28, 0x78, 0xc5, 0x75, 0x8b, 0x2c, 0x6a, 0x41, 0x79, 0x1e, 0xf5, 0xd7, 0xfc, 0xca, 0x65, 0xd0, 0x11, 0x57, 0x57, 0x75, 0xe, 0x9a, 0xfd, 0xd, 0x52, 0xbe, 0x87, 0x18, 0x11, 0x5c, 0xb0, 0x97, 0x50, 0xe7, 0x1d, 0x76, 0xf2, 0xd0, 0xec, 0x30, 0xbd, 0x8b, 0x89, 0xe8, 0x4c, 0xd9, 0x70, 0xe6, 0x1c, 0xaf, 0x98, 0x48, 0x7a, 0xc8, 0x85, 0x7c, 0xdd, 0xb8, 0x1a, 0xa2, 0xe4, 0x6b, 0xe7, 0x86, 0x61, 0xbe, 0xe6, 0x89, 0x6d, 0xae, 0xb9, 0x88, 0x89, 0xe1, 0x76, 0xf4, 0xfc, 0x2f, 0x0, 0xea, 0x3a, 0xb1, 0x9c, 0x3d, 0x67, 0x4e, 0xd, 0x9b, 0x4e, 0x64, 0xa8, 0xeb, 0x48, 0x9, 0x8d, 0x57, 0xe0, 0xda, 0xdf, 0xb1, 0x6b, 0x3e, 0xf2, 0xc, 0x1c, 0x1a, 0x86, 0x49, 0xc, 0x13, 0x33, 0xf2, 0x9c, 0x8d, 0x25, 0x47, 0x47, 0x59, 0x40, 0x36, 0x11, 0x64, 0x3, 0xcf, 0xea, 0xa, 0x9d, 0xc7, 0x95, 0x24, 0x3, 0x73, 0xf7, 0xa2, 0xf8, 0x47, 0x70, 0x6, 0x5f, 0xd6, 0xd0, 0x2f, 0x74, 0x73, 0x68, 0x80, 0x42, 0x80, 0x4e, 0xb8, 0x39, 0xc4, 0x10, 0xb2, 0x25, 0xb5, 0x22, 0xda, 0x15, 0x8e, 0x0, 0xf1, 0xd1, 0x5c, 0xba, 0x81, 0x45, 0x42, 0x5c, 0x19, 0xb8, 0x61, 0x11, 0x21, 0x26, 0x71, 0x4c, 0x6f, 0x85, 0x9c, 0x27, 0x3c, 0xb8, 0x7b, 0xdd, 0x4f, 0xe1, 0xe4, 0x5f, 0x4f, 0x4c, 0xcc, 0xe, 0xb4, 0x54, 0x1a, 0x66, 0xa4, 0xe4, 0xf9, 0x15, 0x5e, 0xe8, 0x88, 0xb, 0x6d, 0x68, 0xe0, 0x63, 0x4c, 0x85, 0x87, 0xa3, 0x7a, 0xf2, 0xe4, 0x48, 0x61, 0x80, 0x41, 0xe6, 0x30, 0xb4, 0xab, 0xc6, 0x45, 0x8c, 0x8e, 0x2d, 0x3e, 0x60, 0x84, 0xa3, 0xfc, 0x7d, 0xe3, 0xd9, 0x1f, 0xbf, 0x7e, 0xd9, 0xf8, 0xfd, 0xd5, 0x13, 0xd, 0x15, 0x73, 0xf, 0xc1, 0xc, 0x1, 0x3, 0x9a, 0x50, 0x43, 0xdc, 0x99, 0x60, 0xcd, 0xa0, 0xc5, 0xa5, 0x78, 0x8c, 0x3c, 0xdc, 0x48, 0x61, 0xad, 0xfa, 0x34, 0x36, 0x93, 0xcb, 0x5, 0x86, 0xe0, 0x17, 0xae, 0xa1, 0x7e, 0x11, 0xf0, 0x14, 0x28, 0xb6, 0x29, 0x24, 0x9b, 0xab, 0x36, 0x87, 0xa2, 0xd0, 0x7f, 0x81, 0x6f, 0xdf, 0x6, 0xd8, 0xf8, 0xf6, 0x2d, 0xf, 0x9a, 0x98, 0x5a, 0xdc, 0x7f, 0xe1, 0x68, 0x38, 0xea, 0x7c, 0xa5, 0x1b, 0xce, 0x75, 0x8c, 0x9e, 0x9b, 0x50, 0x88, 0x4f, 0x5f, 0x75, 0x27, 0x3a, 0x65, 0x7b, 0x2, 0xab, 0x4f, 0x3c, 0xce, 0x74, 0x46, 0xca, 0xab, 0x0, 0x29, 0x70, 0x63, 0x5a, 0xdc, 0xe3, 0x3a, 0x18, 0x51, 0x2e, 0x2c, 0x42, 0x66, 0x85, 0x4c, 0x28, 0x84, 0xd9, 0x90, 0x3a, 0x42, 0x8a, 0xd0, 0x2, 0xce, 0xac, 0xd7, 0x3b, 0x30, 0xe7, 0xf9, 0x94, 0xbe, 0xf3, 0xd9, 0xc5, 0xf4, 0xce, 0xf5, 0xe6, 0xdf, 0x76, 0x72, 0xf8, 0xbe, 0x1d, 0xe5, 0xf3, 0x1b, 0x3f, 0x3f, 0xf0, 0x39, 0x65, 0x84, 0xb8, 0xaa, 0xe2, 0xcd, 0x1e, 0x5, 0x70, 0xcd, 0x51, 0x1e, 0xfc, 0x7e, 0xb4, 0x4d, 0xcf, 0xd1, 0x1f, 0x37, 0x9e, 0xf4, 0x89, 0x3e, 0x29, 0x10, 0x31, 0x73, 0x42, 0xc8, 0x9, 0x77, 0xb6, 0x73, 0x92, 0x4d, 0x24, 0x2c, 0x66, 0xa7, 0xd6, 0x5a, 0x2d, 0x7d, 0xf9, 0x2, 0x86, 0x3a, 0xe, 0x34, 0x7a, 0x7, 0x4, 0xd8, 0xee, 0xab, 0xa8, 0xc8, 0x31, 0x27, 0xe6, 0x33, 0x1f, 0x97, 0x38, 0x4a, 0x42, 0x43, 0xba, 0x95, 0xf, 0x6d, 0x1b, 0x82, 0x1c, 0x62, 0x5d, 0x79, 0x57, 0xc3, 0x98, 0x48, 0x23, 0xec, 0x73, 0xba, 0x5c, 0xea, 0xd7, 0x2d, 0xee, 0x7e, 0x21, 0x5, 0x90, 0x52, 0x22, 0x63, 0xae, 0x55, 0x39, 0xd3, 0xf2, 0xd9, 0x82, 0xf3, 0xb0, 0xd0, 0x52, 0x2a, 0x7, 0x60, 0x4f, 0xdd, 0xd5, 0x28, 0xef, 0x56, 0xc9, 0xaf, 0x62, 0x44, 0xbb, 0x6b, 0x65, 0x6a, 0xb1, 0x79, 0x87, 0xfa, 0xf4, 0x8d, 0xa7, 0x90, 0xd8, 0x7c, 0xe4, 0x53, 0x3e, 0x8e, 0x49, 0xe6, 0x37, 0x78, 0xbd, 0x39, 0xc1, 0x55, 0x78, 0x8e, 0x1a, 0xa, 0x85, 0x7e, 0x80, 0xae, 0xb, 0x9, 0x76, 0xca, 0xf, 0x50, 0x46, 0x54, 0x36, 0x31, 0xbf, 0x5e, 0x6f, 0xf7, 0xf5, 0xba, 0x92, 0x40, 0xba, 0xf3, 0x26, 0xf4, 0x3, 0x84, 0x83, 0x8b, 0x0, 0xdc, 0xf3, 0xd2, 0x5f, 0x6f, 0x3f, 0x6, 0x86, 0xfd, 0xdb, 0x37, 0xd1, 0xcb, 0x6f, 0xdf, 0xf8, 0x4f, 0x87, 0x4b, 0xeb, 0x1a, 0x9c, 0xa2, 0x1, 0x9c, 0xde, 0x38, 0xf4, 0xb1, 0x71, 0xb4, 0xe0, 0xd4, 0xb7, 0x72, 0x77, 0x99, 0x8a, 0x7, 0xc4, 0x53, 0xf0, 0x3, 0xdc, 0x8, 0xe7, 0xc0, 0x8d, 0x40, 0xb3, 0xa9, 0xf, 0x6e, 0xbc, 0x8e, 0x3a, 0xc0, 0x7c, 0x16, 0x65, 0x42, 0x49, 0x74, 0xe0, 0x19, 0x1c, 0xdb, 0x40, 0xd1, 0xaf, 0x6c, 0x8d, 0xcc, 0xd8, 0x6, 0xb1, 0x39, 0x96, 0x6b, 0xe8, 0x3d, 0xc2, 0xcf, 0x25, 0xc, 0xd2, 0x9d, 0x76, 0xb9, 0x18, 0x6a, 0xae, 0x7e, 0x11, 0x6b, 0xd, 0x5e, 0xf7, 0xc9, 0x4a, 0x25, 0x2, 0x7e, 0x4, 0x69, 0x4, 0xde, 0xc9, 0x6d, 0xa5, 0xe6, 0x8e, 0x96, 0x98, 0x1c, 0x38, 0x6a, 0xd3, 0x46, 0xdf, 0xc1, 0xae, 0xba, 0xe7, 0xaf, 0xf9, 0x1a, 0x21, 0x2a, 0x16, 0x8, 0x51, 0xbe, 0x3a, 0xf8, 0xe, 0xc6, 0xb6, 0x25, 0xac, 0x7f, 0x9f, 0xd9, 0xe7, 0x76, 0x6e, 0xdf, 0xac, 0xc2, 0xad, 0x2, 0xe7, 0x73, 0xc8, 0x2a, 0x46, 0xba, 0xc5, 0x89, 0xe6, 0xc6, 0x90, 0x43, 0x69, 0xb0, 0xc9, 0x4, 0x7e, 0x80, 0xbe, 0xa0, 0x93, 0xd7, 0x5, 0x78, 0xb2, 0x6d, 0xbf, 0x79, 0xb6, 0x92, 0x30, 0x8d, 0xb8, 0x85, 0x13, 0x64, 0x47, 0xfe, 0x0, 0x37, 0xac, 0xab, 0x4e, 0x6b, 0xa2, 0x67, 0x37, 0x3b, 0x5c, 0xbe, 0x8d, 0xdc, 0x12, 0xb, 0xb5, 0x35, 0x53, 0xfd, 0x42, 0xc5, 0x7a, 0xd6, 0xcb, 0x6b, 0x18, 0x1, 0x75, 0x8b, 0x82, 0x52, 0xdb, 0xbf, 0x22, 0xda, 0xfe, 0xc6, 0xac, 0xb3, 0xd0, 0xb6, 0x48, 0xd8, 0xed, 0xa4, 0xe2, 0x51, 0xd1, 0x40, 0xab, 0x60, 0x2a, 0xe6, 0x68, 0xf5, 0x84, 0xd6, 0xf7, 0x20, 0xe6, 0x9f, 0x6a, 0x1b, 0x2f, 0xf8, 0xc1, 0x66, 0x6d, 0x7e, 0xd5, 0x2b, 0xc3, 0x48, 0x91, 0x3a, 0x71, 0x57, 0x9d, 0x6e, 0xb7, 0xf7, 0xa0, 0xb, 0xc8, 0xf5, 0x70, 0x3, 0x7e, 0xb8, 0x9e, 0xa, 0xef, 0xad, 0x5, 0x14, 0x68, 0x41, 0xf7, 0xb4, 0xff, 0xf6, 0x7, 0xf6, 0x82, 0xb6, 0x6e, 0x1c, 0x69, 0x75, 0xcc, 0x55, 0xd6, 0x51, 0x9b, 0x22, 0x85, 0x13, 0x85, 0x74, 0xd9, 0x5c, 0x71, 0x4d, 0x14, 0x1, 0x2d, 0x36, 0xa0, 0x63, 0xb6, 0xca, 0x66, 0x9c, 0xa4, 0x4f, 0x99, 0xce, 0x8b, 0xa5, 0xb9, 0xae, 0xa3, 0x9c, 0x7d, 0x74, 0x62, 0x85, 0x61, 0xd8, 0xe1, 0xb8, 0x39, 0x47, 0xcc, 0xd5, 0x45, 0x61, 0x7d, 0x52, 0xc0, 0xd5, 0x19, 0xbe, 0xc3, 0x3, 0x3b, 0xc7, 0x6e, 0x18, 0x3d, 0xbd, 0xf5, 0x21, 0x9c, 0x89, 0xbb, 0xcc, 0x11, 0xd5, 0x85, 0xfa, 0xe0, 0xda, 0xc3, 0xef, 0xb4, 0xf0, 0x1f, 0x47, 0xb8, 0xd9, 0xd7, 0x86, 0xc5, 0xd4, 0xd3, 0xf, 0x30, 0x70, 0xd4, 0x52, 0x30, 0x56, 0xbf, 0x4e, 0xda, 0x45, 0xb1, 0x3e, 0xc7, 0xc3, 0x30, 0x75, 0x6d, 0x55, 0x5, 0xce, 0xb1, 0x9e, 0xbd, 0x18, 0xeb, 0x93, 0x36, 0xb1, 0xba, 0x26, 0xa2, 0x48, 0xb7, 0x2, 0xf0, 0x22, 0xd, 0x62, 0xb5, 0x46, 0xa8, 0xc5, 0x3f, 0x21, 0xfb, 0xe1, 0x98, 0x8, 0xc, 0x96, 0x6a, 0x96, 0x11, 0xd1, 0x56, 0x42, 0x87, 0xb0, 0x85, 0xd5, 0x3e, 0x4, 0x5d, 0x62, 0xfa, 0x10, 0xf0, 0x13, 0x95, 0x3f, 0xc0, 0x4d, 0x3c, 0xb5, 0xaf, 0xfe, 0x90, 0xf2, 0x71, 0x72, 0xea, 0xdb, 0x94, 0x89, 0x87, 0xc6, 0xc9, 0xa5, 0x50, 0x33, 0x54, 0x74, 0xcd, 0x21, 0xfe, 0xf5, 0x94, 0xa6, 0xfb, 0x54, 0xdd, 0xc0, 0x44, 0x99, 0x15, 0xfa, 0xdf, 0xdb, 0xec, 0xb6, 0x3, 0x76, 0x62, 0x72, 0x94, 0x80, 0x32, 0x55, 0x2d, 0x80, 0x27, 0x26, 0xd1, 0x78, 0x9e, 0x56, 0xa6, 0x53, 0x5d, 0x18, 0xf0, 0x9f, 0x7b, 0x29, 0xfa, 0xaf, 0x7d, 0xb8, 0xeb, 0xa, 0xd2, 0x2d, 0x6c, 0xf1, 0x6f, 0xf4, 0x3, 0x1c, 0x1d, 0xed, 0x56, 0x13, 0xec, 0xe9, 0x7e, 0x30, 0x36, 0xda, 0x73, 0x1e, 0xbe, 0xb8, 0x87, 0x89, 0x3, 0x6, 0x7c, 0xc9, 0x65, 0xce, 0x5b, 0x7a, 0x73, 0x69, 0xe1, 0xbd, 0xd8, 0x46, 0xe2, 0x56, 0x9, 0xc0, 0xc4, 0xff, 0xee, 0xae, 0xdf, 0x6f, 0xa2, 0x13, 0xdd, 0x67, 0xdf, 0x86, 0xe1, 0x14, 0x1a, 0x27, 0x16, 0x4f, 0x24, 0x83, 0x3e, 0x2a, 0xb4, 0xad, 0x19, 0xeb, 0xb3, 0x48, 0xac, 0xca, 0x56, 0x1c, 0x37, 0x42, 0x79, 0xf8, 0x9e, 0x2, 0x7e, 0x3c, 0xd7, 0x37, 0x21, 0xff, 0xa, 0x6e, 0x94, 0xf1, 0x35, 0xab, 0x74, 0xc3, 0x1f, 0xf3, 0xe4, 0xb8, 0xc0, 0xbd, 0xe7, 0xe4, 0x3b, 0xb8, 0x51, 0x15, 0x68, 0xf8, 0xde, 0x37, 0xcb, 0x85, 0xee, 0x77, 0x80, 0x2c, 0x39, 0x12, 0x89, 0x7c, 0x5, 0xbf, 0x97, 0x89, 0x4c, 0x9f, 0xb9, 0xbf, 0xac, 0x10, 0x99, 0x46, 0x59, 0x8f, 0xae, 0xb9, 0xbf, 0x38, 0xa2, 0x29, 0x5f, 0xd8, 0xaf, 0x30, 0x94, 0x65, 0x62, 0xeb, 0xd6, 0x57, 0xd6, 0x51, 0x8f, 0xa4, 0x9d, 0x4e, 0x32, 0x15, 0xe9, 0xcc, 0x9c, 0xbc, 0x43, 0xac, 0x8b, 0x5, 0x66, 0xaa, 0x51, 0x3e, 0x4a, 0x7c, 0x6a, 0x16, 0x33, 0x1d, 0x32, 0x9d, 0x95, 0xb5, 0x46, 0x11, 0x9b, 0xb4, 0xbf, 0x3, 0x62, 0xcd, 0x90, 0xb9, 0xc4, 0x14, 0x1, 0xa2, 0xab, 0x2b, 0x31, 0xb6, 0x2, 0x11, 0x31, 0xa9, 0x67, 0xc9, 0xb, 0x34, 0x3f, 0xc0, 0xd, 0xd1, 0x3, 0xda, 0x67, 0xc3, 0x11, 0xb1, 0x4d, 0xce, 0xee, 0x6c, 0x2c, 0x5c, 0x41, 0x1d, 0xf6, 0x9a, 0x7c, 0x7c, 0xfc, 0xe3, 0xb5, 0x35, 0xf4, 0x3f, 0xc4, 0x4b, 0x36, 0x50, 0xfc, 0xdf, 0x7d, 0x8a, 0x8a, 0x37, 0x41, 0x11, 0x34, 0xe5, 0x59, 0xb9, 0xed, 0xb5, 0xd3, 0xe7, 0xf, 0x40, 0xb9, 0xcd, 0xf0, 0xec, 0x83, 0x62, 0xdf, 0xcc, 0x7, 0x53, 0x64, 0x4b, 0xad, 0xc7, 0x21, 0x26, 0x58, 0xb5, 0x84, 0x1a, 0xe0, 0x10, 0x27, 0xfc, 0x27, 0x3, 0xf8, 0x55, 0x24, 0x19, 0xe2, 0x9, 0x68, 0x7e, 0x63, 0xf3, 0x9, 0xd1, 0xbf, 0xee, 0x1d, 0xf, 0xac, 0x78, 0x18, 0x86, 0xf5, 0x32, 0x3, 0x17, 0x8f, 0x82, 0xbb, 0x26, 0x13, 0x3, 0xad, 0xfb, 0xc5, 0x7e, 0x71, 0x45, 0xb5, 0xaf, 0xbe, 0x93, 0x16, 0xd8, 0x83, 0x18, 0x88, 0xdf, 0xc, 0x26, 0x48, 0xc, 0x38, 0xcc, 0x2, 0x99, 0x78, 0xb2, 0x62, 0x13, 0xab, 0x7, 0x76, 0xce, 0x1f, 0x81, 0xda, 0x60, 0xd0, 0xed, 0x3, 0x9f, 0x49, 0xc3, 0xf0, 0xc, 0xd6, 0x66, 0x88, 0x1f, 0x95, 0x97, 0x4b, 0x87, 0x21, 0xf9, 0xdd, 0xfb, 0xb5, 0x66, 0xf8, 0x4d, 0x3f, 0x9, 0xe7, 0x6c, 0x99, 0xe8, 0x32, 0x32, 0x2c, 0x1a, 0xdd, 0xf0, 0x5b, 0x44, 0x85, 0x29, 0x14, 0x66, 0x6b, 0x15, 0xdb, 0x62, 0xc6, 0x98, 0x83, 0x2b, 0xec, 0x9d, 0x8e, 0x8b, 0x7e, 0x75, 0xe2, 0x23, 0x88, 0xb7, 0x6c, 0xf7, 0xde, 0x71, 0x4b, 0xc1, 0xd6, 0x15, 0x34, 0xc1, 0xba, 0x6b, 0x1, 0xf8, 0x9, 0x75, 0xe, 0x45, 0x31, 0x32, 0xf9, 0xbc, 0x6d, 0x11, 0xc7, 0xd3, 0x4, 0xba, 0xe7, 0x25, 0xca, 0x4c, 0x34, 0x9f, 0xbd, 0xe0, 0xdb, 0xd9, 0x2, 0xbf, 0x52, 0x84, 0xf8, 0x82, 0xdd, 0x14, 0x9b, 0x8a, 0x74, 0xcb, 0x57, 0xf2, 0x95, 0x6b, 0x67, 0xb4, 0xe1, 0x3e, 0xd9, 0x69, 0xdd, 0x7f, 0x8c, 0x84, 0x91, 0xd0, 0x66, 0x3a, 0x46, 0x84, 0x94, 0xf2, 0x6e, 0x18, 0x44, 0x61, 0x2b, 0x33, 0x3c, 0x15, 0xf9, 0xbb, 0x7f, 0x80, 0x9b, 0x3f, 0xff, 0xa, 0x18, 0x6d, 0xdf, 0x61, 0xe, 0x3e, 0x45, 0xfb, 0xe, 0x7c, 0x4, 0x63, 0xf9, 0xfd, 0x8f, 0x20, 0x2d, 0xe8, 0x1c, 0x39, 0x71, 0x9, 0x89, 0x76, 0x19, 0x9c, 0x78, 0x88, 0xc5, 0x9a, 0xc3, 0x6d, 0xfd, 0xdb, 0xb7, 0x53, 0x2f, 0x4, 0xdc, 0xb5, 0x4a, 0x7c, 0x41, 0xe1, 0x4f, 0x30, 0x4a, 0xd6, 0xb5, 0xf7, 0xd9, 0x24, 0xeb, 0x1a, 0x37, 0x7b, 0x1a, 0xd8, 0xb2, 0x48, 0x2, 0x51, 0xfa, 0xd, 0x92, 0x1d, 0x4, 0x8f, 0xdb, 0x23, 0x41, 0xf8, 0x2, 0xcc, 0x11, 0x1f, 0x56, 0x67, 0x5e, 0xf4, 0x1, 0x3e, 0x3e, 0x2f, 0xee, 0xc4, 0xd1, 0x6f, 0x41, 0x7b, 0xc1, 0xf5, 0x9b, 0x8, 0xbc, 0xba, 0x5b, 0x38, 0xfe, 0xd6, 0x42, 0xe7, 0xa3, 0xf3, 0x15, 0x5c, 0xef, 0xc3, 0xf2, 0x72, 0xa6, 0xf7, 0x21, 0x79, 0x16, 0xcf, 0xf, 0xeb, 0x2e, 0xaf, 0x7, 0x9c, 0x77, 0xf, 0xe0, 0x71, 0x1b, 0xef, 0xe3, 0x6d, 0x1b, 0xdf, 0x6c, 0x21, 0xda, 0xe2, 0xe5, 0xd, 0x50, 0x3f, 0xf, 0x7, 0x9c, 0x89, 0xf, 0xe2, 0x5d, 0x3f, 0x7c, 0x0, 0xcf, 0xda, 0xd8, 0xe5, 0x55, 0x1b, 0x1f, 0xe0, 0x51, 0xef, 0xac, 0x89, 0x53, 0xfb, 0x29, 0x3c, 0xb9, 0x7d, 0xc6, 0xc4, 0x1, 0x75, 0x9e, 0x39, 0xd, 0x6, 0x2a, 0x47, 0x1b, 0xff, 0xbd, 0xb9, 0x78, 0xeb, 0x40, 0xe0, 0x33, 0xb9, 0x77, 0xf3, 0x30, 0xde, 0x33, 0xb9, 0xd6, 0x77, 0x4c, 0xf0, 0x49, 0xdc, 0xda, 0x5a, 0xf5, 0xcf, 0x9a, 0x2e, 0xc3, 0x6a, 0x2b, 0x7a, 0xa7, 0x3e, 0x85, 0x67, 0x79, 0xc5, 0x7d, 0x6c, 0xcb, 0x5f, 0xde, 0xec, 0x62, 0xdc, 0x62, 0xde, 0x6d, 0x1c, 0x7e, 0xfe, 0xf5, 0x83, 0x3d, 0xce, 0xc2, 0x5b, 0x58, 0x2, 0xb8, 0x58, 0xe0, 0x9a, 0x39, 0xab, 0x3f, 0xde, 0x5f, 0xd0, 0xf7, 0x56, 0x7f, 0xff, 0x6f, 0xa3, 0x96, 0xe1, 0x2c, 0xf1, 0x44, 0xad, 0xae, 0xb3, 0xc4, 0x4b, 0x24, 0xa4, 0xf4, 0x46, 0x35, 0xdb, 0x59, 0xd9, 0x89, 0x6a, 0x43, 0xdf, 0xca, 0xce, 0x24, 0x64, 0xb3, 0x5d, 0xb6, 0xda, 0xf0, 0x61, 0x74, 0xd7, 0x1e, 0xac, 0xaa, 0xe7, 0x9f, 0xf2, 0x55, 0x77, 0x17, 0x6, 0x6b, 0x90, 0xb2, 0xf3, 0x64, 0x2f, 0xc8, 0xdf, 0x5a, 0x12, 0x4, 0x89, 0x1f, 0x6f, 0x3e, 0x89, 0x76, 0x5f, 0x21, 0x84, 0x2, 0xc1, 0xcb, 0xe5, 0x50, 0xc0, 0x3f, 0x4b, 0x14, 0x5d, 0x87, 0xa5, 0x2b, 0x8d, 0x7b, 0x93, 0x4f, 0x7, 0x8, 0xa4, 0x5b, 0x77, 0x47, 0x26, 0xbd, 0x9c, 0x86, 0xc6, 0x8c, 0x58, 0xde, 0x8a, 0x6b, 0x37, 0x5f, 0xb5, 0x5f, 0x32, 0x3, 0x90, 0xc5, 0x23, 0xe9, 0x48, 0x3c, 0xbc, 0x21, 0xa3, 0x7b, 0x33, 0x57, 0x7, 0x89, 0xe9, 0x2e, 0xca, 0x0, 0x49, 0xdd, 0xbe, 0x9d, 0x80, 0x21, 0xf2, 0x0, 0xf9, 0x36, 0xbb, 0xe3, 0xb0, 0xb, 0xfc, 0xe4, 0x1, 0x57, 0x23, 0x6c, 0x20, 0x78, 0xca, 0x94, 0xb4, 0x9b, 0x4b, 0xfb, 0xef, 0x28, 0x54, 0xdb, 0x79, 0x44, 0x3f, 0x50, 0xae, 0x2, 0xd3, 0xb, 0x3f, 0x53, 0xb4, 0x82, 0x92, 0xfa, 0x3e, 0x53, 0xba, 0x76, 0x52, 0xf, 0x3f, 0x49, 0xc0, 0x4a, 0x2a, 0xc4, 0x9e, 0x7b, 0x54, 0x66, 0x3f, 0xfc, 0xae, 0x5d, 0x27, 0x5c, 0x8d, 0x57, 0xfa, 0xef, 0x2d, 0xdf, 0xb9, 0xa8, 0xfc, 0x4, 0x39, 0xe4, 0x15, 0x77, 0x84, 0x90, 0x3f, 0xdd, 0x94, 0x40, 0x3f, 0xc6, 0x2d, 0xf1, 0xdb, 0xc6, 0x11, 0x8f, 0x48, 0x91, 0x98, 0x2b, 0x7b, 0x6b, 0xd8, 0xbf, 0x29, 0x8b, 0xae, 0x9, 0x7c, 0x5, 0x8b, 0x8, 0x4, 0x2f, 0xe7, 0xf, 0x1, 0xff, 0xc, 0xe6, 0xb8, 0x59, 0x5f, 0x60, 0xcc, 0x6a, 0x77, 0x16, 0xc8, 0x34, 0xb1, 0x82, 0xdc, 0x86, 0xdc, 0x77, 0xce, 0xae, 0xe3, 0xef, 0x3e, 0xb9, 0x38, 0x14, 0x78, 0x28, 0x42, 0xf6, 0x84, 0x87, 0x6e, 0x12, 0xcf, 0x25, 0xb2, 0x30, 0x99, 0x46, 0x9, 0x88, 0xb2, 0x28, 0x9e, 0x8a, 0xc5, 0x91, 0x82, 0x62, 0xb1, 0x64, 0x3c, 0x99, 0x4e, 0x49, 0x52, 0x52, 0xca, 0x25, 0xe5, 0x84, 0x9c, 0x48, 0x24, 0xa2, 0x94, 0x6f, 0x8a, 0xfa, 0x6e, 0x55, 0x8e, 0x3e, 0x2e, 0x9c, 0x9c, 0xbd, 0xdb, 0xfc, 0xba, 0x4a, 0x97, 0xbf, 0x37, 0x2f, 0x36, 0xf5, 0x31, 0xb8, 0xa8, 0xb6, 0xcd, 0xe1, 0xee, 0xb5, 0xc8, 0x4f, 0xde, 0x2f, 0x10, 0x0, 0x60, 0xcf, 0x8e, 0xc1, 0xc6, 0x5d, 0xa2, 0x9b, 0x9c, 0x1f, 0xd4, 0xd2, 0x96, 0x4, 0xec, 0xc3, 0x2d, 0x45, 0x52, 0x9b, 0x92, 0xf0, 0xf8, 0x5, 0xdd, 0x8f, 0x50, 0xcd, 0x1, 0xf6, 0x52, 0xcd, 0xdf, 0x6, 0x53, 0xbd, 0x75, 0xbb, 0x77, 0x10, 0xd5, 0xdb, 0xb8, 0xf7, 0x51, 0xad, 0x8c, 0x9f, 0x41, 0xb1, 0x6b, 0x18, 0xee, 0xd0, 0xac, 0x41, 0x13, 0x43, 0x65, 0x1c, 0x48, 0xad, 0xd7, 0x42, 0x30, 0xa5, 0x1, 0x38, 0x83, 0x88, 0xf4, 0x39, 0xd7, 0xf9, 0x26, 0x96, 0xe7, 0x40, 0x27, 0x13, 0xc7, 0x99, 0x1b, 0x84, 0xf3, 0x7, 0xe8, 0x1b, 0x48, 0xc6, 0x93, 0xd5, 0x3a, 0xe4, 0xd3, 0x3, 0xf4, 0xd3, 0xf8, 0xa, 0x2d, 0xe1, 0x60, 0x78, 0xb9, 0x9a, 0x70, 0x10, 0x3c, 0x6b, 0x12, 0x71, 0xf6, 0xa3, 0x5d, 0x31, 0xdb, 0x4a, 0x87, 0xe3, 0x93, 0x33, 0x37, 0x10, 0x48, 0xf8, 0x79, 0xc5, 0xf6, 0x9d, 0x2b, 0x70, 0x21, 0x77, 0x6c, 0x10, 0x94, 0x67, 0xeb, 0x18, 0x7, 0x67, 0x3b, 0x9d, 0x47, 0x76, 0x88, 0x8, 0x9e, 0x39, 0x5a, 0xfd, 0xc6, 0xe5, 0xfc, 0xf7, 0xef, 0xde, 0x9f, 0x7f, 0xdc, 0x0, 0x68, 0x4e, 0x6d, 0xde, 0x1b, 0x8b, 0x38, 0xe1, 0x51, 0x4e, 0x70, 0xc8, 0x4d, 0x4, 0x9c, 0x10, 0x13, 0xa0, 0x7b, 0xbe, 0x9f, 0xb3, 0x1d, 0x7, 0xe2, 0x8f, 0x1c, 0x7a, 0x4e, 0xc4, 0x90, 0x2f, 0x3a, 0x46, 0x44, 0x8e, 0x14, 0x54, 0x5e, 0xcd, 0xc2, 0xb, 0xa4, 0xae, 0xbe, 0x3, 0x8, 0x46, 0x85, 0x56, 0x53, 0x84, 0xb8, 0xf0, 0x10, 0x31, 0xca, 0xbb, 0x87, 0x9d, 0x58, 0x10, 0xa1, 0xa8, 0xbc, 0x40, 0x29, 0x5f, 0x48, 0x87, 0x13, 0x4a, 0x66, 0x98, 0x64, 0x81, 0x15, 0xa4, 0x80, 0xe5, 0xc, 0xab, 0x8, 0x6c, 0xc5, 0xc0, 0x88, 0xd0, 0x66, 0x7f, 0xbf, 0xbe, 0x3f, 0xa7, 0x5f, 0x13, 0x10, 0x35, 0xa0, 0x35, 0x8b, 0x5a, 0xc4, 0xaf, 0x44, 0x45, 0x3f, 0x7c, 0xd1, 0x67, 0xfe, 0x90, 0x7c, 0x7f, 0x44, 0xc9, 0xa6, 0xae, 0xf7, 0xab, 0x61, 0x71, 0x4a, 0x62, 0x6d, 0x60, 0x85, 0x42, 0xce, 0x9e, 0xf, 0xb5, 0x88, 0xe9, 0x74, 0x9d, 0xef, 0xe, 0x43, 0x5d, 0xd9, 0x8c, 0xc4, 0xe3, 0xe6, 0x96, 0x9b, 0x57, 0xc8, 0xcd, 0xb8, 0x15, 0xf1, 0x48, 0x90, 0x67, 0x50, 0x9f, 0x22, 0xdf, 0xd0, 0x9, 0x3, 0xcc, 0x22, 0x3b, 0xdb, 0xcf, 0xb2, 0x8, 0x29, 0xe2, 0xc7, 0x8, 0xd6, 0xa4, 0x58, 0xe7, 0xeb, 0xfb, 0x8, 0xf8, 0xd8, 0x20, 0xa8, 0x88, 0x50, 0xbb, 0xa3, 0xc2, 0x4e, 0xbb, 0xcc, 0x2c, 0x9c, 0xf0, 0x98, 0x7a, 0x37, 0x76, 0x92, 0x9f, 0x85, 0x86, 0x80, 0x9, 0x1, 0xa6, 0x8e, 0xe8, 0x8, 0xe3, 0x12, 0x72, 0xf1, 0xe0, 0xa1, 0xd5, 0x0, 0xdd, 0xf3, 0x80, 0x1d, 0x48, 0x81, 0x4a, 0xf4, 0xa9, 0x38, 0x3c, 0x0, 0x2d, 0x17, 0xca, 0xb4, 0x75, 0x9d, 0xef, 0x5f, 0xeb, 0xe2, 0x31, 0x93, 0xf2, 0x8, 0xb8, 0xd8, 0xc0, 0x2c, 0x42, 0x8e, 0x14, 0x67, 0x4b, 0x92, 0x57, 0x11, 0x7b, 0x72, 0xfa, 0xa, 0x98, 0x8, 0x52, 0xa2, 0x7f, 0x5f, 0x8f, 0xa1, 0x13, 0x5a, 0xe5, 0x11, 0x8f, 0xa9, 0x13, 0x6e, 0xc4, 0xf7, 0xf1, 0x10, 0x9b, 0x4a, 0x8e, 0xbe, 0x3d, 0xe9, 0x70, 0x9e, 0xb3, 0x65, 0xe6, 0xc4, 0xd0, 0x33, 0x29, 0xa2, 0x11, 0x95, 0xc8, 0xf3, 0xb7, 0x3c, 0x63, 0x74, 0xe8, 0xfc, 0x7f, 0x22, 0x95, 0xd8, 0xce, 0xff, 0x2c, 0x49, 0x9f, 0xe7, 0x7f, 0x3f, 0xa4, 0x78, 0xa7, 0x22, 0x30, 0xa2, 0xf9, 0xd0, 0xfa, 0xb6, 0x16, 0x5, 0x53, 0x91, 0x64, 0xd5, 0x99, 0x7d, 0xf3, 0x60, 0xd7, 0x90, 0xe, 0xb, 0x6b, 0xce, 0xbd, 0x3d, 0x22, 0x32, 0x25, 0x64, 0xaa, 0x22, 0x68, 0x60, 0xca, 0xcc, 0xbe, 0x90, 0xef, 0xb6, 0xde, 0x44, 0x24, 0x1e, 0x49, 0x85, 0x14, 0x3c, 0x45, 0xd4, 0xca, 0x3, 0x3a, 0x83, 0xf1, 0x54, 0x3a, 0x8f, 0xa4, 0x49, 0x2c, 0x1b, 0x4f, 0x66, 0xa4, 0x44, 0x16, 0x41, 0x38, 0xce, 0x2a, 0x59, 0x94, 0xcd, 0xa2, 0xf1, 0x38, 0x9, 0xc7, 0x93, 0x24, 0x82, 0xa9, 0x5c, 0x26, 0x93, 0x85, 0xd9, 0x74, 0x2a, 0x99, 0x8a, 0x67, 0x73, 0xa9, 0x4c, 0x2e, 0x95, 0x49, 0x25, 0x92, 0x50, 0x99, 0xa4, 0x13, 0x89, 0x4c, 0x2e, 0x96, 0x1a, 0x87, 0xbc, 0x20, 0x95, 0x3c, 0x88, 0x4b, 0xb1, 0x6c, 0x58, 0x4a, 0x85, 0x63, 0xe9, 0x41, 0x2c, 0x96, 0x4f, 0x24, 0xf3, 0x52, 0x2e, 0x22, 0x65, 0xa4, 0x4c, 0x2e, 0x97, 0xcd, 0xa6, 0x8f, 0xa5, 0x6c, 0x5e, 0xfa, 0x1f, 0x9f, 0xe9, 0x39, 0xb8, 0x4, 0xc9, 0xff, 0xdb, 0x65, 0x7e, 0x17, 0xe5, 0x90, 0xfc, 0xc7, 0x52, 0xdb, 0xe7, 0x3f, 0x93, 0xd2, 0x67, 0xfe, 0x9f, 0x8f, 0x29, 0x8f, 0xcb, 0xff, 0x96, 0x0, 0xbf, 0x52, 0x21, 0xfc, 0xec, 0xbe, 0x7e, 0x96, 0xcf, 0xf2, 0x59, 0x3e, 0xcb, 0x67, 0x59, 0x97, 0xff, 0x2f, 0x0, 0x0, 0xff, 0xff, 0xb9, 0xe, 0xe4, 0x88, 0x0, 0x6c, 0x1, 0x0} diff --git a/src/chartserver/cache.go b/src/chartserver/cache.go index c0384ffe0..0e86f883d 100644 --- a/src/chartserver/cache.go +++ b/src/chartserver/cache.go @@ -8,50 +8,50 @@ import ( beego_cache "github.com/astaxie/beego/cache" hlog "github.com/goharbor/harbor/src/common/utils/log" - //Enable redis cache adaptor + // Enable redis cache adaptor _ "github.com/astaxie/beego/cache/redis" ) const ( standardExpireTime = 3600 * time.Second redisENVKey = "_REDIS_URL" - cacheDriverENVKey = "CHART_CACHE_DRIVER" //"memory" or "redis" + cacheDriverENVKey = "CHART_CACHE_DRIVER" // "memory" or "redis" cacheDriverMem = "memory" cacheDriverRedis = "redis" cacheCollectionName = "helm_chart_cache" ) -//ChartCache is designed to cache some processed data for repeated accessing -//to improve the performance +// ChartCache is designed to cache some processed data for repeated accessing +// to improve the performance type ChartCache struct { - //Cache driver + // Cache driver cache beego_cache.Cache - //Keep the driver type + // Keep the driver type driverType string - //To indicate if the chart cache is enabled + // To indicate if the chart cache is enabled isEnabled bool } -//ChartCacheConfig keeps the configurations of ChartCache +// ChartCacheConfig keeps the configurations of ChartCache type ChartCacheConfig struct { - //Only support 'in-memory' and 'redis' now + // Only support 'in-memory' and 'redis' now DriverType string - //Align with config + // Align with config Config string } -//NewChartCache is constructor of ChartCache -//If return nil, that means no cache is enabled for chart repository server +// NewChartCache is constructor of ChartCache +// If return nil, that means no cache is enabled for chart repository server func NewChartCache(config *ChartCacheConfig) *ChartCache { - //Never return nil object + // Never return nil object chartCache := &ChartCache{ isEnabled: false, } - //Double check the configurations are what we want + // Double check the configurations are what we want if config == nil { return chartCache } @@ -66,13 +66,13 @@ func NewChartCache(config *ChartCacheConfig) *ChartCache { } } - //Try to create the upstream cache + // Try to create the upstream cache cache := initCacheDriver(config) if cache == nil { return chartCache } - //Cache enabled + // Cache enabled chartCache.isEnabled = true chartCache.driverType = config.DriverType chartCache.cache = cache @@ -80,74 +80,74 @@ func NewChartCache(config *ChartCacheConfig) *ChartCache { return chartCache } -//IsEnabled to indicate if the chart cache is successfully enabled -//The cache may be disabled if +// IsEnabled to indicate if the chart cache is successfully enabled +// The cache may be disabled if // user does not set // wrong configurations func (chc *ChartCache) IsEnabled() bool { return chc.isEnabled } -//PutChart caches the detailed data of chart version +// PutChart caches the detailed data of chart version func (chc *ChartCache) PutChart(chart *ChartVersionDetails) { - //If cache is not enabled, do nothing + // If cache is not enabled, do nothing if !chc.IsEnabled() { return } - //As it's a valid json data anymore when retrieving back from redis cache, - //here we use separate methods to handle the data according to the driver type + // As it's a valid json data anymore when retrieving back from redis cache, + // here we use separate methods to handle the data according to the driver type if chart != nil { var err error switch chc.driverType { case cacheDriverMem: - //Directly put object in + // Directly put object in err = chc.cache.Put(chart.Metadata.Digest, chart, standardExpireTime) case cacheDriverRedis: - //Marshal to json data before saving + // Marshal to json data before saving var jsonData []byte if jsonData, err = json.Marshal(chart); err == nil { err = chc.cache.Put(chart.Metadata.Digest, jsonData, standardExpireTime) } default: - //Should not reach here, but still put guard code here + // Should not reach here, but still put guard code here err = errors.New("Meet invalid cache driver") } if err != nil { - //Just logged + // Just logged hlog.Errorf("Failed to cache chart object with error: %s\n", err) hlog.Warningf("If cache driver is using 'redis', please check the related configurations or the network connection") } } } -//GetChart trys to retrieve it from the cache -//If hit, return the cached item; -//otherwise, nil object is returned +// GetChart trys to retrieve it from the cache +// If hit, return the cached item; +// otherwise, nil object is returned func (chc *ChartCache) GetChart(chartDigest string) *ChartVersionDetails { - //If cache is not enabled, do nothing + // If cache is not enabled, do nothing if !chc.IsEnabled() { return nil } object := chc.cache.Get(chartDigest) if object != nil { - //Try to convert data - //First try the normal way + // Try to convert data + // First try the normal way if chartDetails, ok := object.(*ChartVersionDetails); ok { return chartDetails } - //Maybe json bytes + // Maybe json bytes if bytes, yes := object.([]byte); yes { chartDetails := &ChartVersionDetails{} err := json.Unmarshal(bytes, chartDetails) if err == nil { return chartDetails } - //Just logged the error + // Just logged the error hlog.Errorf("Failed to retrieve chart from cache with error: %s", err) } } @@ -155,7 +155,7 @@ func (chc *ChartCache) GetChart(chartDigest string) *ChartVersionDetails { return nil } -//Initialize the cache driver based on the config +// Initialize the cache driver based on the config func initCacheDriver(cacheConfig *ChartCacheConfig) beego_cache.Cache { switch cacheConfig.DriverType { case cacheDriverMem: @@ -164,7 +164,7 @@ func initCacheDriver(cacheConfig *ChartCacheConfig) beego_cache.Cache { case cacheDriverRedis: redisCache, err := beego_cache.NewCache(cacheDriverRedis, cacheConfig.Config) if err != nil { - //Just logged + // Just logged hlog.Errorf("Failed to initialize redis cache: %s", err) return nil } @@ -175,7 +175,7 @@ func initCacheDriver(cacheConfig *ChartCacheConfig) beego_cache.Cache { break } - //Any other cases + // Any other cases hlog.Info("No cache is enabled for chart caching") return nil } diff --git a/src/chartserver/cache_test.go b/src/chartserver/cache_test.go index b3b9c4a4d..a9f765c58 100644 --- a/src/chartserver/cache_test.go +++ b/src/chartserver/cache_test.go @@ -22,7 +22,7 @@ var ( } ) -//Test the no cache set scenario +// Test the no cache set scenario func TestNoCache(t *testing.T) { chartCache := NewChartCache(nil) if chartCache == nil { @@ -34,7 +34,7 @@ func TestNoCache(t *testing.T) { } } -//Test the in memory cache +// Test the in memory cache func TestInMemoryCache(t *testing.T) { chartCache := NewChartCache(&ChartCacheConfig{ DriverType: cacheDriverMem, @@ -58,8 +58,8 @@ func TestInMemoryCache(t *testing.T) { } } -//Test redis cache -//Failed to config redis cache and then use in memory instead +// Test redis cache +// Failed to config redis cache and then use in memory instead func TestRedisCache(t *testing.T) { redisConfigV := make(map[string]string) redisConfigV["key"] = cacheCollectionName diff --git a/src/chartserver/chart_operator.go b/src/chartserver/chart_operator.go index aa5578766..563011359 100644 --- a/src/chartserver/chart_operator.go +++ b/src/chartserver/chart_operator.go @@ -21,7 +21,7 @@ const ( valuesFileName = "values.yaml" ) -//ChartVersionDetails keeps the detailed data info of the chart version +// ChartVersionDetails keeps the detailed data info of the chart version type ChartVersionDetails struct { Metadata *helm_repo.ChartVersion `json:"metadata"` Dependencies []*chartutil.Dependency `json:"dependencies"` @@ -30,19 +30,19 @@ type ChartVersionDetails struct { Security *SecurityReport `json:"security"` } -//SecurityReport keeps the info related with security -//e.g.: digital signature, vulnerability scanning etc. +// SecurityReport keeps the info related with security +// e.g.: digital signature, vulnerability scanning etc. type SecurityReport struct { Signature *DigitalSignature `json:"signature"` } -//DigitalSignature used to indicate if the chart has been signed +// DigitalSignature used to indicate if the chart has been signed type DigitalSignature struct { Signed bool `json:"signed"` Provenance string `json:"prov_file"` } -//ChartInfo keeps the information of the chart +// ChartInfo keeps the information of the chart type ChartInfo struct { Name string TotalVersions uint32 `json:"total_versions"` @@ -54,27 +54,27 @@ type ChartInfo struct { Deprecated bool } -//ChartOperator is designed to process the contents of -//the specified chart version to get more details +// ChartOperator is designed to process the contents of +// the specified chart version to get more details type ChartOperator struct{} -//GetChartDetails parse the details from the provided content bytes +// GetChartDetails parse the details from the provided content bytes func (cho *ChartOperator) GetChartDetails(content []byte) (*ChartVersionDetails, error) { if content == nil || len(content) == 0 { return nil, errors.New("zero content") } - //Load chart from in-memory content + // Load chart from in-memory content reader := bytes.NewReader(content) chartData, err := chartutil.LoadArchive(reader) if err != nil { return nil, err } - //Parse the requirements of chart + // Parse the requirements of chart requirements, err := chartutil.LoadRequirements(chartData) if err != nil { - //If no requirements.yaml, return empty dependency list + // If no requirements.yaml, return empty dependency list if _, ok := err.(chartutil.ErrNoRequirementsFile); ok { requirements = &chartutil.Requirements{ Dependencies: make([]*chartutil.Dependency, 0), @@ -86,16 +86,16 @@ func (cho *ChartOperator) GetChartDetails(content []byte) (*ChartVersionDetails, var values map[string]interface{} files := make(map[string]string) - //Parse values + // Parse values if chartData.Values != nil { values = parseRawValues([]byte(chartData.Values.GetRaw())) if len(values) > 0 { - //Append values.yaml file + // Append values.yaml file files[valuesFileName] = chartData.Values.Raw } } - //Append other files like 'README.md' + // Append other files like 'README.md' for _, v := range chartData.GetFiles() { if v.TypeUrl == readmeFileName { files[readmeFileName] = string(v.GetValue()) @@ -112,7 +112,7 @@ func (cho *ChartOperator) GetChartDetails(content []byte) (*ChartVersionDetails, return theChart, nil } -//GetChartList returns a reorganized chart list +// GetChartList returns a reorganized chart list func (cho *ChartOperator) GetChartList(content []byte) ([]*ChartInfo, error) { if content == nil || len(content) == 0 { return nil, errors.New("zero content") @@ -140,8 +140,8 @@ func (cho *ChartOperator) GetChartList(content []byte) ([]*ChartInfo, error) { } } - //Sort the chart list by the updated time which is the create time - //of the latest version of the chart. + // Sort the chart list by the updated time which is the create time + // of the latest version of the chart. sort.Slice(chartList, func(i, j int) bool { if chartList[i].Updated.Equal(chartList[j].Updated) { return strings.Compare(chartList[i].Name, chartList[j].Name) < 0 @@ -153,7 +153,7 @@ func (cho *ChartOperator) GetChartList(content []byte) ([]*ChartInfo, error) { return chartList, nil } -//GetChartVersions returns the chart versions +// GetChartVersions returns the chart versions func (cho *ChartOperator) GetChartVersions(content []byte) (helm_repo.ChartVersions, error) { if content == nil || len(content) == 0 { return nil, errors.New("zero content") @@ -167,7 +167,7 @@ func (cho *ChartOperator) GetChartVersions(content []byte) (helm_repo.ChartVersi return chartVersions, nil } -//Get the latest and oldest chart versions +// Get the latest and oldest chart versions func getTheTwoCharts(chartVersions helm_repo.ChartVersions) (latestChart *helm_repo.ChartVersion, oldestChart *helm_repo.ChartVersion) { if len(chartVersions) == 1 { return chartVersions[0], chartVersions[0] @@ -176,18 +176,18 @@ func getTheTwoCharts(chartVersions helm_repo.ChartVersions) (latestChart *helm_r for _, chartVersion := range chartVersions { currentV, err := semver.NewVersion(chartVersion.Version) if err != nil { - //ignore it, just logged + // ignore it, just logged hlog.Warningf("Malformed semversion %s for the chart %s", chartVersion.Version, chartVersion.Name) continue } - //Find latest chart + // Find latest chart if latestChart == nil { latestChart = chartVersion } else { lVersion, err := semver.NewVersion(latestChart.Version) if err != nil { - //ignore it, just logged + // ignore it, just logged hlog.Warningf("Malformed semversion %s for the chart %s", latestChart.Version, chartVersion.Name) continue } @@ -208,7 +208,7 @@ func getTheTwoCharts(chartVersions helm_repo.ChartVersions) (latestChart *helm_r return latestChart, oldestChart } -//Parse the raw values to value map +// Parse the raw values to value map func parseRawValues(rawValue []byte) map[string]interface{} { valueMap := make(map[string]interface{}) @@ -226,7 +226,7 @@ func parseRawValues(rawValue []byte) map[string]interface{} { return valueMap } -//Recursively read value +// Recursively read value func readValue(values map[string]interface{}, keyPrefix string, valueMap map[string]interface{}) { for key, value := range values { longKey := key diff --git a/src/chartserver/client.go b/src/chartserver/client.go index ac09c7e1d..b0c5ff7fe 100644 --- a/src/chartserver/client.go +++ b/src/chartserver/client.go @@ -17,18 +17,18 @@ const ( idleConnectionTimeout = 30 * time.Second ) -//ChartClient is a http client to get the content from the external http server +// ChartClient is a http client to get the content from the external http server type ChartClient struct { - //HTTP client + // HTTP client httpClient *http.Client - //Auth info + // Auth info credentail *Credential } -//NewChartClient is constructor of ChartClient -//credentail can be nil -func NewChartClient(credentail *Credential) *ChartClient { //Create http client with customized timeouts +// NewChartClient is constructor of ChartClient +// credentail can be nil +func NewChartClient(credentail *Credential) *ChartClient { // Create http client with customized timeouts client := &http.Client{ Timeout: clientTimeout, Transport: &http.Transport{ @@ -43,7 +43,7 @@ func NewChartClient(credentail *Credential) *ChartClient { //Create http client } } -//GetContent get the bytes from the specified url +// GetContent get the bytes from the specified url func (cc *ChartClient) GetContent(addr string) ([]byte, error) { response, err := cc.sendRequest(addr, http.MethodGet, nil, []int{http.StatusOK}) if err != nil { @@ -59,13 +59,13 @@ func (cc *ChartClient) GetContent(addr string) ([]byte, error) { return content, nil } -//DeleteContent sends deleting request to the addr to delete content +// DeleteContent sends deleting request to the addr to delete content func (cc *ChartClient) DeleteContent(addr string) error { _, err := cc.sendRequest(addr, http.MethodDelete, nil, []int{http.StatusOK}) return err } -//sendRequest sends requests to the addr with the specified spec +// sendRequest sends requests to the addr with the specified spec func (cc *ChartClient) sendRequest(addr string, method string, body io.Reader, expectedCodes []int) (*http.Response, error) { if len(strings.TrimSpace(addr)) == 0 { return nil, errors.New("empty url is not allowed") @@ -81,7 +81,7 @@ func (cc *ChartClient) sendRequest(addr string, method string, body io.Reader, e return nil, err } - //Set basic auth + // Set basic auth if cc.credentail != nil { request.SetBasicAuth(cc.credentail.Username, cc.credentail.Password) } diff --git a/src/chartserver/controller.go b/src/chartserver/controller.go index f4a4ffe90..6603047aa 100644 --- a/src/chartserver/controller.go +++ b/src/chartserver/controller.go @@ -15,58 +15,58 @@ const ( passwordKey = "UI_SECRET" ) -//Credential keeps the username and password for the basic auth +// Credential keeps the username and password for the basic auth type Credential struct { Username string Password string } -//Controller is used to handle flows of related requests based on the corresponding handlers -//A reverse proxy will be created and managed to proxy the related traffics between API and -//backend chart server +// Controller is used to handle flows of related requests based on the corresponding handlers +// A reverse proxy will be created and managed to proxy the related traffics between API and +// backend chart server type Controller struct { - //The access endpoint of the backend chart repository server + // The access endpoint of the backend chart repository server backendServerAddr *url.URL - //To cover the server info and status requests + // To cover the server info and status requests baseHandler *BaseHandler - //To cover the chart repository requests + // To cover the chart repository requests repositoryHandler *RepositoryHandler - //To cover all the manipulation requests + // To cover all the manipulation requests manipulationHandler *ManipulationHandler - //To cover the other utility requests + // To cover the other utility requests utilityHandler *UtilityHandler } -//NewController is constructor of the chartserver.Controller +// NewController is constructor of the chartserver.Controller func NewController(backendServer *url.URL) (*Controller, error) { if backendServer == nil { return nil, errors.New("failed to create chartserver.Controller: backend sever address is required") } - //Try to create credential + // Try to create credential cred := &Credential{ Username: userName, Password: os.Getenv(passwordKey), } - //Use customized reverse proxy + // Use customized reverse proxy proxy := NewProxyEngine(backendServer, cred) - //Create http client with customized timeouts + // Create http client with customized timeouts client := NewChartClient(cred) - //Initialize chart operator for use + // Initialize chart operator for use operator := &ChartOperator{} - //Creat cache + // Creat cache cacheCfg, err := getCacheConfig() if err != nil { - //just log the error - //will not break the whole flow if failed to create cache + // just log the error + // will not break the whole flow if failed to create cache hlog.Errorf("failed to get cache configuration with error: %s", err) } cache := NewChartCache(cacheCfg) @@ -97,33 +97,33 @@ func NewController(backendServer *url.URL) (*Controller, error) { }, nil } -//GetBaseHandler returns the reference of BaseHandler +// GetBaseHandler returns the reference of BaseHandler func (c *Controller) GetBaseHandler() *BaseHandler { return c.baseHandler } -//GetRepositoryHandler returns the reference of RepositoryHandler +// GetRepositoryHandler returns the reference of RepositoryHandler func (c *Controller) GetRepositoryHandler() *RepositoryHandler { return c.repositoryHandler } -//GetManipulationHandler returns the reference of ManipulationHandler +// GetManipulationHandler returns the reference of ManipulationHandler func (c *Controller) GetManipulationHandler() *ManipulationHandler { return c.manipulationHandler } -//GetUtilityHandler returns the reference of UtilityHandler +// GetUtilityHandler returns the reference of UtilityHandler func (c *Controller) GetUtilityHandler() *UtilityHandler { return c.utilityHandler } -//What's the cache driver if it is set +// What's the cache driver if it is set func parseCacheDriver() (string, bool) { driver, ok := os.LookupEnv(cacheDriverENVKey) return strings.ToLower(driver), ok } -//Get and parse the configuration for the chart cache +// Get and parse the configuration for the chart cache func getCacheConfig() (*ChartCacheConfig, error) { driver, isSet := parseCacheDriver() if !isSet { diff --git a/src/chartserver/controller_test.go b/src/chartserver/controller_test.go index be86f45a7..4a83ae4cb 100644 --- a/src/chartserver/controller_test.go +++ b/src/chartserver/controller_test.go @@ -12,14 +12,14 @@ import ( helm_repo "k8s.io/helm/pkg/repo" ) -//Prepare, start the mock servers +// Prepare, start the mock servers func TestStartServers(t *testing.T) { if err := startMockServers(); err != nil { t.Fatal(err) } } -//Test /health +// Test /health func TestGetHealthOfBaseHandler(t *testing.T) { content, err := httpClient.GetContent(fmt.Sprintf("%s/health", getTheAddrOfFrontServer())) if err != nil { @@ -36,7 +36,7 @@ func TestGetHealthOfBaseHandler(t *testing.T) { } } -//Get /repo1/index.yaml +// Get /repo1/index.yaml func TestGetIndexYamlByRepo(t *testing.T) { indexFile, err := getIndexYaml("/repo1/index.yaml") if err != nil { @@ -48,7 +48,7 @@ func TestGetIndexYamlByRepo(t *testing.T) { } } -//Test get /index.yaml +// Test get /index.yaml func TestGetUnifiedYamlFile(t *testing.T) { indexFile, err := getIndexYaml("/index.yaml") if err != nil { @@ -70,8 +70,8 @@ func TestGetUnifiedYamlFile(t *testing.T) { } } -//Test download /:repo/charts/chart.tar -//Use this case to test the proxy function +// Test download /:repo/charts/chart.tar +// Use this case to test the proxy function func TestDownloadChart(t *testing.T) { content, err := httpClient.GetContent(fmt.Sprintf("%s/repo1/charts/harbor-0.2.0.tgz", getTheAddrOfFrontServer())) if err != nil { @@ -86,7 +86,7 @@ func TestDownloadChart(t *testing.T) { } } -//Test get /api/:repo/charts +// Test get /api/:repo/charts func TestRetrieveChartList(t *testing.T) { content, err := httpClient.GetContent(fmt.Sprintf("%s/api/repo1/charts", getTheAddrOfFrontServer())) if err != nil { @@ -116,7 +116,7 @@ func TestRetrieveChartList(t *testing.T) { } } -//Test get /api/:repo/charts/:chart_name/:version +// Test get /api/:repo/charts/:chart_name/:version func TestGetChartVersion(t *testing.T) { content, err := httpClient.GetContent(fmt.Sprintf("%s/api/repo1/charts/harbor/0.2.0", getTheAddrOfFrontServer())) if err != nil { @@ -145,7 +145,7 @@ func TestGetChartVersion(t *testing.T) { } } -//Test get /api/:repo/charts/:chart_name/:version with none-existing version +// Test get /api/:repo/charts/:chart_name/:version with none-existing version func TestGetChartVersionWithError(t *testing.T) { _, err := httpClient.GetContent(fmt.Sprintf("%s/api/repo1/charts/harbor/1.0.0", getTheAddrOfFrontServer())) if err == nil { @@ -153,8 +153,8 @@ func TestGetChartVersionWithError(t *testing.T) { } } -//Get /api/repo1/charts/harbor -//401 will be rewritten to 500 with specified error +// Get /api/repo1/charts/harbor +// 401 will be rewritten to 500 with specified error func TestResponseRewrite(t *testing.T) { response, err := http.Get(fmt.Sprintf("%s/api/repo1/charts/harbor", getTheAddrOfFrontServer())) if err != nil { @@ -185,12 +185,12 @@ func TestResponseRewrite(t *testing.T) { } } -//Clear environments +// Clear environments func TestStopServers(t *testing.T) { stopMockServers() } -//Utility method for getting index yaml file +// Utility method for getting index yaml file func getIndexYaml(path string) (*helm_repo.IndexFile, error) { content, err := httpClient.GetContent(fmt.Sprintf("%s%s", getTheAddrOfFrontServer(), path)) if err != nil { diff --git a/src/chartserver/manipulation_handler.go b/src/chartserver/manipulation_handler.go index a27a29391..c21c9a449 100644 --- a/src/chartserver/manipulation_handler.go +++ b/src/chartserver/manipulation_handler.go @@ -15,34 +15,34 @@ import ( ) const ( - //NamespaceContextKey is context key for the namespace + // NamespaceContextKey is context key for the namespace NamespaceContextKey ContextKey = ":repo" ) -//ContextKey is defined for add value in the context of http request +// ContextKey is defined for add value in the context of http request type ContextKey string -//ManipulationHandler includes all the handler methods for the purpose of manipulating the -//chart repository +// ManipulationHandler includes all the handler methods for the purpose of manipulating the +// chart repository type ManipulationHandler struct { - //Proxy used to to transfer the traffic of requests - //It's mainly used to talk to the backend chart server + // Proxy used to to transfer the traffic of requests + // It's mainly used to talk to the backend chart server trafficProxy *ProxyEngine - //Parse and process the chart version to provide required info data + // Parse and process the chart version to provide required info data chartOperator *ChartOperator - //HTTP client used to call the realted APIs of the backend chart repositories + // HTTP client used to call the realted APIs of the backend chart repositories apiClient *ChartClient - //Point to the url of the backend server + // Point to the url of the backend server backendServerAddress *url.URL - //Cache the chart data + // Cache the chart data chartCache *ChartCache } -//ListCharts lists all the charts under the specified namespace +// ListCharts lists all the charts under the specified namespace func (mh *ManipulationHandler) ListCharts(w http.ResponseWriter, req *http.Request) { url := strings.TrimPrefix(req.URL.String(), "/") url = fmt.Sprintf("%s/%s", mh.backendServerAddress.String(), url) @@ -68,14 +68,14 @@ func (mh *ManipulationHandler) ListCharts(w http.ResponseWriter, req *http.Reque writeJSONData(w, jsonData) } -//GetChart returns all the chart versions under the specified chart +// GetChart returns all the chart versions under the specified chart func (mh *ManipulationHandler) GetChart(w http.ResponseWriter, req *http.Request) { mh.trafficProxy.ServeHTTP(w, req) } -//GetChartVersion get the specified version for one chart -//This handler should return the details of the chart version, -//maybe including metadata,dependencies and values etc. +// GetChartVersion get the specified version for one chart +// This handler should return the details of the chart version, +// maybe including metadata,dependencies and values etc. func (mh *ManipulationHandler) GetChartVersion(w http.ResponseWriter, req *http.Request) { chartV, err := mh.getChartVersion(req.URL.String()) if err != nil { @@ -83,8 +83,8 @@ func (mh *ManipulationHandler) GetChartVersion(w http.ResponseWriter, req *http. return } - //Get and check namespace - //even we get the data from cache + // Get and check namespace + // even we get the data from cache var namespace string repoValue := req.Context().Value(NamespaceContextKey) @@ -99,17 +99,17 @@ func (mh *ManipulationHandler) GetChartVersion(w http.ResponseWriter, req *http. return } - //Query cache + // Query cache chartDetails := mh.chartCache.GetChart(chartV.Digest) if chartDetails == nil { - //NOT hit!! + // NOT hit!! content, err := mh.getChartVersionContent(namespace, chartV.URLs[0]) if err != nil { WriteInternalError(w, err) return } - //Process bytes and get more details of chart version + // Process bytes and get more details of chart version chartDetails, err = mh.chartOperator.GetChartDetails(content) if err != nil { WriteInternalError(w, err) @@ -117,35 +117,35 @@ func (mh *ManipulationHandler) GetChartVersion(w http.ResponseWriter, req *http. } chartDetails.Metadata = chartV - //Put it into the cache for next access + // Put it into the cache for next access mh.chartCache.PutChart(chartDetails) } else { - //Just logged + // Just logged hlog.Debugf("Get detailed data from cache for chart: %s:%s (%s)", chartDetails.Metadata.Name, chartDetails.Metadata.Version, chartDetails.Metadata.Digest) } - //The change of prov file will not cause any influence to the digest of chart, - //and then the digital signature status should be not cached + // The change of prov file will not cause any influence to the digest of chart, + // and then the digital signature status should be not cached // - //Generate the security report - //prov file share same endpoint with the chart version - //Just add .prov suffix to the chart version to form the path of prov file - //Anyway, there will be a report about the digital signature status + // Generate the security report + // prov file share same endpoint with the chart version + // Just add .prov suffix to the chart version to form the path of prov file + // Anyway, there will be a report about the digital signature status chartDetails.Security = &SecurityReport{ Signature: &DigitalSignature{ Signed: false, }, } - //Try to get the prov file to confirm if it is exitsing + // Try to get the prov file to confirm if it is exitsing provFilePath := fmt.Sprintf("%s.prov", chartV.URLs[0]) provBytes, err := mh.getChartVersionContent(namespace, provFilePath) if err == nil && len(provBytes) > 0 { chartDetails.Security.Signature.Signed = true chartDetails.Security.Signature.Provenance = provFilePath } else { - //Just log it + // Just log it hlog.Errorf("Failed to get prov file for chart %s with error: %s, got %d bytes", chartV.Name, err.Error(), len(provBytes)) } @@ -158,22 +158,22 @@ func (mh *ManipulationHandler) GetChartVersion(w http.ResponseWriter, req *http. writeJSONData(w, bytes) } -//UploadChartVersion will save the new version of the chart to the backend storage +// UploadChartVersion will save the new version of the chart to the backend storage func (mh *ManipulationHandler) UploadChartVersion(w http.ResponseWriter, req *http.Request) { mh.trafficProxy.ServeHTTP(w, req) } -//UploadProvenanceFile will save the provenance file of the chart to the backend storage +// UploadProvenanceFile will save the provenance file of the chart to the backend storage func (mh *ManipulationHandler) UploadProvenanceFile(w http.ResponseWriter, req *http.Request) { mh.trafficProxy.ServeHTTP(w, req) } -//DeleteChartVersion will delete the specified version of the chart +// DeleteChartVersion will delete the specified version of the chart func (mh *ManipulationHandler) DeleteChartVersion(w http.ResponseWriter, req *http.Request) { mh.trafficProxy.ServeHTTP(w, req) } -//Get the basic metadata of chart version +// Get the basic metadata of chart version func (mh *ManipulationHandler) getChartVersion(subPath string) (*helm_repo.ChartVersion, error) { url := fmt.Sprintf("%s/%s", mh.backendServerAddress.String(), strings.TrimPrefix(subPath, "/")) @@ -190,7 +190,7 @@ func (mh *ManipulationHandler) getChartVersion(subPath string) (*helm_repo.Chart return chartVersion, nil } -//Get the content bytes of the chart version +// Get the content bytes of the chart version func (mh *ManipulationHandler) getChartVersionContent(namespace string, subPath string) ([]byte, error) { url := path.Join(namespace, subPath) url = fmt.Sprintf("%s/%s", mh.backendServerAddress.String(), url) diff --git a/src/chartserver/repo_handler.go b/src/chartserver/repo_handler.go index 853826b0c..b640e3995 100644 --- a/src/chartserver/repo_handler.go +++ b/src/chartserver/repo_handler.go @@ -22,62 +22,62 @@ const ( maxWorkers = 10 ) -//RepositoryHandler defines all the handlers to handle the requests related with chart repository -//e.g: index.yaml and downloading chart objects +// RepositoryHandler defines all the handlers to handle the requests related with chart repository +// e.g: index.yaml and downloading chart objects type RepositoryHandler struct { - //Proxy used to to transfer the traffic of requests - //It's mainly used to talk to the backend chart server + // Proxy used to to transfer the traffic of requests + // It's mainly used to talk to the backend chart server trafficProxy *ProxyEngine - //HTTP client used to call the realted APIs of the backend chart repositories + // HTTP client used to call the realted APIs of the backend chart repositories apiClient *ChartClient - //Point to the url of the backend server + // Point to the url of the backend server backendServerAddress *url.URL } -//Pass work to the workers -//'index' is the location of processing namespace/project in the list +// Pass work to the workers +// 'index' is the location of processing namespace/project in the list type workload struct { index uint32 } -//Result returned by worker +// Result returned by worker type processedResult struct { namespace string indexFileOfRepo *helm_repo.IndexFile } -//GetIndexFileWithNS will read the index.yaml data under the specified namespace +// GetIndexFileWithNS will read the index.yaml data under the specified namespace func (rh *RepositoryHandler) GetIndexFileWithNS(w http.ResponseWriter, req *http.Request) { rh.trafficProxy.ServeHTTP(w, req) } -//GetIndexFile will read the index.yaml under all namespaces and merge them as a single one -//Please be aware that, to support this function, the backend chart repository server should -//enable multi-tenancies +// GetIndexFile will read the index.yaml under all namespaces and merge them as a single one +// Please be aware that, to support this function, the backend chart repository server should +// enable multi-tenancies func (rh *RepositoryHandler) GetIndexFile(w http.ResponseWriter, req *http.Request) { - //Get project manager references + // Get project manager references projectMgr, err := filter.GetProjectManager(req) if err != nil { WriteInternalError(w, err) return } - //Get all the projects + // Get all the projects results, err := projectMgr.List(nil) if err != nil { WriteInternalError(w, err) return } - //If no projects existing, return empty index.yaml content immediately + // If no projects existing, return empty index.yaml content immediately if results.Total == 0 { w.Write(emptyIndexFile()) return } - //The final merged index file + // The final merged index file mergedIndexFile := &helm_repo.IndexFile{ APIVersion: "v1", Entries: make(map[string]helm_repo.ChartVersions), @@ -85,20 +85,20 @@ func (rh *RepositoryHandler) GetIndexFile(w http.ResponseWriter, req *http.Reque PublicKeys: []string{}, } - //Retrieve index.yaml for repositories + // Retrieve index.yaml for repositories workerPool := make(chan *workload, maxWorkers) - //Sync the output results from the retriever + // Sync the output results from the retriever resultChan := make(chan *processedResult, 1) - //Receive error + // Receive error errorChan := make(chan error, 1) - //Signal chan for merging work + // Signal chan for merging work mergeDone := make(chan struct{}, 1) - //Total projects/namespaces + // Total projects/namespaces total := uint32(results.Total) - //Track all the background threads + // Track all the background threads waitGroup := new(sync.WaitGroup) - //Initialize + // Initialize initialItemCount := maxWorkers if total < maxWorkers { initialItemCount = int(total) @@ -107,11 +107,11 @@ func (rh *RepositoryHandler) GetIndexFile(w http.ResponseWriter, req *http.Reque workerPool <- &workload{uint32(i)} } - //Atomtic index + // Atomtic index var indexRef uint32 atomic.AddUint32(&indexRef, uint32(initialItemCount-1)) - //Start the index files merging thread + // Start the index files merging thread go func() { defer func() { mergeDone <- struct{}{} @@ -122,8 +122,8 @@ func (rh *RepositoryHandler) GetIndexFile(w http.ResponseWriter, req *http.Reque } }() - //Retrieve the index files for the repositories - //and blocking here + // Retrieve the index files for the repositories + // and blocking here LOOP: for { select { @@ -131,16 +131,16 @@ LOOP: if work.index >= total { break LOOP } - //Process - //New one + // Process + // New one waitGroup.Add(1) namespace := results.Projects[work.index].Name go func(ns string) { - //Return the worker back to the pool + // Return the worker back to the pool defer func() { - waitGroup.Done() //done + waitGroup.Done() // done - //Put one. The invalid index will be treated as a signal to quit loop + // Put one. The invalid index will be treated as a signal to quit loop nextOne := atomic.AddUint32(&indexRef, 1) workerPool <- &workload{nextOne} }() @@ -151,39 +151,39 @@ LOOP: return } - //Output + // Output resultChan <- &processedResult{ namespace: ns, indexFileOfRepo: indexFile, } }(namespace) case err = <-errorChan: - //Quit earlier + // Quit earlier break LOOP case <-req.Context().Done(): - //Quit earlier + // Quit earlier err = errors.New("request of getting index yaml file is aborted") break LOOP } } - //Hold util all the retrieving work are done + // Hold util all the retrieving work are done waitGroup.Wait() - //close consumer channel + // close consumer channel close(resultChan) - //Wait until merging thread quit + // Wait until merging thread quit <-mergeDone - //All the threads are done - //Met an error + // All the threads are done + // Met an error if err != nil { WriteInternalError(w, err) return } - //Remove duplicated keys in public key list + // Remove duplicated keys in public key list hash := make(map[string]string) for _, key := range mergedIndexFile.PublicKeys { hash[key] = key @@ -202,15 +202,15 @@ LOOP: w.Write(bytes) } -//DownloadChartObject will download the stored chart object to the client -//e.g: helm install +// DownloadChartObject will download the stored chart object to the client +// e.g: helm install func (rh *RepositoryHandler) DownloadChartObject(w http.ResponseWriter, req *http.Request) { rh.trafficProxy.ServeHTTP(w, req) } -//Get the index yaml file under the specified namespace from the backend server +// Get the index yaml file under the specified namespace from the backend server func (rh *RepositoryHandler) getIndexYamlWithNS(namespace string) (*helm_repo.IndexFile, error) { - //Join url path + // Join url path url := path.Join(namespace, "index.yaml") url = fmt.Sprintf("%s/%s", rh.backendServerAddress.String(), url) hlog.Debugf("Getting index.yaml from '%s'", url) @@ -220,7 +220,7 @@ func (rh *RepositoryHandler) getIndexYamlWithNS(namespace string) (*helm_repo.In return nil, err } - //Traverse to index file object for merging + // Traverse to index file object for merging indexFile := helm_repo.NewIndexFile() if err := yaml.Unmarshal(content, indexFile); err != nil { return nil, err @@ -229,41 +229,41 @@ func (rh *RepositoryHandler) getIndexYamlWithNS(namespace string) (*helm_repo.In return indexFile, nil } -//Merge the content of mergingIndexFile to the baseIndex -//The chart url should be without --chart-url prefix +// Merge the content of mergingIndexFile to the baseIndex +// The chart url should be without --chart-url prefix func (rh *RepositoryHandler) mergeIndexFile(namespace string, baseIndex *helm_repo.IndexFile, mergingIndexFile *helm_repo.IndexFile) { - //Append entries + // Append entries for chartName, chartVersions := range mergingIndexFile.Entries { nameWithNS := fmt.Sprintf("%s/%s", namespace, chartName) for _, version := range chartVersions { version.Name = nameWithNS - //Currently there is only one url + // Currently there is only one url for index, url := range version.URLs { version.URLs[index] = path.Join(namespace, url) } } - //Appended + // Appended baseIndex.Entries[nameWithNS] = chartVersions } - //Update generated time + // Update generated time if mergingIndexFile.Generated.After(baseIndex.Generated) { baseIndex.Generated = mergingIndexFile.Generated } - //Merge public keys + // Merge public keys baseIndex.PublicKeys = append(baseIndex.PublicKeys, mergingIndexFile.PublicKeys...) } -//Generate empty index file +// Generate empty index file func emptyIndexFile() []byte { emptyIndexFile := &helm_repo.IndexFile{} emptyIndexFile.Generated = time.Now() - //Ignore the error + // Ignore the error rawData, _ := json.Marshal(emptyIndexFile) return rawData diff --git a/src/chartserver/reverse_proxy.go b/src/chartserver/reverse_proxy.go index d97e2ff5f..e83ed8919 100644 --- a/src/chartserver/reverse_proxy.go +++ b/src/chartserver/reverse_proxy.go @@ -19,17 +19,17 @@ const ( contentLengthHeader = "Content-Length" ) -//ProxyEngine is used to proxy the related traffics +// ProxyEngine is used to proxy the related traffics type ProxyEngine struct { - //The backend target server the traffic will be forwarded to - //Just in case we'll use it + // The backend target server the traffic will be forwarded to + // Just in case we'll use it backend *url.URL - //Use go reverse proxy as engine + // Use go reverse proxy as engine engine *httputil.ReverseProxy } -//NewProxyEngine is constructor of NewProxyEngine +// NewProxyEngine is constructor of NewProxyEngine func NewProxyEngine(target *url.URL, cred *Credential) *ProxyEngine { return &ProxyEngine{ backend: target, @@ -43,17 +43,17 @@ func NewProxyEngine(target *url.URL, cred *Credential) *ProxyEngine { } } -//ServeHTTP serves the incoming http requests +// ServeHTTP serves the incoming http requests func (pe *ProxyEngine) ServeHTTP(w http.ResponseWriter, req *http.Request) { pe.engine.ServeHTTP(w, req) } -//Overwrite the http requests +// Overwrite the http requests func director(target *url.URL, cred *Credential, req *http.Request) { - //Closure + // Closure targetQuery := target.RawQuery - //Overwrite the request URL to the target path + // Overwrite the request URL to the target path req.URL.Scheme = target.Scheme req.URL.Host = target.Host req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path) @@ -66,28 +66,28 @@ func director(target *url.URL, cred *Credential, req *http.Request) { req.Header.Set("User-Agent", agentHarbor) } - //Add authentication header if it is existing + // Add authentication header if it is existing if cred != nil { req.SetBasicAuth(cred.Username, cred.Password) } } -//Modify the http response +// Modify the http response func modifyResponse(res *http.Response) error { - //Accept cases - //Success or redirect + // Accept cases + // Success or redirect if res.StatusCode >= http.StatusOK && res.StatusCode <= http.StatusTemporaryRedirect { return nil } - //Detect the 401 code, if it is,overwrite it to 500. - //We also re-write the error content to structural error object + // Detect the 401 code, if it is,overwrite it to 500. + // We also re-write the error content to structural error object errorObj := make(map[string]string) if res.StatusCode == http.StatusUnauthorized { errorObj["error"] = "operation request from unauthorized source is rejected" res.StatusCode = http.StatusInternalServerError } else { - //Extract the error and wrap it into the error object + // Extract the error and wrap it into the error object data, err := ioutil.ReadAll(res.Body) if err != nil { errorObj["error"] = fmt.Sprintf("%s: %s", res.Status, err.Error()) @@ -112,8 +112,8 @@ func modifyResponse(res *http.Response) error { return nil } -//Join the path -//Copy from the go reverse proxy +// Join the path +// Copy from the go reverse proxy func singleJoiningSlash(a, b string) string { aslash := strings.HasSuffix(a, "/") bslash := strings.HasPrefix(b, "/") diff --git a/src/chartserver/utility_handler.go b/src/chartserver/utility_handler.go index b20f8562f..1215a04d1 100644 --- a/src/chartserver/utility_handler.go +++ b/src/chartserver/utility_handler.go @@ -14,19 +14,19 @@ const ( maxDeletionThreads = 10 ) -//UtilityHandler provides utility methods +// UtilityHandler provides utility methods type UtilityHandler struct { - //Parse and process the chart version to provide required info data + // Parse and process the chart version to provide required info data chartOperator *ChartOperator - //HTTP client used to call the realted APIs of the backend chart repositories + // HTTP client used to call the realted APIs of the backend chart repositories apiClient *ChartClient - //Point to the url of the backend server + // Point to the url of the backend server backendServerAddress *url.URL } -//GetChartsByNs gets the chart list under the namespace +// GetChartsByNs gets the chart list under the namespace func (uh *UtilityHandler) GetChartsByNs(namespace string) ([]*ChartInfo, error) { if len(strings.TrimSpace(namespace)) == 0 { return nil, errors.New("empty namespace when getting chart list") @@ -43,7 +43,7 @@ func (uh *UtilityHandler) GetChartsByNs(namespace string) ([]*ChartInfo, error) return uh.chartOperator.GetChartList(content) } -//DeleteChart deletes all the chart versions of the specified chart under the namespace. +// DeleteChart deletes all the chart versions of the specified chart under the namespace. func (uh *UtilityHandler) DeleteChart(namespace, chartName string) error { if len(strings.TrimSpace(namespace)) == 0 { return errors.New("empty namespace when deleting chart") @@ -66,8 +66,8 @@ func (uh *UtilityHandler) DeleteChart(namespace, chartName string) error { return err } - //Let's delete the versions in parallel - //The number of goroutine is controlled by the const maxDeletionThreads + // Let's delete the versions in parallel + // The number of goroutine is controlled by the const maxDeletionThreads qSize := len(allVersions) if qSize > maxDeletionThreads { qSize = maxDeletionThreads @@ -77,17 +77,17 @@ func (uh *UtilityHandler) DeleteChart(namespace, chartName string) error { waitGroup := new(sync.WaitGroup) waitGroup.Add(len(allVersions)) - //Append initial tokens + // Append initial tokens for i := 0; i < qSize; i++ { tokenQueue <- struct{}{} } - //Collect errors + // Collect errors errs := make([]error, 0) errWrapper := make(chan error, 1) go func() { defer func() { - //pass to the out func + // pass to the out func if len(errs) > 0 { errWrapper <- fmt.Errorf("%v", errs) } @@ -99,19 +99,19 @@ func (uh *UtilityHandler) DeleteChart(namespace, chartName string) error { } }() - //Schedule deletion tasks + // Schedule deletion tasks for _, deletingVersion := range allVersions { - //Apply for token first - //If no available token, pending here + // Apply for token first + // If no available token, pending here <-tokenQueue - //Got one token + // Got one token go func(deletingVersion *helm_repo.ChartVersion) { defer func() { - //return the token back + // return the token back tokenQueue <- struct{}{} - //done + // done waitGroup.Done() }() @@ -121,9 +121,9 @@ func (uh *UtilityHandler) DeleteChart(namespace, chartName string) error { }(deletingVersion) } - //Wait all goroutines are done + // Wait all goroutines are done waitGroup.Wait() - //Safe to quit error collection goroutine + // Safe to quit error collection goroutine close(errChan) err = <-errWrapper @@ -131,7 +131,7 @@ func (uh *UtilityHandler) DeleteChart(namespace, chartName string) error { return err } -//deleteChartVersion deletes the specified chart version +// deleteChartVersion deletes the specified chart version func (uh *UtilityHandler) deleteChartVersion(namespace, chartName, version string) error { path := fmt.Sprintf("/api/%s/charts/%s/%s", namespace, chartName, version) url := fmt.Sprintf("%s%s", uh.backendServerAddress.String(), path) diff --git a/src/chartserver/utility_handler_test.go b/src/chartserver/utility_handler_test.go index 0fdb43497..d1bb2d1a7 100644 --- a/src/chartserver/utility_handler_test.go +++ b/src/chartserver/utility_handler_test.go @@ -7,7 +7,7 @@ import ( "testing" ) -//TestGetChartsByNs tests GetChartsByNs method in UtilityHandler +// TestGetChartsByNs tests GetChartsByNs method in UtilityHandler func TestGetChartsByNs(t *testing.T) { mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.RequestURI { @@ -43,7 +43,7 @@ func TestGetChartsByNs(t *testing.T) { } } -//Test the function DeleteChart +// Test the function DeleteChart func TestDeleteChart(t *testing.T) { mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.RequestURI { diff --git a/src/chartserver/utils.go b/src/chartserver/utils.go index 78aa0d919..6162d6610 100644 --- a/src/chartserver/utils.go +++ b/src/chartserver/utils.go @@ -14,7 +14,7 @@ const ( contentTypeJSON = "application/json" ) -//WriteError writes error to http client +// WriteError writes error to http client func WriteError(w http.ResponseWriter, code int, err error) { errorObj := make(map[string]string) errorObj["error"] = err.Error() @@ -26,20 +26,20 @@ func WriteError(w http.ResponseWriter, code int, err error) { w.Write(errorContent) } -//WriteInternalError writes error with statusCode == 500 +// WriteInternalError writes error with statusCode == 500 func WriteInternalError(w http.ResponseWriter, err error) { WriteError(w, http.StatusInternalServerError, err) } -//Write JSON data to http client +// Write JSON data to http client func writeJSONData(w http.ResponseWriter, data []byte) { w.Header().Set(contentTypeHeader, contentTypeJSON) w.WriteHeader(http.StatusOK) w.Write(data) } -//Extract error object '{"error": "****---***"}' from the content if existing -//nil error will be returned if it does exist +// Extract error object '{"error": "****---***"}' from the content if existing +// nil error will be returned if it does exist func extractError(content []byte) error { if len(content) == 0 { return nil @@ -58,8 +58,8 @@ func extractError(content []byte) error { return nil } -//Parse the redis configuration to the beego cache pattern -//Config pattern is "address:port[,weight,password,db_index]" +// Parse the redis configuration to the beego cache pattern +// Config pattern is "address:port[,weight,password,db_index]" func parseRedisConfig(redisConfigV string) (string, error) { if len(redisConfigV) == 0 { return "", errors.New("empty redis config") @@ -68,47 +68,47 @@ func parseRedisConfig(redisConfigV string) (string, error) { redisConfig := make(map[string]string) redisConfig["key"] = cacheCollectionName - //Try best to parse the configuration segments. - //If the related parts are missing, assign default value. - //The default database index for UI process is 0. + // Try best to parse the configuration segments. + // If the related parts are missing, assign default value. + // The default database index for UI process is 0. configSegments := strings.Split(redisConfigV, ",") for i, segment := range configSegments { if i > 3 { - //ignore useless segments + // ignore useless segments break } switch i { - //address:port + // address:port case 0: redisConfig["conn"] = segment - //password, may not exist + // password, may not exist case 2: redisConfig["password"] = segment - //database index, may not exist + // database index, may not exist case 3: redisConfig["dbNum"] = segment } } - //Assign default value + // Assign default value if len(redisConfig["dbNum"]) == 0 { redisConfig["dbNum"] = "0" } - //Try to validate the connection address + // Try to validate the connection address fullAddr := redisConfig["conn"] if strings.Index(fullAddr, "://") == -1 { - //Append schema + // Append schema fullAddr = fmt.Sprintf("redis://%s", fullAddr) } - //Validate it by url + // Validate it by url _, err := url.Parse(fullAddr) if err != nil { return "", err } - //Convert config map to string + // Convert config map to string cfgData, err := json.Marshal(redisConfig) if err != nil { return "", err diff --git a/src/chartserver/utils_test.go b/src/chartserver/utils_test.go index c678853ea..fba83321c 100644 --- a/src/chartserver/utils_test.go +++ b/src/chartserver/utils_test.go @@ -5,21 +5,21 @@ import ( "testing" ) -//Test the utility function parseRedisConfig +// Test the utility function parseRedisConfig func TestParseRedisConfig(t *testing.T) { - //Case 1: empty addr + // Case 1: empty addr redisAddr := "" if _, err := parseRedisConfig(redisAddr); err == nil { t.Fatal("expect non nil error but got nil one if addr is empty") } - //Case 2: short pattern, addr:port + // Case 2: short pattern, addr:port redisAddr = "redis:6379" if parsedConnStr, err := parseRedisConfig(redisAddr); err != nil { t.Fatalf("expect nil error but got non nil one if addr is short pattern: %s\n", parsedConnStr) } - //Case 3: long pattern but miss some parts + // Case 3: long pattern but miss some parts redisAddr = "redis:6379,100" if parsedConnStr, err := parseRedisConfig(redisAddr); err != nil { t.Fatalf("expect nil error but got non nil one if addr is long pattern with some parts missing: %s\n", parsedConnStr) @@ -29,7 +29,7 @@ func TestParseRedisConfig(t *testing.T) { } } - //Case 4: long pattern + // Case 4: long pattern redisAddr = "redis:6379,100,Passw0rd,1" if parsedConnStr, err := parseRedisConfig(redisAddr); err != nil { t.Fatal("expect nil error but got non nil one if addr is long pattern") diff --git a/src/common/const.go b/src/common/const.go index 4aa0d363e..7a7f499af 100644 --- a/src/common/const.go +++ b/src/common/const.go @@ -154,7 +154,7 @@ var ( ReadOnly, } - //value is default value + // value is default value HarborStringKeysMap = map[string]string{ AUTHMode: "db_auth", LDAPURL: "", diff --git a/src/common/dao/accesslog.go b/src/common/dao/accesslog.go index 2711efa02..c9a0fb4a5 100644 --- a/src/common/dao/accesslog.go +++ b/src/common/dao/accesslog.go @@ -38,7 +38,7 @@ func GetTotalOfAccessLogs(query *models.LogQueryParam) (int64, error) { return logQueryConditions(query).Count() } -//GetAccessLogs gets access logs according to different conditions +// GetAccessLogs gets access logs according to different conditions func GetAccessLogs(query *models.LogQueryParam) ([]models.AccessLog, error) { qs := logQueryConditions(query).OrderBy("-op_time") diff --git a/src/common/dao/base.go b/src/common/dao/base.go index 041048f3d..3cab37527 100644 --- a/src/common/dao/base.go +++ b/src/common/dao/base.go @@ -131,7 +131,7 @@ func ClearTable(table string) error { if table == models.UserTable { sql = fmt.Sprintf("delete from %s where user_id > 2", table) } - if table == "project_metadata" { //make sure library is public + if table == "project_metadata" { // make sure library is public sql = fmt.Sprintf("delete from %s where id > 1", table) } _, err := o.Raw(sql).Exec() @@ -152,7 +152,7 @@ func paginateForQuerySetter(qs orm.QuerySeter, page, size int64) orm.QuerySeter return qs } -//Escape .. +// Escape .. func Escape(str string) string { str = strings.Replace(str, `%`, `\%`, -1) str = strings.Replace(str, `_`, `\_`, -1) diff --git a/src/common/dao/clair.go b/src/common/dao/clair.go index 95a4cca8e..58f9de2d4 100644 --- a/src/common/dao/clair.go +++ b/src/common/dao/clair.go @@ -21,7 +21,7 @@ import ( "time" ) -//SetClairVulnTimestamp update the last_update of a namespace. If there's no record for this namespace, one will be created. +// SetClairVulnTimestamp update the last_update of a namespace. If there's no record for this namespace, one will be created. func SetClairVulnTimestamp(namespace string, timestamp time.Time) error { o := GetOrmer() rec := &models.ClairVulnTimestamp{ @@ -43,7 +43,7 @@ func SetClairVulnTimestamp(namespace string, timestamp time.Time) error { return nil } -//ListClairVulnTimestamps return a list of all records in vuln timestamp table. +// ListClairVulnTimestamps return a list of all records in vuln timestamp table. func ListClairVulnTimestamps() ([]*models.ClairVulnTimestamp, error) { var res []*models.ClairVulnTimestamp o := GetOrmer() diff --git a/src/common/dao/clair/base.go b/src/common/dao/clair/base.go index bd6d0f7f5..5b55fcc33 100644 --- a/src/common/dao/clair/base.go +++ b/src/common/dao/clair/base.go @@ -32,7 +32,7 @@ var ( once sync.Once ) -//GetOrmer return the singleton of Ormer for clair DB. +// GetOrmer return the singleton of Ormer for clair DB. func GetOrmer() orm.Ormer { once.Do(func() { dbInstance, err := orm.GetDB(dao.ClairDBAlias) @@ -47,7 +47,7 @@ func GetOrmer() orm.Ormer { return ormer } -//GetLastUpdate query the table `keyvalue` in clair's DB return the value of `updater/last` +// GetLastUpdate query the table `keyvalue` in clair's DB return the value of `updater/last` func GetLastUpdate() (int64, error) { var list orm.ParamsList num, err := GetOrmer().Raw("SELECT value from keyvalue where key=?", updaterLast).ValuesFlat(&list) @@ -60,7 +60,7 @@ func GetLastUpdate() (int64, error) { return 0, fmt.Errorf("The value: %v, is non-string", list[0]) } res, err := strconv.ParseInt(s, 0, 64) - if err != nil { //shouldn't be here. + if err != nil { // shouldn't be here. return 0, err } return res, nil @@ -68,6 +68,6 @@ func GetLastUpdate() (int64, error) { if num > 1 { return 0, fmt.Errorf("Multiple entries for %s in Clair DB", updaterLast) } - //num is zero, it's not updated yet. + // num is zero, it's not updated yet. return 0, nil } diff --git a/src/common/dao/dao_test.go b/src/common/dao/dao_test.go index 497bb23eb..03d9c2ad9 100644 --- a/src/common/dao/dao_test.go +++ b/src/common/dao/dao_test.go @@ -187,7 +187,7 @@ func TestRegister(t *testing.T) { t.Errorf("Error occurred in Register: %v", err) } - //Check if user registered successfully. + // Check if user registered successfully. queryUser := models.User{ Username: username, } @@ -567,7 +567,7 @@ func TestGetUserProjectRoles(t *testing.T) { t.Errorf("Error happened in GetUserProjectRole: %v, userID: %+v, project Id: %d", err, currentUser.UserID, currentProject.ProjectID) } - //Get the size of current user project role. + // Get the size of current user project role. if len(r) != 1 { t.Errorf("The user, id: %d, should only have one role in project, id: %d, but actual: %d", currentUser.UserID, currentProject.ProjectID, len(r)) } @@ -675,7 +675,7 @@ func TestAddRepTarget(t *testing.T) { Username: "admin", Password: "admin", } - //_, err := AddRepTarget(target) + // _, err := AddRepTarget(target) id, err := AddRepTarget(target) t.Logf("added target, id: %d", id) if err != nil { diff --git a/src/common/dao/group/usergroup.go b/src/common/dao/group/usergroup.go index 4e19358a1..eaddf0a6c 100644 --- a/src/common/dao/group/usergroup.go +++ b/src/common/dao/group/usergroup.go @@ -91,7 +91,7 @@ func DeleteUserGroup(id int) error { o := dao.GetOrmer() _, err := o.Delete(&userGroup) if err == nil { - //Delete all related project members + // Delete all related project members sql := `delete from project_member where entity_id = ? and entity_type='g'` _, err := o.Raw(sql, id).Exec() if err != nil { @@ -147,7 +147,7 @@ func GetGroupDNQueryCondition(userGroupList []*models.UserGroup) string { count++ } } - //No LDAP Group found + // No LDAP Group found if count == 0 { return "" } diff --git a/src/common/dao/group/usergroup_test.go b/src/common/dao/group/usergroup_test.go index ffd005f33..6455708fb 100644 --- a/src/common/dao/group/usergroup_test.go +++ b/src/common/dao/group/usergroup_test.go @@ -30,7 +30,7 @@ var createdUserGroupID int func TestMain(m *testing.M) { - //databases := []string{"mysql", "sqlite"} + // databases := []string{"mysql", "sqlite"} databases := []string{"postgresql"} for _, database := range databases { log.Infof("run test cases for database: %s", database) @@ -43,7 +43,7 @@ func TestMain(m *testing.M) { log.Fatalf("invalid database: %s", database) } - //Extract to test utils + // Extract to test utils initSqls := []string{ "insert into harbor_user (username, email, password, realname) values ('member_test_01', 'member_test_01@example.com', '123456', 'member_test_01')", "insert into project (name, owner_id) values ('member_test_01', 1)", diff --git a/src/common/dao/mysql.go b/src/common/dao/mysql.go index e16d015e5..7d5ef4a36 100644 --- a/src/common/dao/mysql.go +++ b/src/common/dao/mysql.go @@ -19,7 +19,7 @@ import ( "time" "github.com/astaxie/beego/orm" - _ "github.com/go-sql-driver/mysql" //register mysql driver + _ "github.com/go-sql-driver/mysql" // register mysql driver "github.com/goharbor/harbor/src/common/utils" ) diff --git a/src/common/dao/pgsql.go b/src/common/dao/pgsql.go index 6086225b7..77f4d01a2 100644 --- a/src/common/dao/pgsql.go +++ b/src/common/dao/pgsql.go @@ -20,12 +20,12 @@ import ( "github.com/astaxie/beego/orm" "github.com/golang-migrate/migrate" - _ "github.com/golang-migrate/migrate/database/postgres" //import pgsql driver for migrator + _ "github.com/golang-migrate/migrate/database/postgres" // import pgsql driver for migrator _ "github.com/golang-migrate/migrate/source/file" // import local file driver for migrator "github.com/goharbor/harbor/src/common/utils" "github.com/goharbor/harbor/src/common/utils/log" - _ "github.com/lib/pq" //register pgsql driver + _ "github.com/lib/pq" // register pgsql driver ) const defaultMigrationPath = "migrations/postgresql/" @@ -71,7 +71,7 @@ func NewPGSQL(host string, port string, usr string, pwd string, database string, } } -//Register registers pgSQL to orm with the info wrapped by the instance. +// Register registers pgSQL to orm with the info wrapped by the instance. func (p *pgsql) Register(alias ...string) error { if err := utils.TestTCPConn(fmt.Sprintf("%s:%s", p.host, p.port), 60, 2); err != nil { return err @@ -91,10 +91,10 @@ func (p *pgsql) Register(alias ...string) error { return orm.RegisterDataBase(an, "postgres", info) } -//UpgradeSchema calls migrate tool to upgrade schema to the latest based on the SQL scripts. +// UpgradeSchema calls migrate tool to upgrade schema to the latest based on the SQL scripts. func (p *pgsql) UpgradeSchema() error { dbURL := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=%s", p.usr, p.pwd, p.host, p.port, p.database, pgsqlSSLMode(p.sslmode)) - //For UT + // For UT path := os.Getenv("POSTGRES_MIGRATION_SCRIPTS_PATH") if len(path) == 0 { path = defaultMigrationPath @@ -114,7 +114,7 @@ func (p *pgsql) UpgradeSchema() error { err = m.Up() if err == migrate.ErrNoChange { log.Infof("No change in schema, skip.") - } else if err != nil { //migrate.ErrLockTimeout will be thrown when another process is doing migration and timeout. + } else if err != nil { // migrate.ErrLockTimeout will be thrown when another process is doing migration and timeout. log.Errorf("Failed to upgrade schema, error: %q", err) return err } diff --git a/src/common/dao/project.go b/src/common/dao/project.go index 37f9f4fbb..3b23b0d65 100644 --- a/src/common/dao/project.go +++ b/src/common/dao/project.go @@ -292,8 +292,8 @@ func GetRolesByLDAPGroup(projectID int64, groupDNCondition string) ([]int, error return roles, nil } o := GetOrmer() - //Because an LDAP user can be memberof multiple groups, - //the role is in descent order (1-admin, 2-developer, 3-guest), use min to select the max privilege role. + // Because an LDAP user can be memberof multiple groups, + // the role is in descent order (1-admin, 2-developer, 3-guest), use min to select the max privilege role. sql := fmt.Sprintf( `select min(pm.role) from project_member pm left join user_group ug on pm.entity_type = 'g' and pm.entity_id = ug.id @@ -304,7 +304,7 @@ func GetRolesByLDAPGroup(projectID int64, groupDNCondition string) ([]int, error log.Warningf("Error in GetRolesByLDAPGroup, error: %v", err) return nil, err } - //If there is no row selected, the min returns an empty row, to avoid return 0 as role + // If there is no row selected, the min returns an empty row, to avoid return 0 as role if len(roles) == 1 && roles[0] == 0 { return []int{}, nil } diff --git a/src/common/dao/project/projectmember_test.go b/src/common/dao/project/projectmember_test.go index c08039ea5..bc79cf06d 100644 --- a/src/common/dao/project/projectmember_test.go +++ b/src/common/dao/project/projectmember_test.go @@ -30,7 +30,7 @@ import ( func TestMain(m *testing.M) { - //databases := []string{"mysql", "sqlite"} + // databases := []string{"mysql", "sqlite"} databases := []string{"postgresql"} for _, database := range databases { log.Infof("run test cases for database: %s", database) @@ -43,7 +43,7 @@ func TestMain(m *testing.M) { log.Fatalf("invalid database: %s", database) } - //Extract to test utils + // Extract to test utils initSqls := []string{ "insert into harbor_user (username, email, password, realname) values ('member_test_01', 'member_test_01@example.com', '123456', 'member_test_01')", "insert into project (name, owner_id) values ('member_test_01', 1)", diff --git a/src/common/dao/repository.go b/src/common/dao/repository.go index df50d3eb2..b7942ca2e 100644 --- a/src/common/dao/repository.go +++ b/src/common/dao/repository.go @@ -91,13 +91,13 @@ func IncreasePullCount(name string) (err error) { return nil } -//RepositoryExists returns whether the repository exists according to its name. +// RepositoryExists returns whether the repository exists according to its name. func RepositoryExists(name string) bool { o := GetOrmer() return o.QueryTable("repository").Filter("name", name).Exist() } -//GetTopRepos returns the most popular repositories whose project ID is +// GetTopRepos returns the most popular repositories whose project ID is // in projectIDs func GetTopRepos(projectIDs []int64, n int) ([]*models.RepoRecord, error) { repositories := []*models.RepoRecord{} diff --git a/src/common/dao/sqlite.go b/src/common/dao/sqlite.go index 490f74b4e..3256c7689 100644 --- a/src/common/dao/sqlite.go +++ b/src/common/dao/sqlite.go @@ -18,7 +18,7 @@ import ( "fmt" "github.com/astaxie/beego/orm" - _ "github.com/mattn/go-sqlite3" //register sqlite driver + _ "github.com/mattn/go-sqlite3" // register sqlite driver ) type sqlite struct { diff --git a/src/common/dao/user.go b/src/common/dao/user.go index ecfa576e9..bded3305b 100644 --- a/src/common/dao/user.go +++ b/src/common/dao/user.go @@ -94,7 +94,7 @@ func LoginByDb(auth models.AuthModel) (*models.User, error) { return nil, nil } - user.Password = "" //do not return the password + user.Password = "" // do not return the password return &user, nil } @@ -244,7 +244,7 @@ func OnBoardUser(u *models.User) error { return nil } -//IsSuperUser checks if the user is super user(conventionally id == 1) of Harbor +// IsSuperUser checks if the user is super user(conventionally id == 1) of Harbor func IsSuperUser(username string) bool { u, err := GetUser(models.User{ Username: username, @@ -257,7 +257,7 @@ func IsSuperUser(username string) bool { return u != nil && u.UserID == 1 } -//CleanUser - Clean this user information from DB +// CleanUser - Clean this user information from DB func CleanUser(id int64) error { if _, err := GetOrmer().QueryTable(&models.User{}). Filter("UserID", id).Delete(); err != nil { diff --git a/src/common/job/client.go b/src/common/job/client.go index 326f6141d..1070ae735 100644 --- a/src/common/job/client.go +++ b/src/common/job/client.go @@ -17,7 +17,7 @@ type Client interface { SubmitJob(*models.JobData) (string, error) GetJobLog(uuid string) ([]byte, error) PostAction(uuid, action string) error - //TODO Redirect joblog when we see there's memory issue. + // TODO Redirect joblog when we see there's memory issue. } // DefaultClient is the default implementation of Client interface @@ -41,7 +41,7 @@ func NewDefaultClient(endpoint, secret string) *DefaultClient { } } -//SubmitJob call jobserivce API to submit a job and returns the job's UUID. +// SubmitJob call jobserivce API to submit a job and returns the job's UUID. func (d *DefaultClient) SubmitJob(jd *models.JobData) (string, error) { url := d.endpoint + "/api/v1/jobs" jq := models.JobRequest{ @@ -78,7 +78,7 @@ func (d *DefaultClient) SubmitJob(jd *models.JobData) (string, error) { return stats.Stats.JobID, nil } -//GetJobLog call jobserivce API to get the log of a job. It only accepts the UUID of the job +// GetJobLog call jobserivce API to get the log of a job. It only accepts the UUID of the job func (d *DefaultClient) GetJobLog(uuid string) ([]byte, error) { url := d.endpoint + "/api/v1/jobs/" + uuid + "/log" req, err := http.NewRequest(http.MethodGet, url, nil) diff --git a/src/common/job/const.go b/src/common/job/const.go index b495c81ac..9dd31d840 100644 --- a/src/common/job/const.go +++ b/src/common/job/const.go @@ -1,7 +1,7 @@ package job const ( - //ImageScanJob is name of scan job it will be used as key to register to job service. + // ImageScanJob is name of scan job it will be used as key to register to job service. ImageScanJob = "IMAGE_SCAN" // ImageTransfer : the name of image transfer job in job service ImageTransfer = "IMAGE_TRANSFER" @@ -12,26 +12,26 @@ const ( // ImageGC the name of image garbage collection job in job service ImageGC = "IMAGE_GC" - //JobKindGeneric : Kind of generic job + // JobKindGeneric : Kind of generic job JobKindGeneric = "Generic" - //JobKindScheduled : Kind of scheduled job + // JobKindScheduled : Kind of scheduled job JobKindScheduled = "Scheduled" - //JobKindPeriodic : Kind of periodic job + // JobKindPeriodic : Kind of periodic job JobKindPeriodic = "Periodic" - //JobServiceStatusPending : job status pending + // JobServiceStatusPending : job status pending JobServiceStatusPending = "Pending" - //JobServiceStatusRunning : job status running + // JobServiceStatusRunning : job status running JobServiceStatusRunning = "Running" - //JobServiceStatusStopped : job status stopped + // JobServiceStatusStopped : job status stopped JobServiceStatusStopped = "Stopped" - //JobServiceStatusCancelled : job status cancelled + // JobServiceStatusCancelled : job status cancelled JobServiceStatusCancelled = "Cancelled" - //JobServiceStatusError : job status error + // JobServiceStatusError : job status error JobServiceStatusError = "Error" - //JobServiceStatusSuccess : job status success + // JobServiceStatusSuccess : job status success JobServiceStatusSuccess = "Success" - //JobServiceStatusScheduled : job status scheduled + // JobServiceStatusScheduled : job status scheduled JobServiceStatusScheduled = "Scheduled" // JobActionStop : the action to stop the job diff --git a/src/common/job/models/models.go b/src/common/job/models/models.go index 46c0d9bac..3bbbe0b37 100644 --- a/src/common/job/models/models.go +++ b/src/common/job/models/models.go @@ -2,15 +2,15 @@ package models -//Parameters for job execution. +// Parameters for job execution. type Parameters map[string]interface{} -//JobRequest is the request of launching a job. +// JobRequest is the request of launching a job. type JobRequest struct { Job *JobData `json:"job"` } -//JobData keeps the basic info. +// JobData keeps the basic info. type JobData struct { Name string `json:"name"` Parameters Parameters `json:"parameters"` @@ -18,7 +18,7 @@ type JobData struct { StatusHook string `json:"status_hook"` } -//JobMetadata stores the metadata of job. +// JobMetadata stores the metadata of job. type JobMetadata struct { JobKind string `json:"kind"` ScheduleDelay uint64 `json:"schedule_delay,omitempty"` @@ -26,12 +26,12 @@ type JobMetadata struct { IsUnique bool `json:"unique"` } -//JobStats keeps the result of job launching. +// JobStats keeps the result of job launching. type JobStats struct { Stats *JobStatData `json:"job"` } -//JobStatData keeps the stats of job +// JobStatData keeps the stats of job type JobStatData struct { JobID string `json:"id"` Status string `json:"status"` @@ -49,12 +49,12 @@ type JobStatData struct { HookStatus string `json:"hook_status,omitempty"` } -//JobPoolStats represents the healthy and status of all the running worker pools. +// JobPoolStats represents the healthy and status of all the running worker pools. type JobPoolStats struct { Pools []*JobPoolStatsData `json:"worker_pools"` } -//JobPoolStatsData represent the healthy and status of the worker pool. +// JobPoolStatsData represent the healthy and status of the worker pool. type JobPoolStatsData struct { WorkerPoolID string `json:"worker_pool_id"` StartedAt int64 `json:"started_at"` @@ -64,20 +64,20 @@ type JobPoolStatsData struct { Status string `json:"status"` } -//JobActionRequest defines for triggering job action like stop/cancel. +// JobActionRequest defines for triggering job action like stop/cancel. type JobActionRequest struct { Action string `json:"action"` } -//JobStatusChange is designed for reporting the status change via hook. +// JobStatusChange is designed for reporting the status change via hook. type JobStatusChange struct { JobID string `json:"job_id"` Status string `json:"status"` CheckIn string `json:"check_in,omitempty"` } -//Message is designed for sub/pub messages +// Message is designed for sub/pub messages type Message struct { Event string - Data interface{} //generic format + Data interface{} // generic format } diff --git a/src/common/models/adminjob.go b/src/common/models/adminjob.go index c23eacf04..f4457970d 100644 --- a/src/common/models/adminjob.go +++ b/src/common/models/adminjob.go @@ -19,7 +19,7 @@ import ( ) const ( - //AdminJobTable is table name for admin job + // AdminJobTable is table name for admin job AdminJobTable = "admin_job" ) @@ -36,7 +36,7 @@ type AdminJob struct { UpdateTime time.Time `orm:"column(update_time);auto_now" json:"update_time"` } -//TableName is required by by beego orm to map AdminJob to table AdminJob +// TableName is required by by beego orm to map AdminJob to table AdminJob func (a *AdminJob) TableName() string { return AdminJobTable } diff --git a/src/common/models/clair.go b/src/common/models/clair.go index 27f9330e4..f35bbcb3b 100644 --- a/src/common/models/clair.go +++ b/src/common/models/clair.go @@ -29,12 +29,12 @@ type ClairVulnTimestamp struct { LastUpdateUTC int64 `orm:"-" json:"last_update"` } -//TableName is required by beego to map struct to table. +// TableName is required by beego to map struct to table. func (ct *ClairVulnTimestamp) TableName() string { return ClairVulnTimestampTable } -//ClairLayer ... +// ClairLayer ... type ClairLayer struct { Name string `json:"Name,omitempty"` NamespaceNames []string `json:"NamespaceNames,omitempty"` @@ -45,7 +45,7 @@ type ClairLayer struct { Features []ClairFeature `json:"Features,omitempty"` } -//ClairFeature ... +// ClairFeature ... type ClairFeature struct { Name string `json:"Name,omitempty"` NamespaceName string `json:"NamespaceName,omitempty"` @@ -55,7 +55,7 @@ type ClairFeature struct { AddedBy string `json:"AddedBy,omitempty"` } -//ClairVulnerability ... +// ClairVulnerability ... type ClairVulnerability struct { Name string `json:"Name,omitempty"` NamespaceName string `json:"NamespaceName,omitempty"` @@ -67,18 +67,18 @@ type ClairVulnerability struct { FixedIn []ClairFeature `json:"FixedIn,omitempty"` } -//ClairError ... +// ClairError ... type ClairError struct { Message string `json:"Message,omitempty"` } -//ClairLayerEnvelope ... +// ClairLayerEnvelope ... type ClairLayerEnvelope struct { Layer *ClairLayer `json:"Layer,omitempty"` Error *ClairError `json:"Error,omitempty"` } -//ClairNotification ... +// ClairNotification ... type ClairNotification struct { Name string `json:"Name,omitempty"` Created string `json:"Created,omitempty"` @@ -91,45 +91,45 @@ type ClairNotification struct { New *ClairVulnerabilityWithLayers `json:"New,omitempty"` } -//ClairNotificationEnvelope ... +// ClairNotificationEnvelope ... type ClairNotificationEnvelope struct { Notification *ClairNotification `json:"Notification,omitempty"` Error *ClairError `json:"Error,omitempty"` } -//ClairVulnerabilityWithLayers ... +// ClairVulnerabilityWithLayers ... type ClairVulnerabilityWithLayers struct { Vulnerability *ClairVulnerability `json:"Vulnerability,omitempty"` OrderedLayersIntroducingVulnerability []ClairOrderedLayerName `json:"OrderedLayersIntroducingVulnerability,omitempty"` } -//ClairOrderedLayerName ... +// ClairOrderedLayerName ... type ClairOrderedLayerName struct { Index int `json:"Index"` LayerName string `json:"LayerName"` } -//ClairVulnerabilityStatus reflects the readiness and freshness of vulnerability data in Clair, -//which will be returned in response of systeminfo API. +// ClairVulnerabilityStatus reflects the readiness and freshness of vulnerability data in Clair, +// which will be returned in response of systeminfo API. type ClairVulnerabilityStatus struct { OverallUTC int64 `json:"overall_last_update,omitempty"` Details []ClairNamespaceTimestamp `json:"details,omitempty"` } -//ClairNamespaceTimestamp is a record to store the clairname space and the timestamp, -//in practice different namespace in Clair maybe merged into one, e.g. ubuntu:14.04 and ubuntu:16.4 maybe merged into ubuntu and put into response. +// ClairNamespaceTimestamp is a record to store the clairname space and the timestamp, +// in practice different namespace in Clair maybe merged into one, e.g. ubuntu:14.04 and ubuntu:16.4 maybe merged into ubuntu and put into response. type ClairNamespaceTimestamp struct { Namespace string `json:"namespace"` Timestamp int64 `json:"last_update"` } -//ClairNamespace ... +// ClairNamespace ... type ClairNamespace struct { Name string `json:"Name,omitempty"` VersionFormat string `json:"VersionFormat,omitempty"` } -//ClairNamespaceEnvelope ... +// ClairNamespaceEnvelope ... type ClairNamespaceEnvelope struct { Namespaces *[]ClairNamespace `json:"Namespaces,omitempty"` Error *ClairError `json:"Error,omitempty"` diff --git a/src/common/models/job.go b/src/common/models/job.go index ef5a9a7e3..35cda3252 100644 --- a/src/common/models/job.go +++ b/src/common/models/job.go @@ -15,21 +15,21 @@ package models const ( - //JobPending ... + // JobPending ... JobPending string = "pending" - //JobRunning ... + // JobRunning ... JobRunning string = "running" - //JobError ... + // JobError ... JobError string = "error" - //JobStopped ... + // JobStopped ... JobStopped string = "stopped" - //JobFinished ... + // JobFinished ... JobFinished string = "finished" - //JobCanceled ... + // JobCanceled ... JobCanceled string = "canceled" - //JobRetrying indicate the job needs to be retried, it will be scheduled to the end of job queue by statemachine after an interval. + // JobRetrying indicate the job needs to be retried, it will be scheduled to the end of job queue by statemachine after an interval. JobRetrying string = "retrying" - //JobContinue is the status returned by statehandler to tell statemachine to move to next possible state based on trasition table. + // JobContinue is the status returned by statehandler to tell statemachine to move to next possible state based on trasition table. JobContinue string = "_continue" // JobScheduled ... JobScheduled string = "scheduled" diff --git a/src/common/models/ldap.go b/src/common/models/ldap.go index ce7793a44..18160ec1b 100644 --- a/src/common/models/ldap.go +++ b/src/common/models/ldap.go @@ -45,7 +45,7 @@ type LdapUser struct { GroupDNList []string `json:"ldap_groupdn"` } -//LdapImportUser ... +// LdapImportUser ... type LdapImportUser struct { LdapUIDList []string `json:"ldap_uid_list"` } diff --git a/src/common/models/pro_meta.go b/src/common/models/pro_meta.go index c623af64e..b75fa1efc 100644 --- a/src/common/models/pro_meta.go +++ b/src/common/models/pro_meta.go @@ -22,7 +22,7 @@ import ( const ( ProMetaPublic = "public" ProMetaEnableContentTrust = "enable_content_trust" - ProMetaPreventVul = "prevent_vul" //prevent vulnerable images from being pulled + ProMetaPreventVul = "prevent_vul" // prevent vulnerable images from being pulled ProMetaSeverity = "severity" ProMetaAutoScan = "auto_scan" SeverityNone = "negligible" diff --git a/src/common/models/project.go b/src/common/models/project.go index 63dfd595e..02418e88f 100644 --- a/src/common/models/project.go +++ b/src/common/models/project.go @@ -154,7 +154,7 @@ type BaseProjectCollection struct { // ProjectRequest holds informations that need for creating project API type ProjectRequest struct { Name string `json:"project_name"` - Public *int `json:"public"` //deprecated, reserved for project creation in replication + Public *int `json:"public"` // deprecated, reserved for project creation in replication Metadata map[string]string `json:"metadata"` } @@ -164,7 +164,7 @@ type ProjectQueryResult struct { Projects []*Project } -//TableName is required by beego orm to map Project to table project +// TableName is required by beego orm to map Project to table project func (p *Project) TableName() string { return ProjectTable } diff --git a/src/common/models/replication_job.go b/src/common/models/replication_job.go index a2b7ebbd6..9f1be5a3c 100644 --- a/src/common/models/replication_job.go +++ b/src/common/models/replication_job.go @@ -22,17 +22,17 @@ import ( ) const ( - //RepOpTransfer represents the operation of a job to transfer repository to a remote registry/harbor instance. + // RepOpTransfer represents the operation of a job to transfer repository to a remote registry/harbor instance. RepOpTransfer string = "transfer" - //RepOpDelete represents the operation of a job to remove repository from a remote registry/harbor instance. + // RepOpDelete represents the operation of a job to remove repository from a remote registry/harbor instance. RepOpDelete string = "delete" - //RepOpSchedule represents the operation of a job to schedule the real replication process + // RepOpSchedule represents the operation of a job to schedule the real replication process RepOpSchedule string = "schedule" - //RepTargetTable is the table name for replication targets + // RepTargetTable is the table name for replication targets RepTargetTable = "replication_target" - //RepJobTable is the table name for replication jobs + // RepJobTable is the table name for replication jobs RepJobTable = "replication_job" - //RepPolicyTable is table name for replication policies + // RepPolicyTable is table name for replication policies RepPolicyTable = "replication_policy" ) @@ -108,17 +108,17 @@ func (r *RepTarget) Valid(v *validation.Validation) { } } -//TableName is required by by beego orm to map RepTarget to table replication_target +// TableName is required by by beego orm to map RepTarget to table replication_target func (r *RepTarget) TableName() string { return RepTargetTable } -//TableName is required by by beego orm to map RepJob to table replication_job +// TableName is required by by beego orm to map RepJob to table replication_job func (r *RepJob) TableName() string { return RepJobTable } -//TableName is required by by beego orm to map RepPolicy to table replication_policy +// TableName is required by by beego orm to map RepPolicy to table replication_policy func (r *RepPolicy) TableName() string { return RepPolicyTable } diff --git a/src/common/models/repo.go b/src/common/models/repo.go index 1540e1282..d9bb3cce0 100644 --- a/src/common/models/repo.go +++ b/src/common/models/repo.go @@ -18,7 +18,7 @@ import ( "time" ) -//RepoTable is the table name for repository +// RepoTable is the table name for repository const RepoTable = "repository" // RepoRecord holds the record of an repository in DB, all the infors are from the registry notification event. @@ -33,7 +33,7 @@ type RepoRecord struct { UpdateTime time.Time `orm:"column(update_time);auto_now" json:"update_time"` } -//TableName is required by by beego orm to map RepoRecord to table repository +// TableName is required by by beego orm to map RepoRecord to table repository func (rp *RepoRecord) TableName() string { return RepoTable } diff --git a/src/common/models/role.go b/src/common/models/role.go index 209190f51..ec90a3eba 100644 --- a/src/common/models/role.go +++ b/src/common/models/role.go @@ -15,11 +15,11 @@ package models const ( - //PROJECTADMIN project administrator + // PROJECTADMIN project administrator PROJECTADMIN = 1 - //DEVELOPER developer + // DEVELOPER developer DEVELOPER = 2 - //GUEST guest + // GUEST guest GUEST = 3 ) diff --git a/src/common/models/scan_job.go b/src/common/models/scan_job.go index bc239e2db..497194d86 100644 --- a/src/common/models/scan_job.go +++ b/src/common/models/scan_job.go @@ -16,13 +16,13 @@ package models import "time" -//ScanJobTable is the name of the table whose data is mapped by ScanJob struct. +// ScanJobTable is the name of the table whose data is mapped by ScanJob struct. const ScanJobTable = "img_scan_job" -//ScanOverviewTable is the name of the table whose data is mapped by ImgScanOverview struct. +// ScanOverviewTable is the name of the table whose data is mapped by ImgScanOverview struct. const ScanOverviewTable = "img_scan_overview" -//ScanJob is the model to represent a job for image scan in DB. +// ScanJob is the model to represent a job for image scan in DB. type ScanJob struct { ID int64 `orm:"pk;auto;column(id)" json:"id"` Status string `orm:"column(status)" json:"status"` @@ -47,7 +47,7 @@ const ( SevHigh ) -//String is the output function for sererity variable +// String is the output function for sererity variable func (sev Severity) String() string { name := []string{"negligible", "unknown", "low", "medium", "high"} i := int64(sev) @@ -59,12 +59,12 @@ func (sev Severity) String() string { } } -//TableName is required by by beego orm to map ScanJob to table img_scan_job +// TableName is required by by beego orm to map ScanJob to table img_scan_job func (s *ScanJob) TableName() string { return ScanJobTable } -//ImgScanOverview mapped to a record of image scan overview. +// ImgScanOverview mapped to a record of image scan overview. type ImgScanOverview struct { ID int64 `orm:"pk;auto;column(id)" json:"-"` Digest string `orm:"column(image_digest)" json:"image_digest"` @@ -78,18 +78,18 @@ type ImgScanOverview struct { UpdateTime time.Time `orm:"column(update_time);auto_now" json:"update_time,omitempty"` } -//TableName ... +// TableName ... func (iso *ImgScanOverview) TableName() string { return ScanOverviewTable } -//ComponentsOverview has the total number and a list of components number of different serverity level. +// ComponentsOverview has the total number and a list of components number of different serverity level. type ComponentsOverview struct { Total int `json:"total"` Summary []*ComponentsOverviewEntry `json:"summary"` } -//ComponentsOverviewEntry ... +// ComponentsOverviewEntry ... type ComponentsOverviewEntry struct { Sev int `json:"severity"` Count int `json:"count"` @@ -129,7 +129,7 @@ const ( ScanAllDailyTime = "daily_time" ) -//DefaultScanAllPolicy ... +// DefaultScanAllPolicy ... var DefaultScanAllPolicy = ScanAllPolicy{ Type: ScanAllDaily, Parm: map[string]interface{}{ diff --git a/src/common/models/uaa.go b/src/common/models/uaa.go index 889ddeb6f..ef61e5841 100644 --- a/src/common/models/uaa.go +++ b/src/common/models/uaa.go @@ -14,7 +14,7 @@ package models -//UAASettings wraps the configuraations to access UAA service +// UAASettings wraps the configuraations to access UAA service type UAASettings struct { Endpoint string ClientID string diff --git a/src/common/models/user.go b/src/common/models/user.go index 136c271ad..bf129743a 100644 --- a/src/common/models/user.go +++ b/src/common/models/user.go @@ -31,8 +31,8 @@ type User struct { Comment string `orm:"column(comment)" json:"comment"` Deleted bool `orm:"column(deleted)" json:"deleted"` Rolename string `orm:"-" json:"role_name"` - //if this field is named as "RoleID", beego orm can not map role_id - //to it. + // if this field is named as "RoleID", beego orm can not map role_id + // to it. Role int `orm:"-" json:"role_id"` // RoleList []Role `json:"role_list"` HasAdminRole bool `orm:"column(sysadmin_flag)" json:"has_admin_role"` diff --git a/src/common/models/watch_item.go b/src/common/models/watch_item.go index 1dbb6f73c..5b65a2c32 100644 --- a/src/common/models/watch_item.go +++ b/src/common/models/watch_item.go @@ -29,7 +29,7 @@ type WatchItem struct { UpdateTime time.Time `orm:"column(update_time);auto_now" json:"update_time"` } -//TableName ... +// TableName ... func (w *WatchItem) TableName() string { return "replication_immediate_trigger" } diff --git a/src/common/notifier/config_watcher.go b/src/common/notifier/config_watcher.go index 4ff00282b..b812c8775 100644 --- a/src/common/notifier/config_watcher.go +++ b/src/common/notifier/config_watcher.go @@ -7,13 +7,13 @@ import ( "github.com/goharbor/harbor/src/common/utils" ) -//WatchConfigChanges is used to watch the configuration changes. +// WatchConfigChanges is used to watch the configuration changes. func WatchConfigChanges(cfg map[string]interface{}) error { if cfg == nil { return errors.New("Empty configurations") } - //Currently only watch the scan all policy change. + // Currently only watch the scan all policy change. if v, ok := cfg[ScanAllPolicyTopic]; ok { policyCfg := &models.ScanAllPolicy{} if err := utils.ConvertMapToStruct(policyCfg, v); err != nil { diff --git a/src/common/notifier/notification_handler.go b/src/common/notifier/notification_handler.go index 5d4508aa3..9bc893055 100644 --- a/src/common/notifier/notification_handler.go +++ b/src/common/notifier/notification_handler.go @@ -1,15 +1,15 @@ package notifier -//NotificationHandler defines what operations a notification handler -//should have. +// NotificationHandler defines what operations a notification handler +// should have. type NotificationHandler interface { - //Handle the event when it coming. - //value might be optional, it depends on usages. + // Handle the event when it coming. + // value might be optional, it depends on usages. Handle(value interface{}) error - //IsStateful returns whether the handler is stateful or not. - //If handler is stateful, it will not be triggerred in parallel. - //Otherwise, the handler will be triggered concurrently if more - //than one same handler are matched the topics. + // IsStateful returns whether the handler is stateful or not. + // If handler is stateful, it will not be triggerred in parallel. + // Otherwise, the handler will be triggered concurrently if more + // than one same handler are matched the topics. IsStateful() bool } diff --git a/src/common/notifier/notifier.go b/src/common/notifier/notifier.go index 2608447a8..98ef7af4f 100644 --- a/src/common/notifier/notifier.go +++ b/src/common/notifier/notifier.go @@ -10,52 +10,52 @@ import ( "github.com/goharbor/harbor/src/common/utils/log" ) -//HandlerIndexer is setup the relationship between the handler type and -//instance. +// HandlerIndexer is setup the relationship between the handler type and +// instance. type HandlerIndexer map[string]NotificationHandler -//Notification wraps the topic and related data value if existing. +// Notification wraps the topic and related data value if existing. type Notification struct { - //Topic of notification - //Required + // Topic of notification + // Required Topic string - //Value of notification. - //Optional + // Value of notification. + // Optional Value interface{} } -//HandlerChannel provides not only the chan itself but also the count of -//handlers related with this chan. +// HandlerChannel provides not only the chan itself but also the count of +// handlers related with this chan. type HandlerChannel struct { - //To indicate how many handler instances bound with this chan. + // To indicate how many handler instances bound with this chan. boundCount uint32 - //The chan for controlling concurrent executions. + // The chan for controlling concurrent executions. channel chan bool } -//NotificationWatcher is defined to accept the events published -//by the sender and match it with pre-registered notification handler -//and then trigger the execution of the found handler. +// NotificationWatcher is defined to accept the events published +// by the sender and match it with pre-registered notification handler +// and then trigger the execution of the found handler. type NotificationWatcher struct { - //For handle concurrent scenario. + // For handle concurrent scenario. *sync.RWMutex - //To keep the registered handlers in memory. - //Each topic can register multiple handlers. - //Each handler can bind to multiple topics. + // To keep the registered handlers in memory. + // Each topic can register multiple handlers. + // Each handler can bind to multiple topics. handlers map[string]HandlerIndexer - //Keep the channels which are used to control the concurrent executions - //of multiple stateful handlers with same type. + // Keep the channels which are used to control the concurrent executions + // of multiple stateful handlers with same type. handlerChannels map[string]*HandlerChannel } -//notificationWatcher is a default notification watcher in package level. +// notificationWatcher is a default notification watcher in package level. var notificationWatcher = NewNotificationWatcher() -//NewNotificationWatcher is constructor of NotificationWatcher. +// NewNotificationWatcher is constructor of NotificationWatcher. func NewNotificationWatcher() *NotificationWatcher { return &NotificationWatcher{ new(sync.RWMutex), @@ -64,7 +64,7 @@ func NewNotificationWatcher() *NotificationWatcher { } } -//Handle the related topic with the specified handler. +// Handle the related topic with the specified handler. func (nw *NotificationWatcher) Handle(topic string, handler NotificationHandler) error { if strings.TrimSpace(topic) == "" { return errors.New("Empty topic is not supported") @@ -91,11 +91,11 @@ func (nw *NotificationWatcher) Handle(topic string, handler NotificationHandler) } if handler.IsStateful() { - //First time + // First time if handlerChan, ok := nw.handlerChannels[t]; !ok { nw.handlerChannels[t] = &HandlerChannel{1, make(chan bool, 1)} } else { - //Already have chan, just increase count + // Already have chan, just increase count handlerChan.boundCount++ } } @@ -103,9 +103,9 @@ func (nw *NotificationWatcher) Handle(topic string, handler NotificationHandler) return nil } -//UnHandle is to revoke the registered handler with the specified topic. -//'handler' is optional, the type name of the handler. If it's empty value, -//then revoke the whole topic, otherwise only revoke the specified handler. +// UnHandle is to revoke the registered handler with the specified topic. +// 'handler' is optional, the type name of the handler. If it's empty value, +// then revoke the whole topic, otherwise only revoke the specified handler. func (nw *NotificationWatcher) UnHandle(topic string, handler string) error { if strings.TrimSpace(topic) == "" { return errors.New("Empty topic is not supported") @@ -115,20 +115,20 @@ func (nw *NotificationWatcher) UnHandle(topic string, handler string) error { nw.Lock() var revokeHandler = func(indexer HandlerIndexer, handlerType string) bool { - //Find the specified one + // Find the specified one if hd, existing := indexer[handlerType]; existing { delete(indexer, handlerType) if len(indexer) == 0 { - //No handler existing, then remove topic + // No handler existing, then remove topic delete(nw.handlers, topic) } - //Update channel counter or remove channel + // Update channel counter or remove channel if hd.IsStateful() { if theChan, yes := nw.handlerChannels[handlerType]; yes { theChan.boundCount-- if theChan.boundCount == 0 { - //Empty, then remove the channel + // Empty, then remove the channel delete(nw.handlerChannels, handlerType) } } @@ -149,7 +149,7 @@ func (nw *NotificationWatcher) UnHandle(topic string, handler string) error { return nil } - //Revoke the specified handler. + // Revoke the specified handler. if revokeHandler(indexer, handler) { return nil } @@ -158,7 +158,7 @@ func (nw *NotificationWatcher) UnHandle(topic string, handler string) error { return fmt.Errorf("Failed to revoke handler %s with topic %s", handler, topic) } -//Notify that notification is coming. +// Notify that notification is coming. func (nw *NotificationWatcher) Notify(notification Notification) error { if strings.TrimSpace(notification.Topic) == "" { return errors.New("Empty topic can not be notified") @@ -180,7 +180,7 @@ func (nw *NotificationWatcher) Notify(notification Notification) error { handlers = append(handlers, h) } - //Trigger handlers + // Trigger handlers for _, h := range handlers { var handlerChan chan bool if h.IsStateful() { @@ -198,7 +198,7 @@ func (nw *NotificationWatcher) Notify(notification Notification) error { } }() if err := hd.Handle(notification.Value); err != nil { - //Currently, we just log the error + // Currently, we just log the error log.Errorf("Error occurred when triggering handler %s of topic %s: %s\n", reflect.TypeOf(hd).String(), notification.Topic, err.Error()) } else { log.Infof("Handle notification with topic '%s': %#v\n", notification.Topic, notification.Value) @@ -210,17 +210,17 @@ func (nw *NotificationWatcher) Notify(notification Notification) error { return nil } -//Subscribe is a wrapper utility method for NotificationWatcher.handle() +// Subscribe is a wrapper utility method for NotificationWatcher.handle() func Subscribe(topic string, handler NotificationHandler) error { return notificationWatcher.Handle(topic, handler) } -//UnSubscribe is a wrapper utility method for NotificationWatcher.UnHandle() +// UnSubscribe is a wrapper utility method for NotificationWatcher.UnHandle() func UnSubscribe(topic string, handler string) error { return notificationWatcher.UnHandle(topic, handler) } -//Publish is a wrapper utility method for NotificationWatcher.notify() +// Publish is a wrapper utility method for NotificationWatcher.notify() func Publish(topic string, value interface{}) error { return notificationWatcher.Notify(Notification{ Topic: topic, diff --git a/src/common/notifier/notifier_test.go b/src/common/notifier/notifier_test.go index db839c38e..d2923c218 100644 --- a/src/common/notifier/notifier_test.go +++ b/src/common/notifier/notifier_test.go @@ -128,7 +128,7 @@ func TestPublish(t *testing.T) { Publish("topic1", 100) Publish("topic2", 50) - //Waiting for async is done + // Waiting for async is done <-time.After(1 * time.Second) finalData := atomic.LoadInt32(&statefulData) @@ -146,7 +146,7 @@ func TestPublish(t *testing.T) { t.Fatal(err) } - //Clear stateful data. + // Clear stateful data. atomic.StoreInt32(&statefulData, 0) } @@ -161,12 +161,12 @@ func TestConcurrentPublish(t *testing.T) { t.Fail() } - //Publish in a short interval. + // Publish in a short interval. for i := 0; i < 10; i++ { Publish("topic1", 100) } - //Waiting for async is done + // Waiting for async is done <-time.After(1 * time.Second) finalData := atomic.LoadInt32(&statefulData) @@ -179,7 +179,7 @@ func TestConcurrentPublish(t *testing.T) { t.Fatal(err) } - //Clear stateful data. + // Clear stateful data. atomic.StoreInt32(&statefulData, 0) } @@ -206,7 +206,7 @@ func TestConcurrentPublishWithScanPolicyHandler(t *testing.T) { } } - //Wating for everything is ready. + // Wating for everything is ready. <-time.After(2 * time.Second) if err := UnSubscribe("testing_topic", ""); err != nil { @@ -218,7 +218,7 @@ func TestConcurrentPublishWithScanPolicyHandler(t *testing.T) { } scheduler.DefaultScheduler.Stop() - //Wating for everything is ready. + // Wating for everything is ready. <-time.After(1 * time.Second) if scheduler.DefaultScheduler.IsRunning() { t.Fatal("Policy scheduler is not stopped") diff --git a/src/common/notifier/scan_policy_notitification_handler.go b/src/common/notifier/scan_policy_notitification_handler.go index f2dcfab87..214da2267 100644 --- a/src/common/notifier/scan_policy_notitification_handler.go +++ b/src/common/notifier/scan_policy_notitification_handler.go @@ -13,35 +13,35 @@ import ( ) const ( - //PolicyTypeDaily specify the policy type is "daily" + // PolicyTypeDaily specify the policy type is "daily" PolicyTypeDaily = "daily" - //PolicyTypeNone specify the policy type is "none" + // PolicyTypeNone specify the policy type is "none" PolicyTypeNone = "none" alternatePolicy = "Alternate Policy" ) -//ScanPolicyNotification is defined for pass the policy change data. +// ScanPolicyNotification is defined for pass the policy change data. type ScanPolicyNotification struct { - //Type is used to keep the scan policy type: "none","daily" and "refresh". + // Type is used to keep the scan policy type: "none","daily" and "refresh". Type string - //DailyTime is used when the type is 'daily', the offset with UTC time 00:00. + // DailyTime is used when the type is 'daily', the offset with UTC time 00:00. DailyTime int64 } -//ScanPolicyNotificationHandler is defined to handle the changes of scanning -//policy. +// ScanPolicyNotificationHandler is defined to handle the changes of scanning +// policy. type ScanPolicyNotificationHandler struct{} -//IsStateful to indicate this handler is stateful. +// IsStateful to indicate this handler is stateful. func (s *ScanPolicyNotificationHandler) IsStateful() bool { - //Policy change should be done one by one. + // Policy change should be done one by one. return true } -//Handle the policy change notification. +// Handle the policy change notification. func (s *ScanPolicyNotificationHandler) Handle(value interface{}) error { if value == nil { return errors.New("ScanPolicyNotificationHandler can not handle nil value") @@ -57,27 +57,27 @@ func (s *ScanPolicyNotificationHandler) Handle(value interface{}) error { hasScheduled := scheduler.DefaultScheduler.HasScheduled(alternatePolicy) if notification.Type == PolicyTypeDaily { if !hasScheduled { - //Schedule a new policy. + // Schedule a new policy. return schedulePolicy(notification) } - //To check and compare if the related parameter is changed. + // To check and compare if the related parameter is changed. if pl := scheduler.DefaultScheduler.GetPolicy(alternatePolicy); pl != nil { policyCandidate := policy.NewAlternatePolicy(alternatePolicy, &policy.AlternatePolicyConfiguration{ Duration: 24 * time.Hour, OffsetTime: notification.DailyTime, }) if !pl.Equal(policyCandidate) { - //Parameter changed. - //Unschedule policy. + // Parameter changed. + // Unschedule policy. if err := scheduler.DefaultScheduler.UnSchedule(alternatePolicy); err != nil { return err } - //Schedule a new policy. + // Schedule a new policy. return schedulePolicy(notification) } - //Same policy configuration, do nothing + // Same policy configuration, do nothing return nil } @@ -93,7 +93,7 @@ func (s *ScanPolicyNotificationHandler) Handle(value interface{}) error { return nil } -//Schedule policy. +// Schedule policy. func schedulePolicy(notification ScanPolicyNotification) error { schedulePolicy := policy.NewAlternatePolicy(alternatePolicy, &policy.AlternatePolicyConfiguration{ Duration: 24 * time.Hour, diff --git a/src/common/notifier/scan_policy_notitification_handler_test.go b/src/common/notifier/scan_policy_notitification_handler_test.go index 1211dc506..50a155858 100644 --- a/src/common/notifier/scan_policy_notitification_handler_test.go +++ b/src/common/notifier/scan_policy_notitification_handler_test.go @@ -11,7 +11,7 @@ import ( var testingScheduler = scheduler.DefaultScheduler func TestScanPolicyNotificationHandler(t *testing.T) { - //Scheduler should be running. + // Scheduler should be running. testingScheduler.Start() if !testingScheduler.IsRunning() { t.Fatal("scheduler should be running") @@ -32,7 +32,7 @@ func TestScanPolicyNotificationHandler(t *testing.T) { t.Fatal("Handler does not work") } - //Policy parameter changed. + // Policy parameter changed. notification2 := ScanPolicyNotification{"daily", utcTime + 7200} if err := handler.Handle(notification2); err != nil { t.Fatal(err) @@ -63,9 +63,9 @@ func TestScanPolicyNotificationHandler(t *testing.T) { t.Fail() } - //Clear + // Clear testingScheduler.Stop() - //Waiting for everything is ready. + // Waiting for everything is ready. <-time.After(1 * time.Second) if testingScheduler.IsRunning() { t.Fatal("scheduler should be stopped") diff --git a/src/common/notifier/topics.go b/src/common/notifier/topics.go index d88e79b69..23aca94cf 100644 --- a/src/common/notifier/topics.go +++ b/src/common/notifier/topics.go @@ -4,8 +4,8 @@ import ( "github.com/goharbor/harbor/src/common" ) -//Define global topic names +// Define global topic names const ( - //ScanAllPolicyTopic is for notifying the change of scanning all policy. + // ScanAllPolicyTopic is for notifying the change of scanning all policy. ScanAllPolicyTopic = common.ScanAllPolicy ) diff --git a/src/common/scheduler/policy/alternate_policy.go b/src/common/scheduler/policy/alternate_policy.go index c8ba207a0..da9e7ba63 100644 --- a/src/common/scheduler/policy/alternate_policy.go +++ b/src/common/scheduler/policy/alternate_policy.go @@ -14,52 +14,52 @@ const ( oneDay = 24 * 3600 ) -//AlternatePolicyConfiguration store the related configurations for alternate policy. +// AlternatePolicyConfiguration store the related configurations for alternate policy. type AlternatePolicyConfiguration struct { - //Duration is the interval of executing attached tasks. - //E.g: 24*3600 for daily + // Duration is the interval of executing attached tasks. + // E.g: 24*3600 for daily // 7*24*3600 for weekly Duration time.Duration - //An integer to indicate the the weekday of the week. Please be noted that Sunday is 7. - //Use default value 0 to indicate weekday is not set. - //To support by weekly function. + // An integer to indicate the the weekday of the week. Please be noted that Sunday is 7. + // Use default value 0 to indicate weekday is not set. + // To support by weekly function. Weekday int8 - //OffsetTime is the execution time point of each turn - //It's a number to indicate the seconds offset to the 00:00 of UTC time. + // OffsetTime is the execution time point of each turn + // It's a number to indicate the seconds offset to the 00:00 of UTC time. OffsetTime int64 } -//AlternatePolicy is a policy that repeatedly executing tasks with specified duration during a specified time scope. +// AlternatePolicy is a policy that repeatedly executing tasks with specified duration during a specified time scope. type AlternatePolicy struct { - //To sync the related operations. + // To sync the related operations. *sync.RWMutex - //Keep the attached tasks. + // Keep the attached tasks. tasks task.Store - //Policy configurations. + // Policy configurations. config *AlternatePolicyConfiguration - //To indicated whether policy is enabled or not. + // To indicated whether policy is enabled or not. isEnabled bool - //Channel used to send evaluation result signals. + // Channel used to send evaluation result signals. evaluation chan bool - //Channel used to notify policy termination. + // Channel used to notify policy termination. done chan bool - //Channel used to receive terminate signal. + // Channel used to receive terminate signal. terminator chan bool - //Unique name of this policy to support multiple instances + // Unique name of this policy to support multiple instances name string } -//NewAlternatePolicy is constructor of creating AlternatePolicy. -//Accept name and configuration as parameters. +// NewAlternatePolicy is constructor of creating AlternatePolicy. +// Accept name and configuration as parameters. func NewAlternatePolicy(name string, config *AlternatePolicyConfiguration) *AlternatePolicy { return &AlternatePolicy{ RWMutex: new(sync.RWMutex), @@ -71,27 +71,27 @@ func NewAlternatePolicy(name string, config *AlternatePolicyConfiguration) *Alte } } -//GetConfig returns the current configuration options of this policy. +// GetConfig returns the current configuration options of this policy. func (alp *AlternatePolicy) GetConfig() *AlternatePolicyConfiguration { return alp.config } -//Name is an implementation of same method in policy interface. +// Name is an implementation of same method in policy interface. func (alp *AlternatePolicy) Name() string { return alp.name } -//Tasks is an implementation of same method in policy interface. +// Tasks is an implementation of same method in policy interface. func (alp *AlternatePolicy) Tasks() []task.Task { return alp.tasks.GetTasks() } -//Done is an implementation of same method in policy interface. +// Done is an implementation of same method in policy interface. func (alp *AlternatePolicy) Done() <-chan bool { return alp.done } -//AttachTasks is an implementation of same method in policy interface. +// AttachTasks is an implementation of same method in policy interface. func (alp *AlternatePolicy) AttachTasks(tasks ...task.Task) error { if len(tasks) == 0 { return errors.New("No tasks can be attached") @@ -102,7 +102,7 @@ func (alp *AlternatePolicy) AttachTasks(tasks ...task.Task) error { return nil } -//Disable is an implementation of same method in policy interface. +// Disable is an implementation of same method in policy interface. func (alp *AlternatePolicy) Disable() error { alp.Lock() if !alp.isEnabled { @@ -110,33 +110,33 @@ func (alp *AlternatePolicy) Disable() error { return fmt.Errorf("Instance of policy %s is not enabled", alp.Name()) } - //Set state to disabled + // Set state to disabled alp.isEnabled = false alp.Unlock() - //Stop the evaluation goroutine + // Stop the evaluation goroutine alp.terminator <- true return nil } -//Evaluate is an implementation of same method in policy interface. +// Evaluate is an implementation of same method in policy interface. func (alp *AlternatePolicy) Evaluate() (<-chan bool, error) { - //Lock for state changing + // Lock for state changing defer alp.Unlock() alp.Lock() - //Check if configuration is valid + // Check if configuration is valid if !alp.isValidConfig() { return nil, errors.New("Policy configuration is not valid") } - //Check if policy instance is still running + // Check if policy instance is still running if alp.isEnabled { return nil, fmt.Errorf("Instance of policy %s is still running", alp.Name()) } - //Keep idempotent + // Keep idempotent if alp.evaluation != nil { return alp.evaluation, nil } @@ -150,8 +150,8 @@ func (alp *AlternatePolicy) Evaluate() (<-chan bool, error) { ) timeNow := time.Now().UTC() - //Reach the execution time point? - //Weekday is set + // Reach the execution time point? + // Weekday is set if alp.config.Weekday > 0 { targetWeekday := (alp.config.Weekday + 7) % 7 currentWeekday := timeNow.Weekday() @@ -162,7 +162,7 @@ func (alp *AlternatePolicy) Evaluate() (<-chan bool, error) { waitingTime = (int64)(weekdayDiff * oneDay) } - //Time + // Time utcTime := (int64)(timeNow.Hour()*3600 + timeNow.Minute()*60) diff := alp.config.OffsetTime - utcTime if waitingTime > 0 { @@ -174,9 +174,9 @@ func (alp *AlternatePolicy) Evaluate() (<-chan bool, error) { } } - //Let's wait for a while + // Let's wait for a while if waitingTime > 0 { - //Wait for a while. + // Wait for a while. log.Infof("Waiting for %d seconds after comparing offset %d and utc time %d\n", diff, alp.config.OffsetTime, utcTime) select { case <-time.After(time.Duration(waitingTime) * time.Second): @@ -185,10 +185,10 @@ func (alp *AlternatePolicy) Evaluate() (<-chan bool, error) { } } - //Trigger the first tick. + // Trigger the first tick. alp.evaluation <- true - //Start the ticker for repeat checking. + // Start the ticker for repeat checking. tk := time.NewTicker(alp.config.Duration) defer func() { if tk != nil { @@ -208,13 +208,13 @@ func (alp *AlternatePolicy) Evaluate() (<-chan bool, error) { } }() - //Enabled + // Enabled alp.isEnabled = true return alp.evaluation, nil } -//Equal is an implementation of same method in policy interface. +// Equal is an implementation of same method in policy interface. func (alp *AlternatePolicy) Equal(p Policy) bool { if p == nil { return false @@ -237,7 +237,7 @@ func (alp *AlternatePolicy) Equal(p Policy) bool { cfg.Weekday == cfg2.Weekday) } -//IsEnabled is an implementation of same method in policy interface. +// IsEnabled is an implementation of same method in policy interface. func (alp *AlternatePolicy) IsEnabled() bool { defer alp.RUnlock() alp.RLock() @@ -245,7 +245,7 @@ func (alp *AlternatePolicy) IsEnabled() bool { return alp.isEnabled } -//Check if the config is valid. At least it should have the configurations for supporting daily policy. +// Check if the config is valid. At least it should have the configurations for supporting daily policy. func (alp *AlternatePolicy) isValidConfig() bool { return alp.config != nil && alp.config.Duration > 0 && alp.config.OffsetTime >= 0 } diff --git a/src/common/scheduler/policy/alternate_policy_test.go b/src/common/scheduler/policy/alternate_policy_test.go index 5a3eda4e3..0492c3426 100644 --- a/src/common/scheduler/policy/alternate_policy_test.go +++ b/src/common/scheduler/policy/alternate_policy_test.go @@ -112,9 +112,9 @@ func TestDisablePolicy(t *testing.T) { if tp.Disable() != nil { t.Fatal("Failed to disable policy") } - //Waiting for everything is stable + // Waiting for everything is stable <-time.After(1 * time.Second) - //Copy value + // Copy value var copiedCounter int32 atomic.StoreInt32(&copiedCounter, atomic.LoadInt32(&counter)) time.Sleep(2 * time.Second) diff --git a/src/common/scheduler/policy/policy.go b/src/common/scheduler/policy/policy.go index 865eda1b2..6957d4ef0 100644 --- a/src/common/scheduler/policy/policy.go +++ b/src/common/scheduler/policy/policy.go @@ -4,45 +4,45 @@ import ( "github.com/goharbor/harbor/src/common/scheduler/task" ) -//Policy is an if-then logic to determine how the attached tasks should be -//executed based on the evaluation result of the defined conditions. -//E.g: +// Policy is an if-then logic to determine how the attached tasks should be +// executed based on the evaluation result of the defined conditions. +// E.g: // Daily execute TASK between 2017/06/24 and 2018/06/23 // Execute TASK at 2017/09/01 14:30:00 // -//Each policy should have a name to identify itself. -//Please be aware that policy with no tasks will be treated as invalid. +// Each policy should have a name to identify itself. +// Please be aware that policy with no tasks will be treated as invalid. // type Policy interface { - //Name will return the name of the policy. - //If the policy supports multiple instances, please make sure the name is unique as an UUID. + // Name will return the name of the policy. + // If the policy supports multiple instances, please make sure the name is unique as an UUID. Name() string - //Tasks will return the attached tasks with this policy. + // Tasks will return the attached tasks with this policy. Tasks() []task.Task - //AttachTasks is to attach tasks to this policy + // AttachTasks is to attach tasks to this policy AttachTasks(...task.Task) error - //Done will setup a channel for other components to check whether or not - //the policy is completed. Possibly designed for the none loop policy. + // Done will setup a channel for other components to check whether or not + // the policy is completed. Possibly designed for the none loop policy. Done() <-chan bool - //Evaluate the policy based on its definition and return the result via - //result channel. Policy is enabled after it is evaluated. - //Make sure Evaluate is idempotent, that means one policy can be only enabled - //only once even if Evaluate is called more than one times. + // Evaluate the policy based on its definition and return the result via + // result channel. Policy is enabled after it is evaluated. + // Make sure Evaluate is idempotent, that means one policy can be only enabled + // only once even if Evaluate is called more than one times. Evaluate() (<-chan bool, error) - //Disable the enabled policy and release all the allocated resources. + // Disable the enabled policy and release all the allocated resources. Disable() error - //Equal will compare the two policies based on related factors if existing such as confgiuration etc. - //to determine whether the two policies are same ones or not. Please pay attention that, not every policy - //needs to support this method. If no need, please directly return false to indicate each policies are - //different. + // Equal will compare the two policies based on related factors if existing such as confgiuration etc. + // to determine whether the two policies are same ones or not. Please pay attention that, not every policy + // needs to support this method. If no need, please directly return false to indicate each policies are + // different. Equal(p Policy) bool - //IsEnabled is to indicate whether the policy is enabled or not (disabled). + // IsEnabled is to indicate whether the policy is enabled or not (disabled). IsEnabled() bool } diff --git a/src/common/scheduler/policy/uuid.go b/src/common/scheduler/policy/uuid.go index 8bd1bd72c..1f001e00b 100644 --- a/src/common/scheduler/policy/uuid.go +++ b/src/common/scheduler/policy/uuid.go @@ -6,8 +6,8 @@ import ( "io" ) -//NewUUID will generate a new UUID. -//Code copied from https://play.golang.org/p/4FkNSiUDMg +// NewUUID will generate a new UUID. +// Code copied from https://play.golang.org/p/4FkNSiUDMg func newUUID() (string, error) { uuid := make([]byte, 16) n, err := io.ReadFull(rand.Reader, uuid) diff --git a/src/common/scheduler/scheduler.go b/src/common/scheduler/scheduler.go index 2cc878a1e..311ac17ac 100644 --- a/src/common/scheduler/scheduler.go +++ b/src/common/scheduler/scheduler.go @@ -22,72 +22,72 @@ const ( statTaskFail = "Task Fail" ) -//StatItem is defined for the stat metrics. +// StatItem is defined for the stat metrics. type StatItem struct { - //Metrics catalog + // Metrics catalog Type string - //The stat value + // The stat value Value uint32 - //Attach some other info + // Attach some other info Attachment interface{} } -//StatSummary is used to collect some metrics of scheduler. +// StatSummary is used to collect some metrics of scheduler. type StatSummary struct { - //Count of scheduled policy + // Count of scheduled policy PolicyCount uint32 - //Total count of tasks + // Total count of tasks Tasks uint32 - //Count of successfully complete tasks + // Count of successfully complete tasks CompletedTasks uint32 - //Count of tasks with errors + // Count of tasks with errors TasksWithError uint32 } -//Configuration defines configuration of Scheduler. +// Configuration defines configuration of Scheduler. type Configuration struct { QueueSize uint8 } -//Scheduler is designed for scheduling policies. +// Scheduler is designed for scheduling policies. type Scheduler struct { - //Mutex for sync controlling. + // Mutex for sync controlling. *sync.RWMutex - //Related configuration options for scheduler. + // Related configuration options for scheduler. config *Configuration - //Store to keep the references of scheduled policies. + // Store to keep the references of scheduled policies. policies Store - //Queue for receiving policy scheduling request + // Queue for receiving policy scheduling request scheduleQueue chan *Watcher - //Queue for receiving policy unscheduling request or complete signal. + // Queue for receiving policy unscheduling request or complete signal. unscheduleQueue chan *Watcher - //Channel for receiving stat metrics. + // Channel for receiving stat metrics. statChan chan *StatItem - //Channel for terminate scheduler damon. + // Channel for terminate scheduler damon. terminateChan chan bool - //The stat metrics of scheduler. + // The stat metrics of scheduler. stats *StatSummary - //To indicate whether scheduler is running or not + // To indicate whether scheduler is running or not isRunning bool } -//DefaultScheduler is a default scheduler. +// DefaultScheduler is a default scheduler. var DefaultScheduler = NewScheduler(nil) -//NewScheduler is constructor for creating a scheduler. +// NewScheduler is constructor for creating a scheduler. func NewScheduler(config *Configuration) *Scheduler { var qSize uint8 = defaultQueueSize if config != nil && config.QueueSize > 0 { @@ -118,12 +118,12 @@ func NewScheduler(config *Configuration) *Scheduler { } } -//Start the scheduler damon. +// Start the scheduler damon. func (sch *Scheduler) Start() { sch.Lock() defer sch.Unlock() - //If scheduler is already running + // If scheduler is already running if sch.isRunning { return } @@ -135,32 +135,32 @@ func (sch *Scheduler) Start() { } }() defer func() { - //Clear resources + // Clear resources sch.policies.Clear() log.Infof("Policy scheduler stop at %s\n", time.Now().UTC().Format(time.RFC3339)) }() for { select { case <-sch.terminateChan: - //Exit + // Exit return case wt := <-sch.scheduleQueue: - //If status is stopped, no requests should be served + // If status is stopped, no requests should be served if !sch.IsRunning() { continue } go func(watcher *Watcher) { if watcher != nil && watcher.p != nil { - //Enable it. + // Enable it. watcher.Start() - //Update stats and log info. + // Update stats and log info. log.Infof("Policy %s is scheduled", watcher.p.Name()) sch.statChan <- &StatItem{statSchedulePolicy, 1, nil} } }(wt) case wt := <-sch.unscheduleQueue: - //If status is stopped, no requests should be served + // If status is stopped, no requests should be served if !sch.IsRunning() { continue } @@ -168,14 +168,14 @@ func (sch *Scheduler) Start() { if watcher != nil && watcher.IsRunning() { watcher.Stop() - //Update stats and log info. + // Update stats and log info. log.Infof("Policy %s is unscheduled", watcher.p.Name()) sch.statChan <- &StatItem{statUnSchedulePolicy, 1, nil} } }(wt) case stat := <-sch.statChan: { - //If status is stopped, no requests should be served + // If status is stopped, no requests should be served if !sch.IsRunning() { continue } @@ -218,12 +218,12 @@ func (sch *Scheduler) Start() { log.Infof("Policy scheduler start at %s\n", time.Now().UTC().Format(time.RFC3339)) } -//Stop the scheduler damon. +// Stop the scheduler damon. func (sch *Scheduler) Stop() { - //Lock for state changing + // Lock for state changing sch.Lock() - //Check if the scheduler is running + // Check if the scheduler is running if !sch.isRunning { sch.Unlock() return @@ -232,11 +232,11 @@ func (sch *Scheduler) Stop() { sch.isRunning = false sch.Unlock() - //Terminate damon to stop receiving signals. + // Terminate damon to stop receiving signals. sch.terminateChan <- true } -//Schedule and enable the policy. +// Schedule and enable the policy. func (sch *Scheduler) Schedule(scheduledPolicy policy.Policy) error { if scheduledPolicy == nil { return errors.New("nil is not Policy object") @@ -251,38 +251,38 @@ func (sch *Scheduler) Schedule(scheduledPolicy policy.Policy) error { return errors.New("Policy must attach task(s)") } - //Try to schedule the policy. - //Keep the policy for future use after it's successfully scheduled. + // Try to schedule the policy. + // Keep the policy for future use after it's successfully scheduled. watcher := NewWatcher(scheduledPolicy, sch.statChan, sch.unscheduleQueue) if err := sch.policies.Put(scheduledPolicy.Name(), watcher); err != nil { return err } - //Schedule the policy + // Schedule the policy sch.scheduleQueue <- watcher return nil } -//UnSchedule the specified policy from the enabled policies list. +// UnSchedule the specified policy from the enabled policies list. func (sch *Scheduler) UnSchedule(policyName string) error { if strings.TrimSpace(policyName) == "" { return errors.New("Empty policy name is invalid") } - //Find the watcher. + // Find the watcher. watcher := sch.policies.Remove(policyName) if watcher == nil { return fmt.Errorf("Policy %s is not existing", policyName) } - //Unschedule the policy. + // Unschedule the policy. sch.unscheduleQueue <- watcher return nil } -//IsRunning to indicate whether the scheduler is running. +// IsRunning to indicate whether the scheduler is running. func (sch *Scheduler) IsRunning() bool { sch.RLock() defer sch.RUnlock() @@ -290,12 +290,12 @@ func (sch *Scheduler) IsRunning() bool { return sch.isRunning } -//HasScheduled is to check whether the given policy has been scheduled or not. +// HasScheduled is to check whether the given policy has been scheduled or not. func (sch *Scheduler) HasScheduled(policyName string) bool { return sch.policies.Exists(policyName) } -//GetPolicy is used to get related policy reference by its name. +// GetPolicy is used to get related policy reference by its name. func (sch *Scheduler) GetPolicy(policyName string) policy.Policy { wk := sch.policies.Get(policyName) if wk != nil { @@ -305,7 +305,7 @@ func (sch *Scheduler) GetPolicy(policyName string) policy.Policy { return nil } -//PolicyCount returns the count of currently scheduled policies in the scheduler. +// PolicyCount returns the count of currently scheduled policies in the scheduler. func (sch *Scheduler) PolicyCount() uint32 { return sch.policies.Size() } diff --git a/src/common/scheduler/scheduler_store.go b/src/common/scheduler/scheduler_store.go index dac97cc9d..08c31b46c 100644 --- a/src/common/scheduler/scheduler_store.go +++ b/src/common/scheduler/scheduler_store.go @@ -7,46 +7,46 @@ import ( "sync" ) -//Store define the basic operations for storing and managing policy watcher. +// Store define the basic operations for storing and managing policy watcher. type Store interface { - //Put a new policy in. + // Put a new policy in. Put(key string, value *Watcher) error - //Get the corresponding policy with the key. + // Get the corresponding policy with the key. Get(key string) *Watcher - //Exists is to check if the key existing in the store. + // Exists is to check if the key existing in the store. Exists(key string) bool - //Remove the specified policy and return its reference. + // Remove the specified policy and return its reference. Remove(key string) *Watcher - //Size return the total count of items in store. + // Size return the total count of items in store. Size() uint32 - //GetAll is to get all the items in the store. + // GetAll is to get all the items in the store. GetAll() []*Watcher - //Clear store. + // Clear store. Clear() } -//DefaultStore implements Store interface to keep the scheduled policies. -//Not support concurrent sync. +// DefaultStore implements Store interface to keep the scheduled policies. +// Not support concurrent sync. type DefaultStore struct { - //Support sync locking + // Support sync locking *sync.RWMutex - //Map used to keep the policy list. + // Map used to keep the policy list. data map[string]*Watcher } -//NewDefaultStore is used to create a new store and return the pointer reference. +// NewDefaultStore is used to create a new store and return the pointer reference. func NewDefaultStore() *DefaultStore { return &DefaultStore{new(sync.RWMutex), make(map[string]*Watcher)} } -//Put a policy into store. +// Put a policy into store. func (cs *DefaultStore) Put(key string, value *Watcher) error { if strings.TrimSpace(key) == "" || value == nil { return errors.New("Bad arguments") @@ -64,7 +64,7 @@ func (cs *DefaultStore) Put(key string, value *Watcher) error { return nil } -//Get policy via key. +// Get policy via key. func (cs *DefaultStore) Get(key string) *Watcher { if strings.TrimSpace(key) == "" { return nil @@ -76,7 +76,7 @@ func (cs *DefaultStore) Get(key string) *Watcher { return cs.data[key] } -//Exists is used to check whether or not the key exists in store. +// Exists is used to check whether or not the key exists in store. func (cs *DefaultStore) Exists(key string) bool { if strings.TrimSpace(key) == "" { return false @@ -90,7 +90,7 @@ func (cs *DefaultStore) Exists(key string) bool { return ok } -//Remove is to delete the specified policy. +// Remove is to delete the specified policy. func (cs *DefaultStore) Remove(key string) *Watcher { if strings.TrimSpace(key) == "" { return nil @@ -107,7 +107,7 @@ func (cs *DefaultStore) Remove(key string) *Watcher { return nil } -//Size return the total count of items in store. +// Size return the total count of items in store. func (cs *DefaultStore) Size() uint32 { cs.RLock() defer cs.RUnlock() @@ -115,7 +115,7 @@ func (cs *DefaultStore) Size() uint32 { return (uint32)(len(cs.data)) } -//GetAll to get all the items of store. +// GetAll to get all the items of store. func (cs *DefaultStore) GetAll() []*Watcher { cs.RLock() defer cs.RUnlock() @@ -129,7 +129,7 @@ func (cs *DefaultStore) GetAll() []*Watcher { return all } -//Clear all the items in store. +// Clear all the items in store. func (cs *DefaultStore) Clear() { cs.Lock() defer cs.Unlock() diff --git a/src/common/scheduler/scheduler_test.go b/src/common/scheduler/scheduler_test.go index 5af11a051..63109728a 100644 --- a/src/common/scheduler/scheduler_test.go +++ b/src/common/scheduler/scheduler_test.go @@ -88,7 +88,7 @@ func (ft *fakeTask) Number() int32 { return atomic.LoadInt32(&(ft.number)) } -//Wacher will be tested together with scheduler. +// Wacher will be tested together with scheduler. func TestScheduler(t *testing.T) { DefaultScheduler.Start() if DefaultScheduler.policies.Size() != 0 { diff --git a/src/common/scheduler/task/replication/replication_task.go b/src/common/scheduler/task/replication/replication_task.go index a6915aca9..7426e214b 100644 --- a/src/common/scheduler/task/replication/replication_task.go +++ b/src/common/scheduler/task/replication/replication_task.go @@ -6,24 +6,24 @@ import ( "github.com/goharbor/harbor/src/replication/event/topic" ) -//Task is the task for triggering one replication +// Task is the task for triggering one replication type Task struct { PolicyID int64 } -//NewTask is constructor of creating ReplicationTask +// NewTask is constructor of creating ReplicationTask func NewTask(policyID int64) *Task { return &Task{ PolicyID: policyID, } } -//Name returns the name of this task +// Name returns the name of this task func (t *Task) Name() string { return "replication" } -//Run the actions here +// Run the actions here func (t *Task) Run() error { return notifier.Publish(topic.StartReplicationTopic, notification.StartReplicationNotification{ PolicyID: t.PolicyID, diff --git a/src/common/scheduler/task/scan_all_task.go b/src/common/scheduler/task/scan_all_task.go index d6f1871ad..d8ddbedd6 100644 --- a/src/common/scheduler/task/scan_all_task.go +++ b/src/common/scheduler/task/scan_all_task.go @@ -4,20 +4,20 @@ import ( "github.com/goharbor/harbor/src/ui/utils" ) -//ScanAllTask is task of scanning all tags. +// ScanAllTask is task of scanning all tags. type ScanAllTask struct{} -//NewScanAllTask is constructor of creating ScanAllTask. +// NewScanAllTask is constructor of creating ScanAllTask. func NewScanAllTask() *ScanAllTask { return &ScanAllTask{} } -//Name returns the name of the task. +// Name returns the name of the task. func (sat *ScanAllTask) Name() string { return "scan all" } -//Run the actions. +// Run the actions. func (sat *ScanAllTask) Run() error { return utils.ScanAllImages() } diff --git a/src/common/scheduler/task/task.go b/src/common/scheduler/task/task.go index 162a6501a..d5eb189b9 100644 --- a/src/common/scheduler/task/task.go +++ b/src/common/scheduler/task/task.go @@ -1,10 +1,10 @@ package task -//Task is used to synchronously run specific action(s). +// Task is used to synchronously run specific action(s). type Task interface { - //Name should return the name of the task. + // Name should return the name of the task. Name() string - //Run the concrete code here + // Run the concrete code here Run() error } diff --git a/src/common/scheduler/task/task_list.go b/src/common/scheduler/task/task_list.go index 2c5d4eb40..d46095b26 100644 --- a/src/common/scheduler/task/task_list.go +++ b/src/common/scheduler/task/task_list.go @@ -4,30 +4,30 @@ import ( "sync" ) -//Store is designed to keep the tasks. +// Store is designed to keep the tasks. type Store interface { - //GetTasks return the current existing list in store. + // GetTasks return the current existing list in store. GetTasks() []Task - //AddTasks is used to append tasks to the list. + // AddTasks is used to append tasks to the list. AddTasks(tasks ...Task) } -//DefaultStore is the default implemetation of Store interface. +// DefaultStore is the default implemetation of Store interface. type DefaultStore struct { - //To sync the related operations. + // To sync the related operations. *sync.RWMutex - //The space to keep the tasks. + // The space to keep the tasks. tasks []Task } -//NewDefaultStore is constructor method for DefaultStore. +// NewDefaultStore is constructor method for DefaultStore. func NewDefaultStore() *DefaultStore { return &DefaultStore{new(sync.RWMutex), []Task{}} } -//GetTasks implements the same method in Store interface. +// GetTasks implements the same method in Store interface. func (ds *DefaultStore) GetTasks() []Task { copyList := []Task{} @@ -41,9 +41,9 @@ func (ds *DefaultStore) GetTasks() []Task { return copyList } -//AddTasks implements the same method in Store interface. +// AddTasks implements the same method in Store interface. func (ds *DefaultStore) AddTasks(tasks ...Task) { - //Double confirm. + // Double confirm. if ds.tasks == nil { ds.tasks = []Task{} } diff --git a/src/common/scheduler/watcher.go b/src/common/scheduler/watcher.go index df70d2d65..36223fab0 100644 --- a/src/common/scheduler/watcher.go +++ b/src/common/scheduler/watcher.go @@ -9,28 +9,28 @@ import ( "sync" ) -//Watcher is an asynchronous runner to provide an evaluation environment for the policy. +// Watcher is an asynchronous runner to provide an evaluation environment for the policy. type Watcher struct { - //Locker to sync related operations. + // Locker to sync related operations. *sync.RWMutex - //The target policy. + // The target policy. p policy.Policy - //The channel for receive stop signal. + // The channel for receive stop signal. cmdChan chan bool - //Indicate whether the watcher is started and running. + // Indicate whether the watcher is started and running. isRunning bool - //Report stats to scheduler. + // Report stats to scheduler. stats chan *StatItem - //If policy is automatically completed, report the policy to scheduler. + // If policy is automatically completed, report the policy to scheduler. doneChan chan *Watcher } -//NewWatcher is used as a constructor. +// NewWatcher is used as a constructor. func NewWatcher(p policy.Policy, st chan *StatItem, done chan *Watcher) *Watcher { return &Watcher{ RWMutex: new(sync.RWMutex), @@ -42,9 +42,9 @@ func NewWatcher(p policy.Policy, st chan *StatItem, done chan *Watcher) *Watcher } } -//Start the running. +// Start the running. func (wc *Watcher) Start() { - //Lock for state changing + // Lock for state changing wc.Lock() defer wc.Unlock() @@ -74,13 +74,13 @@ func (wc *Watcher) Start() { select { case <-evalChan: { - //If worker is not running, should not response any requests. + // If worker is not running, should not response any requests. if !wc.IsRunning() { continue } log.Infof("Receive evaluation signal from policy '%s'\n", pl.Name()) - //Start to run the attached tasks. + // Start to run the attached tasks. for _, t := range pl.Tasks() { go func(tk task.Task) { defer func() { @@ -93,7 +93,7 @@ func (wc *Watcher) Start() { }() err := tk.Run() - //Report task execution stats. + // Report task execution stats. st := &StatItem{statTaskComplete, 1, err} if err != nil { st.Type = statTaskFail @@ -103,7 +103,7 @@ func (wc *Watcher) Start() { } }(t) - //Report task run stats. + // Report task run stats. st := &StatItem{statTaskRun, 1, nil} if wc.stats != nil { wc.stats <- st @@ -112,8 +112,8 @@ func (wc *Watcher) Start() { } case <-done: { - //Policy is automatically completed. - //Report policy change stats. + // Policy is automatically completed. + // Report policy change stats. if wc.doneChan != nil { wc.doneChan <- wc } @@ -121,7 +121,7 @@ func (wc *Watcher) Start() { return } case <-wc.cmdChan: - //Exit goroutine. + // Exit goroutine. return } } @@ -130,9 +130,9 @@ func (wc *Watcher) Start() { wc.isRunning = true } -//Stop the running. +// Stop the running. func (wc *Watcher) Stop() { - //Lock for state changing + // Lock for state changing wc.Lock() if !wc.isRunning { wc.Unlock() @@ -142,18 +142,18 @@ func (wc *Watcher) Stop() { wc.isRunning = false wc.Unlock() - //Disable policy. + // Disable policy. if wc.p != nil { wc.p.Disable() } - //Stop watcher. + // Stop watcher. wc.cmdChan <- true log.Infof("Worker for policy %s is stopped.\n", wc.p.Name()) } -//IsRunning to indicate if the watcher is still running. +// IsRunning to indicate if the watcher is still running. func (wc *Watcher) IsRunning() bool { wc.RLock() defer wc.RUnlock() diff --git a/src/common/secret/request.go b/src/common/secret/request.go index 58849d716..f87d31ea8 100644 --- a/src/common/secret/request.go +++ b/src/common/secret/request.go @@ -20,12 +20,12 @@ import ( "strings" ) -//HeaderPrefix is the prefix of the value of Authorization header. -//It has the space. +// HeaderPrefix is the prefix of the value of Authorization header. +// It has the space. const HeaderPrefix = "Harbor-Secret " -//FromRequest tries to get Harbor Secret from request header. -//It will return empty string if the reqeust is nil. +// FromRequest tries to get Harbor Secret from request header. +// It will return empty string if the reqeust is nil. func FromRequest(req *http.Request) string { if req == nil { return "" @@ -37,7 +37,7 @@ func FromRequest(req *http.Request) string { return "" } -//AddToRequest add the secret to request +// AddToRequest add the secret to request func AddToRequest(req *http.Request, secret string) error { if req == nil { return fmt.Errorf("input request is nil, unable to set secret") diff --git a/src/common/security/context.go b/src/common/security/context.go index bb7215350..f72d50d9c 100644 --- a/src/common/security/context.go +++ b/src/common/security/context.go @@ -34,8 +34,8 @@ type Context interface { HasWritePerm(projectIDOrName interface{}) bool // HasAllPerm returns whether the user has all permissions to the project HasAllPerm(projectIDOrName interface{}) bool - //Get current user's all project + // Get current user's all project GetMyProjects() ([]*models.Project, error) - //Get user's role in provided project + // Get user's role in provided project GetProjectRoles(projectIDOrName interface{}) []int } diff --git a/src/common/security/local/context.go b/src/common/security/local/context.go index b0cd4cd17..9d95b7658 100644 --- a/src/common/security/local/context.go +++ b/src/common/security/local/context.go @@ -184,11 +184,11 @@ func (s *SecurityContext) GetRolesByGroup(projectIDOrName interface{}) []int { var roles []int user := s.user project, err := s.pm.Get(projectIDOrName) - //No user, group or project info + // No user, group or project info if err != nil || project == nil || user == nil || len(user.GroupList) == 0 { return roles } - //Get role by LDAP group + // Get role by LDAP group groupDNConditions := group.GetGroupDNQueryCondition(user.GroupList) roles, err = dao.GetRolesByLDAPGroup(project.ProjectID, groupDNConditions) if err != nil { diff --git a/src/common/security/secret/context_test.go b/src/common/security/secret/context_test.go index c7d85eaee..a7fb2eb1a 100644 --- a/src/common/security/secret/context_test.go +++ b/src/common/security/secret/context_test.go @@ -28,7 +28,7 @@ func TestIsAuthenticated(t *testing.T) { isAuthenticated := context.IsAuthenticated() assert.False(t, isAuthenticated) - //invalid secret + // invalid secret context = NewSecurityContext("invalid_secret", secret.NewStore(map[string]string{ "secret": "username", @@ -36,7 +36,7 @@ func TestIsAuthenticated(t *testing.T) { isAuthenticated = context.IsAuthenticated() assert.False(t, isAuthenticated) - //valid secret + // valid secret context = NewSecurityContext("secret", secret.NewStore(map[string]string{ "secret": "username", @@ -51,7 +51,7 @@ func TestGetUsername(t *testing.T) { username := context.GetUsername() assert.Equal(t, "", username) - //invalid secret + // invalid secret context = NewSecurityContext("invalid_secret", secret.NewStore(map[string]string{ "secret": "username", @@ -59,7 +59,7 @@ func TestGetUsername(t *testing.T) { username = context.GetUsername() assert.Equal(t, "", username) - //valid secret + // valid secret context = NewSecurityContext("secret", secret.NewStore(map[string]string{ "secret": "username", @@ -101,7 +101,7 @@ func TestHasReadPerm(t *testing.T) { hasReadPerm := context.HasReadPerm("project_name") assert.False(t, hasReadPerm) - //invalid secret + // invalid secret context = NewSecurityContext("invalid_secret", secret.NewStore(map[string]string{ "jobservice_secret": secret.JobserviceUser, @@ -109,7 +109,7 @@ func TestHasReadPerm(t *testing.T) { hasReadPerm = context.HasReadPerm("project_name") assert.False(t, hasReadPerm) - //valid secret, project name + // valid secret, project name context = NewSecurityContext("jobservice_secret", secret.NewStore(map[string]string{ "jobservice_secret": secret.JobserviceUser, @@ -117,7 +117,7 @@ func TestHasReadPerm(t *testing.T) { hasReadPerm = context.HasReadPerm("project_name") assert.True(t, hasReadPerm) - //valid secret, project ID + // valid secret, project ID hasReadPerm = context.HasReadPerm(1) assert.True(t, hasReadPerm) } @@ -163,7 +163,7 @@ func TestGetMyProjects(t *testing.T) { } func TestGetProjectRoles(t *testing.T) { - //invalid secret + // invalid secret context := NewSecurityContext("invalid_secret", secret.NewStore(map[string]string{ "jobservice_secret": secret.JobserviceUser, diff --git a/src/common/utils/clair/client.go b/src/common/utils/clair/client.go index 48b79d156..8f1ef3171 100644 --- a/src/common/utils/clair/client.go +++ b/src/common/utils/clair/client.go @@ -30,7 +30,7 @@ import ( // Client communicates with clair endpoint to scan image and get detailed scan result type Client struct { endpoint string - //need to customize the logger to write output to job log. + // need to customize the logger to write output to job log. logger *log.Logger client *http.Client } diff --git a/src/common/utils/clair/utils.go b/src/common/utils/clair/utils.go index 87072f595..48932a2ce 100644 --- a/src/common/utils/clair/utils.go +++ b/src/common/utils/clair/utils.go @@ -22,7 +22,7 @@ import ( "strings" ) -//var client = NewClient() +// var client = NewClient() // ParseClairSev parse the severity of clair to Harbor's Severity type if the string is not recognized the value will be set to unknown. func ParseClairSev(clairSev string) models.Severity { @@ -94,7 +94,7 @@ func transformVuln(clairVuln *models.ClairLayerEnvelope) (*models.ComponentsOver }, overallSev } -//TransformVuln is for running scanning job in both job service V1 and V2. +// TransformVuln is for running scanning job in both job service V1 and V2. func TransformVuln(clairVuln *models.ClairLayerEnvelope) (*models.ComponentsOverview, models.Severity) { return transformVuln(clairVuln) } diff --git a/src/common/utils/email/mail.go b/src/common/utils/email/mail.go index fb72b9235..667ac7525 100644 --- a/src/common/utils/email/mail.go +++ b/src/common/utils/email/mail.go @@ -120,7 +120,7 @@ func newClient(addr, identity, username, password string, return nil, err } - //try to swith to SSL/TLS + // try to swith to SSL/TLS if !tls { if ok, _ := client.Extension("STARTTLS"); ok { log.Debugf("switching the connection with %s to SSL/TLS ...", addr) diff --git a/src/common/utils/email/mail_test.go b/src/common/utils/email/mail_test.go index 2f748d6e5..352c3465c 100644 --- a/src/common/utils/email/mail_test.go +++ b/src/common/utils/email/mail_test.go @@ -38,9 +38,9 @@ func TestSend(t *testing.T) { err := Send(addr, identity, username, password, timeout, tls, insecure, from, to, subject, message) - //bypass the check due to securty policy change on gmail - //TODO - //assert.Nil(t, err) + // bypass the check due to securty policy change on gmail + // TODO + // assert.Nil(t, err) /*not work on travis // non-tls connection @@ -52,7 +52,7 @@ func TestSend(t *testing.T) { assert.Nil(t, err) */ - //invalid username/password + // invalid username/password username = "invalid_username" err = Send(addr, identity, username, password, timeout, tls, insecure, from, to, @@ -78,9 +78,9 @@ func TestPing(t *testing.T) { // tls connection err := Ping(addr, identity, username, password, timeout, tls, insecure) - //bypass the check due to securty policy change on gmail - //TODO - //assert.Nil(t, err) + // bypass the check due to securty policy change on gmail + // TODO + // assert.Nil(t, err) /*not work on travis // non-tls connection @@ -91,7 +91,7 @@ func TestPing(t *testing.T) { assert.Nil(t, err) */ - //invalid username/password + // invalid username/password username = "invalid_username" err = Ping(addr, identity, username, password, timeout, tls, insecure) diff --git a/src/common/utils/encrypt.go b/src/common/utils/encrypt.go index abbd7edcb..a6b04b544 100644 --- a/src/common/utils/encrypt.go +++ b/src/common/utils/encrypt.go @@ -65,7 +65,7 @@ func ReversibleDecrypt(str, key string) (string, error) { str = str[len(EncryptHeaderV1):] return decryptAES(str, key) } - //fallback to base64 + // fallback to base64 return decodeB64(str) } diff --git a/src/common/utils/ldap/ldap.go b/src/common/utils/ldap/ldap.go index ecffce9b2..4788d433b 100644 --- a/src/common/utils/ldap/ldap.go +++ b/src/common/utils/ldap/ldap.go @@ -30,20 +30,20 @@ import ( goldap "gopkg.in/ldap.v2" ) -//ErrNotFound ... +// ErrNotFound ... var ErrNotFound = errors.New("entity not found") -//ErrDNSyntax ... +// ErrDNSyntax ... var ErrDNSyntax = errors.New("Invalid DN syntax") -//Session - define a LDAP session +// Session - define a LDAP session type Session struct { ldapConfig models.LdapConf ldapGroupConfig models.LdapGroupConf ldapConn *goldap.Conn } -//LoadSystemLdapConfig - load LDAP configure from adminserver +// LoadSystemLdapConfig - load LDAP configure from adminserver func LoadSystemLdapConfig() (*Session, error) { authMode, err := config.AuthMode() @@ -71,7 +71,7 @@ func LoadSystemLdapConfig() (*Session, error) { return CreateWithAllConfig(*ldapConf, *ldapGroupConfig) } -//CreateWithConfig - +// CreateWithConfig - func CreateWithConfig(ldapConf models.LdapConf) (*Session, error) { return CreateWithAllConfig(ldapConf, models.LdapGroupConf{}) } @@ -140,7 +140,7 @@ func formatURL(ldapURL string) (string, error) { } -//ConnectionTest - test ldap session connection with system default setting +// ConnectionTest - test ldap session connection with system default setting func (session *Session) ConnectionTest() error { session, err := LoadSystemLdapConfig() if err != nil { @@ -150,12 +150,12 @@ func (session *Session) ConnectionTest() error { return ConnectionTestWithAllConfig(session.ldapConfig, session.ldapGroupConfig) } -//ConnectionTestWithConfig - +// ConnectionTestWithConfig - func ConnectionTestWithConfig(ldapConfig models.LdapConf) error { return ConnectionTestWithAllConfig(ldapConfig, models.LdapGroupConf{}) } -//ConnectionTestWithAllConfig - test ldap session connection, out of the scope of normal session create/close +// ConnectionTestWithAllConfig - test ldap session connection, out of the scope of normal session create/close func ConnectionTestWithAllConfig(ldapConfig models.LdapConf, ldapGroupConfig models.LdapGroupConf) error { authMode, err := config.AuthMode() @@ -164,7 +164,7 @@ func ConnectionTestWithAllConfig(ldapConfig models.LdapConf, ldapGroupConfig mod return err } - //If no password present, use the system default password + // If no password present, use the system default password if ldapConfig.LdapSearchPassword == "" && authMode == "ldap_auth" { session, err := LoadSystemLdapConfig() @@ -199,7 +199,7 @@ func ConnectionTestWithAllConfig(ldapConfig models.LdapConf, ldapGroupConfig mod return nil } -//SearchUser - search LDAP user by name +// SearchUser - search LDAP user by name func (session *Session) SearchUser(username string) ([]models.LdapUser, error) { var ldapUsers []models.LdapUser ldapFilter := session.createUserFilter(username) @@ -213,7 +213,7 @@ func (session *Session) SearchUser(username string) ([]models.LdapUser, error) { var u models.LdapUser groupDNList := []string{} for _, attr := range ldapEntry.Attributes { - //OpenLdap sometimes contain leading space in useranme + // OpenLdap sometimes contain leading space in useranme val := strings.TrimSpace(attr.Values[0]) log.Debugf("Current ldap entry attr name: %s\n", attr.Name) switch strings.ToLower(attr.Name) { @@ -249,7 +249,7 @@ func (session *Session) Bind(dn string, password string) error { return session.ldapConn.Bind(dn, password) } -//Open - open Session +// Open - open Session func (session *Session) Open() error { splitLdapURL := strings.Split(session.ldapConfig.LdapURL, "://") @@ -305,9 +305,9 @@ func (session *Session) SearchLdapAttribute(baseDN, filter string, attributes [] baseDN, session.ldapConfig.LdapScope, goldap.NeverDerefAliases, - 0, //Unlimited results - 0, //Search Timeout - false, //Types only + 0, // Unlimited results + 0, // Search Timeout + false, // Types only filter, attributes, nil, @@ -329,7 +329,7 @@ func (session *Session) SearchLdapAttribute(baseDN, filter string, attributes [] } -//CreateUserFilter - create filter to search user with specified username +// CreateUserFilter - create filter to search user with specified username func (session *Session) createUserFilter(username string) string { var filterTag string @@ -353,14 +353,14 @@ func (session *Session) createUserFilter(username string) string { return ldapFilter } -//Close - close current session +// Close - close current session func (session *Session) Close() { if session.ldapConn != nil { session.ldapConn.Close() } } -//SearchGroupByName ... +// SearchGroupByName ... func (session *Session) SearchGroupByName(groupName string) ([]models.LdapGroup, error) { return session.searchGroup(session.ldapGroupConfig.LdapGroupBaseDN, session.ldapGroupConfig.LdapGroupFilter, @@ -368,7 +368,7 @@ func (session *Session) SearchGroupByName(groupName string) ([]models.LdapGroup, session.ldapGroupConfig.LdapGroupNameAttribute) } -//SearchGroupByDN ... +// SearchGroupByDN ... func (session *Session) SearchGroupByDN(groupDN string) ([]models.LdapGroup, error) { if _, err := goldap.ParseDN(groupDN); err != nil { return nil, ErrDNSyntax @@ -396,7 +396,7 @@ func (session *Session) searchGroup(baseDN, filter, groupName, groupNameAttribut var group models.LdapGroup group.GroupDN = ldapEntry.DN for _, attr := range ldapEntry.Attributes { - //OpenLdap sometimes contain leading space in useranme + // OpenLdap sometimes contain leading space in useranme val := strings.TrimSpace(attr.Values[0]) log.Debugf("Current ldap entry attr name: %s\n", attr.Name) switch strings.ToLower(attr.Name) { diff --git a/src/common/utils/ldap/ldap_test.go b/src/common/utils/ldap/ldap_test.go index cbdd7920f..56bb92e40 100644 --- a/src/common/utils/ldap/ldap_test.go +++ b/src/common/utils/ldap/ldap_test.go @@ -23,7 +23,7 @@ var adminServerLdapTestConfig = map[string]interface{}{ common.PostGreSQLUsername: "postgres", common.PostGreSQLPassword: "root123", common.PostGreSQLDatabase: "registry", - //config.SelfRegistration: true, + // config.SelfRegistration: true, common.LDAPURL: "ldap://127.0.0.1", common.LDAPSearchDN: "cn=admin,dc=example,dc=com", common.LDAPSearchPwd: "admin", diff --git a/src/common/utils/log/logger.go b/src/common/utils/log/logger.go index 50bd2af1f..1abe1c7e3 100644 --- a/src/common/utils/log/logger.go +++ b/src/common/utils/log/logger.go @@ -64,12 +64,12 @@ func New(out io.Writer, fmtter Formatter, lvl Level) *Logger { } } -//DefaultLogger returns the default logger within the pkg, i.e. the one used in log.Infof.... +// DefaultLogger returns the default logger within the pkg, i.e. the one used in log.Infof.... func DefaultLogger() *Logger { return logger } -//SetOutput sets the output of Logger l +// SetOutput sets the output of Logger l func (l *Logger) SetOutput(out io.Writer) { l.mu.Lock() defer l.mu.Unlock() @@ -77,7 +77,7 @@ func (l *Logger) SetOutput(out io.Writer) { l.out = out } -//SetFormatter sets the formatter of Logger l +// SetFormatter sets the formatter of Logger l func (l *Logger) SetFormatter(fmtter Formatter) { l.mu.Lock() defer l.mu.Unlock() @@ -85,7 +85,7 @@ func (l *Logger) SetFormatter(fmtter Formatter) { l.fmtter = fmtter } -//SetLevel sets the level of Logger l +// SetLevel sets the level of Logger l func (l *Logger) SetLevel(lvl Level) { l.mu.Lock() defer l.mu.Unlock() @@ -93,17 +93,17 @@ func (l *Logger) SetLevel(lvl Level) { l.lvl = lvl } -//SetOutput sets the output of default Logger +// SetOutput sets the output of default Logger func SetOutput(out io.Writer) { logger.SetOutput(out) } -//SetFormatter sets the formatter of default Logger +// SetFormatter sets the formatter of default Logger func SetFormatter(fmtter Formatter) { logger.SetFormatter(fmtter) } -//SetLevel sets the level of default Logger +// SetLevel sets the level of default Logger func SetLevel(lvl Level) { logger.SetLevel(lvl) } diff --git a/src/common/utils/notary/helper.go b/src/common/utils/notary/helper.go index 0f8c9912f..7aaaa6c30 100644 --- a/src/common/utils/notary/helper.go +++ b/src/common/utils/notary/helper.go @@ -46,7 +46,7 @@ var ( type Target struct { Tag string `json:"tag"` Hashes data.Hashes `json:"hashes"` - //TODO: update fields as needed. + // TODO: update fields as needed. } func init() { @@ -102,7 +102,7 @@ func GetTargets(notaryEndpoint string, username string, fqRepo string) ([]Target } else if err != nil { return res, err } - //Remove root.json such that when remote repository is removed the local cache can't be reused. + // Remove root.json such that when remote repository is removed the local cache can't be reused. rootJSON := path.Join(notaryCachePath, "tuf", fqRepo, "metadata/root.json") rmErr := os.Remove(rootJSON) if rmErr != nil { diff --git a/src/common/utils/registry/auth/tokenauthorizer.go b/src/common/utils/registry/auth/tokenauthorizer.go index 01435d807..f2cb138a6 100644 --- a/src/common/utils/registry/auth/tokenauthorizer.go +++ b/src/common/utils/registry/auth/tokenauthorizer.go @@ -30,7 +30,7 @@ import ( ) const ( - latency int = 10 //second, the network latency when token is received + latency int = 10 // second, the network latency when token is received scheme = "bearer" ) @@ -51,7 +51,7 @@ type tokenAuthorizer struct { // add token to the request func (t *tokenAuthorizer) Modify(req *http.Request) error { - //only handle requests sent to registry + // only handle requests sent to registry goon, err := t.filterReq(req) if err != nil { return err diff --git a/src/common/utils/registry/registry.go b/src/common/utils/registry/registry.go index 11c4512cd..0e009c601 100644 --- a/src/common/utils/registry/registry.go +++ b/src/common/utils/registry/registry.go @@ -110,7 +110,7 @@ func (r *Registry) Catalog() ([]string, error) { } repos = append(repos, catalogResp.Repositories...) - //Link: ; rel="next" + // Link: ; rel="next" link := resp.Header.Get("Link") if strings.HasSuffix(link, `rel="next"`) && strings.Index(link, "<") >= 0 && strings.Index(link, ">") >= 0 { suffix = link[strings.Index(link, "<")+1 : strings.Index(link, ">")] diff --git a/src/common/utils/timemarker.go b/src/common/utils/timemarker.go index 33468c536..1ffa968c5 100644 --- a/src/common/utils/timemarker.go +++ b/src/common/utils/timemarker.go @@ -29,35 +29,35 @@ var ( once sync.Once ) -//TimeMarker is used to control an action not to be taken frequently within the interval +// TimeMarker is used to control an action not to be taken frequently within the interval type TimeMarker struct { sync.RWMutex next time.Time interval time.Duration } -//Mark tries to mark a future time, which is after the duration of interval from the time it's called. +// Mark tries to mark a future time, which is after the duration of interval from the time it's called. func (t *TimeMarker) Mark() { t.Lock() defer t.Unlock() t.next = time.Now().Add(t.interval) } -//Check returns true if the current time is after the mark by this marker, and the caction the mark guards and be taken. +// Check returns true if the current time is after the mark by this marker, and the caction the mark guards and be taken. func (t *TimeMarker) Check() bool { t.RLock() defer t.RUnlock() return time.Now().After(t.next) } -//Next returns the time of the next mark. +// Next returns the time of the next mark. func (t *TimeMarker) Next() time.Time { t.RLock() defer t.RUnlock() return t.next } -//ScanAllMarker ... +// ScanAllMarker ... func ScanAllMarker() *TimeMarker { once.Do(func() { a := os.Getenv("HARBOR_SCAN_ALL_INTERVAL") @@ -74,7 +74,7 @@ func ScanAllMarker() *TimeMarker { return scanAllMarker } -//ScanOverviewMarker ... +// ScanOverviewMarker ... func ScanOverviewMarker() *TimeMarker { return scanOverviewMarker } diff --git a/src/common/utils/uaa/client.go b/src/common/utils/uaa/client.go index 2dd1a36b3..35c5f87fb 100644 --- a/src/common/utils/uaa/client.go +++ b/src/common/utils/uaa/client.go @@ -31,13 +31,13 @@ import ( ) const ( - //TokenURLSuffix ... + // TokenURLSuffix ... TokenURLSuffix = "/oauth/token" - //AuthURLSuffix ... + // AuthURLSuffix ... AuthURLSuffix = "/oauth/authorize" - //UserInfoURLSuffix ... + // UserInfoURLSuffix ... UserInfoURLSuffix = "/userinfo" - //UsersURLSuffix ... + // UsersURLSuffix ... UsersURLSuffix = "/Users" ) @@ -45,13 +45,13 @@ var uaaTransport = &http.Transport{} // Client provides funcs to interact with UAA. type Client interface { - //PasswordAuth accepts username and password, return a token if it's valid. + // PasswordAuth accepts username and password, return a token if it's valid. PasswordAuth(username, password string) (*oauth2.Token, error) - //GetUserInfoByToken send the token to OIDC endpoint to get user info, currently it's also used to validate the token. + // GetUserInfoByToken send the token to OIDC endpoint to get user info, currently it's also used to validate the token. GetUserInfo(token string) (*UserInfo, error) - //SearchUser searches a user based on user name. + // SearchUser searches a user based on user name. SearchUser(name string) ([]*SearchUserEntry, error) - //UpdateConfig updates the config of the current client + // UpdateConfig updates the config of the current client UpdateConfig(cfg *ClientConfig) error } @@ -61,7 +61,7 @@ type ClientConfig struct { ClientSecret string Endpoint string SkipTLSVerify bool - //Absolut path for CA root used to communicate with UAA, only effective when skipTLSVerify set to false. + // Absolut path for CA root used to communicate with UAA, only effective when skipTLSVerify set to false. CARootPath string } @@ -76,13 +76,13 @@ type UserInfo struct { Email string `json:"email"` } -//SearchUserEmailEntry ... +// SearchUserEmailEntry ... type SearchUserEmailEntry struct { Value string `json:"value"` Primary bool `json:"primary"` } -//SearchUserEntry is the struct of an entry of user within search result. +// SearchUserEntry is the struct of an entry of user within search result. type SearchUserEntry struct { ID string `json:"id"` ExtID string `json:"externalId"` @@ -91,7 +91,7 @@ type SearchUserEntry struct { Groups []interface{} } -//SearchUserRes is the struct to parse the result of search user API of UAA +// SearchUserRes is the struct to parse the result of search user API of UAA type SearchUserRes struct { Resources []*SearchUserEntry `json:"resources"` TotalResults int `json:"totalResults"` @@ -104,7 +104,7 @@ type defaultClient struct { oauth2Cfg *oauth2.Config twoLegCfg *clientcredentials.Config endpoint string - //TODO: add public key, etc... + // TODO: add public key, etc... } func (dc *defaultClient) PasswordAuth(username, password string) (*oauth2.Token, error) { @@ -190,7 +190,7 @@ func (dc *defaultClient) UpdateConfig(cfg *ClientConfig) error { return err } pool := x509.NewCertPool() - //Do not throw error if the certificate is malformed, so we can put a place holder. + // Do not throw error if the certificate is malformed, so we can put a place holder. if ok := pool.AppendCertsFromPEM(content); !ok { log.Warningf("Failed to append certificate to cert pool, cert path: %s", cfg.CARootPath) } else { @@ -202,7 +202,7 @@ func (dc *defaultClient) UpdateConfig(cfg *ClientConfig) error { } uaaTransport.TLSClientConfig = tc dc.httpClient.Transport = uaaTransport - //dc.httpClient.Transport = transport. + // dc.httpClient.Transport = transport. oc := &oauth2.Config{ ClientID: cfg.ClientID, diff --git a/src/common/utils/uaa/client_test.go b/src/common/utils/uaa/client_test.go index b8b16ec26..6193aa1aa 100644 --- a/src/common/utils/uaa/client_test.go +++ b/src/common/utils/uaa/client_test.go @@ -99,7 +99,7 @@ func TestNewClientWithCACert(t *testing.T) { } _, err := NewDefaultClient(cfg) assert.Nil(err) - //Skip if it's malformed. + // Skip if it's malformed. cfg.CARootPath = path.Join(currPath(), "test", "non-ca.pem") _, err = NewDefaultClient(cfg) assert.Nil(err) diff --git a/src/common/utils/utils.go b/src/common/utils/utils.go index 12a75a3fc..f6bf117bc 100644 --- a/src/common/utils/utils.go +++ b/src/common/utils/utils.go @@ -128,7 +128,7 @@ func ParseTimeStamp(timestamp string) (*time.Time, error) { return &t, nil } -//ConvertMapToStruct is used to fill the specified struct with map. +// ConvertMapToStruct is used to fill the specified struct with map. func ConvertMapToStruct(object interface{}, values interface{}) error { if object == nil { return errors.New("nil struct is not supported") @@ -168,7 +168,7 @@ func ParseProjectIDOrName(value interface{}) (int64, string, error) { return id, name, nil } -//SafeCastString -- cast a object to string saftely +// SafeCastString -- cast a object to string saftely func SafeCastString(value interface{}) string { if result, ok := value.(string); ok { return result @@ -176,7 +176,7 @@ func SafeCastString(value interface{}) string { return "" } -//SafeCastInt -- +// SafeCastInt -- func SafeCastInt(value interface{}) int { if result, ok := value.(int); ok { return result @@ -184,7 +184,7 @@ func SafeCastInt(value interface{}) int { return 0 } -//SafeCastBool -- +// SafeCastBool -- func SafeCastBool(value interface{}) bool { if result, ok := value.(bool); ok { return result @@ -192,7 +192,7 @@ func SafeCastBool(value interface{}) bool { return false } -//SafeCastFloat64 -- +// SafeCastFloat64 -- func SafeCastFloat64(value interface{}) float64 { if result, ok := value.(float64); ok { return result diff --git a/src/common/utils/utils_test.go b/src/common/utils/utils_test.go index d6c180165..fdd19f744 100644 --- a/src/common/utils/utils_test.go +++ b/src/common/utils/utils_test.go @@ -121,7 +121,7 @@ func TestReversibleEncrypt(t *testing.T) { if decrypted != password { t.Errorf("decrypted password: %s, is not identical to original", decrypted) } - //Test b64 for backward compatibility + // Test b64 for backward compatibility b64password := base64.StdEncoding.EncodeToString([]byte(password)) decrypted, err = ReversibleDecrypt(b64password, key) if err != nil { diff --git a/src/jobservice/api/authenticator.go b/src/jobservice/api/authenticator.go index c8aa3edd3..cfe437be8 100644 --- a/src/jobservice/api/authenticator.go +++ b/src/jobservice/api/authenticator.go @@ -17,22 +17,22 @@ const ( authHeader = "Authorization" ) -//Authenticator defined behaviors of doing auth checking. +// Authenticator defined behaviors of doing auth checking. type Authenticator interface { - //Auth incoming request + // Auth incoming request // - //req *http.Request: the incoming request + // req *http.Request: the incoming request // - //Returns: + // Returns: // nil returned if successfully done // otherwise an error returned DoAuth(req *http.Request) error } -//SecretAuthenticator implements interface 'Authenticator' based on simple secret. +// SecretAuthenticator implements interface 'Authenticator' based on simple secret. type SecretAuthenticator struct{} -//DoAuth implements same method in interface 'Authenticator'. +// DoAuth implements same method in interface 'Authenticator'. func (sa *SecretAuthenticator) DoAuth(req *http.Request) error { if req == nil { return errors.New("nil request") @@ -48,7 +48,7 @@ func (sa *SecretAuthenticator) DoAuth(req *http.Request) error { } secret := strings.TrimSpace(strings.TrimPrefix(h, secretPrefix)) - //incase both two are empty + // incase both two are empty if utils.IsEmptyStr(secret) { return errors.New("empty secret is not allowed") } diff --git a/src/jobservice/api/handler.go b/src/jobservice/api/handler.go index 318a60be1..ec8d4f2fd 100644 --- a/src/jobservice/api/handler.go +++ b/src/jobservice/api/handler.go @@ -18,37 +18,37 @@ import ( "github.com/goharbor/harbor/src/jobservice/opm" ) -//Handler defines approaches to handle the http requests. +// Handler defines approaches to handle the http requests. type Handler interface { - //HandleLaunchJobReq is used to handle the job submission request. + // HandleLaunchJobReq is used to handle the job submission request. HandleLaunchJobReq(w http.ResponseWriter, req *http.Request) - //HandleGetJobReq is used to handle the job stats query request. + // HandleGetJobReq is used to handle the job stats query request. HandleGetJobReq(w http.ResponseWriter, req *http.Request) - //HandleJobActionReq is used to handle the job action requests (stop/retry). + // HandleJobActionReq is used to handle the job action requests (stop/retry). HandleJobActionReq(w http.ResponseWriter, req *http.Request) - //HandleCheckStatusReq is used to handle the job service healthy status checking request. + // HandleCheckStatusReq is used to handle the job service healthy status checking request. HandleCheckStatusReq(w http.ResponseWriter, req *http.Request) - //HandleJobLogReq is used to handle the request of getting job logs + // HandleJobLogReq is used to handle the request of getting job logs HandleJobLogReq(w http.ResponseWriter, req *http.Request) } -//DefaultHandler is the default request handler which implements the Handler interface. +// DefaultHandler is the default request handler which implements the Handler interface. type DefaultHandler struct { controller core.Interface } -//NewDefaultHandler is constructor of DefaultHandler. +// NewDefaultHandler is constructor of DefaultHandler. func NewDefaultHandler(ctl core.Interface) *DefaultHandler { return &DefaultHandler{ controller: ctl, } } -//HandleLaunchJobReq is implementation of method defined in interface 'Handler' +// HandleLaunchJobReq is implementation of method defined in interface 'Handler' func (dh *DefaultHandler) HandleLaunchJobReq(w http.ResponseWriter, req *http.Request) { if !dh.preCheck(w) { return @@ -60,14 +60,14 @@ func (dh *DefaultHandler) HandleLaunchJobReq(w http.ResponseWriter, req *http.Re return } - //unmarshal data + // unmarshal data jobReq := models.JobRequest{} if err = json.Unmarshal(data, &jobReq); err != nil { dh.handleError(w, http.StatusInternalServerError, errs.HandleJSONDataError(err)) return } - //Pass request to the controller for the follow-up. + // Pass request to the controller for the follow-up. jobStats, err := dh.controller.LaunchJob(jobReq) if err != nil { dh.handleError(w, http.StatusInternalServerError, errs.LaunchJobError(err)) @@ -83,7 +83,7 @@ func (dh *DefaultHandler) HandleLaunchJobReq(w http.ResponseWriter, req *http.Re w.Write(data) } -//HandleGetJobReq is implementation of method defined in interface 'Handler' +// HandleGetJobReq is implementation of method defined in interface 'Handler' func (dh *DefaultHandler) HandleGetJobReq(w http.ResponseWriter, req *http.Request) { if !dh.preCheck(w) { return @@ -113,7 +113,7 @@ func (dh *DefaultHandler) HandleGetJobReq(w http.ResponseWriter, req *http.Reque w.Write(data) } -//HandleJobActionReq is implementation of method defined in interface 'Handler' +// HandleJobActionReq is implementation of method defined in interface 'Handler' func (dh *DefaultHandler) HandleJobActionReq(w http.ResponseWriter, req *http.Request) { if !dh.preCheck(w) { return @@ -128,7 +128,7 @@ func (dh *DefaultHandler) HandleJobActionReq(w http.ResponseWriter, req *http.Re return } - //unmarshal data + // unmarshal data jobActionReq := models.JobActionRequest{} if err = json.Unmarshal(data, &jobActionReq); err != nil { dh.handleError(w, http.StatusInternalServerError, errs.HandleJSONDataError(err)) @@ -174,10 +174,10 @@ func (dh *DefaultHandler) HandleJobActionReq(w http.ResponseWriter, req *http.Re return } - w.WriteHeader(http.StatusNoContent) //only header, no content returned + w.WriteHeader(http.StatusNoContent) // only header, no content returned } -//HandleCheckStatusReq is implementation of method defined in interface 'Handler' +// HandleCheckStatusReq is implementation of method defined in interface 'Handler' func (dh *DefaultHandler) HandleCheckStatusReq(w http.ResponseWriter, req *http.Request) { if !dh.preCheck(w) { return @@ -198,7 +198,7 @@ func (dh *DefaultHandler) HandleCheckStatusReq(w http.ResponseWriter, req *http. w.Write(data) } -//HandleJobLogReq is implementation of method defined in interface 'Handler' +// HandleJobLogReq is implementation of method defined in interface 'Handler' func (dh *DefaultHandler) HandleJobLogReq(w http.ResponseWriter, req *http.Request) { if !dh.preCheck(w) { return diff --git a/src/jobservice/api/router.go b/src/jobservice/api/router.go index 1a56ce184..f56a352cf 100644 --- a/src/jobservice/api/router.go +++ b/src/jobservice/api/router.go @@ -15,26 +15,26 @@ const ( apiVersion = "v1" ) -//Router defines the related routes for the job service and directs the request -//to the right handler method. +// Router defines the related routes for the job service and directs the request +// to the right handler method. type Router interface { - //ServeHTTP used to handle the http requests + // ServeHTTP used to handle the http requests ServeHTTP(w http.ResponseWriter, req *http.Request) } -//BaseRouter provides the basic routes for the job service based on the golang http server mux. +// BaseRouter provides the basic routes for the job service based on the golang http server mux. type BaseRouter struct { - //Use mux to keep the routes mapping. + // Use mux to keep the routes mapping. router *mux.Router - //Handler used to handle the requests + // Handler used to handle the requests handler Handler - //Do auth + // Do auth authenticator Authenticator } -//NewBaseRouter is the constructor of BaseRouter. +// NewBaseRouter is the constructor of BaseRouter. func NewBaseRouter(handler Handler, authenticator Authenticator) Router { br := &BaseRouter{ router: mux.NewRouter(), @@ -42,15 +42,15 @@ func NewBaseRouter(handler Handler, authenticator Authenticator) Router { authenticator: authenticator, } - //Register routes here + // Register routes here br.registerRoutes() return br } -//ServeHTTP is the implementation of Router interface. +// ServeHTTP is the implementation of Router interface. func (br *BaseRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { - //Do auth + // Do auth if err := br.authenticator.DoAuth(req); err != nil { authErr := errs.UnauthorizedError(err) w.WriteHeader(http.StatusUnauthorized) @@ -58,11 +58,11 @@ func (br *BaseRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - //Directly pass requests to the server mux. + // Directly pass requests to the server mux. br.router.ServeHTTP(w, req) } -//registerRoutes adds routes to the server mux. +// registerRoutes adds routes to the server mux. func (br *BaseRouter) registerRoutes() { subRouter := br.router.PathPrefix(fmt.Sprintf("%s/%s", baseRoute, apiVersion)).Subrouter() diff --git a/src/jobservice/api/server.go b/src/jobservice/api/server.go index 4088b8ed2..cc9fe5e5d 100644 --- a/src/jobservice/api/server.go +++ b/src/jobservice/api/server.go @@ -14,37 +14,37 @@ import ( "github.com/goharbor/harbor/src/jobservice/logger" ) -//Server serves the http requests. +// Server serves the http requests. type Server struct { - //The real backend http server to serve the requests + // The real backend http server to serve the requests httpServer *http.Server - //Define the routes of http service + // Define the routes of http service router Router - //Keep the configurations of server + // Keep the configurations of server config ServerConfig - //The context + // The context context *env.Context } -//ServerConfig contains the configurations of Server. +// ServerConfig contains the configurations of Server. type ServerConfig struct { - //Protocol server listening on: https/http + // Protocol server listening on: https/http Protocol string - //Server listening port + // Server listening port Port uint - //Cert file path if using https + // Cert file path if using https Cert string - //Key file path if using https + // Key file path if using https Key string } -//NewServer is constructor of Server. +// NewServer is constructor of Server. func NewServer(ctx *env.Context, router Router, cfg ServerConfig) *Server { apiServer := &Server{ router: router, @@ -60,7 +60,7 @@ func NewServer(ctx *env.Context, router Router, cfg ServerConfig) *Server { IdleTimeout: 60 * time.Second, } - //Initialize TLS/SSL config if protocol is https + // Initialize TLS/SSL config if protocol is https if cfg.Protocol == config.JobServiceProtocolHTTPS { tlsCfg := &tls.Config{ MinVersion: tls.VersionTLS12, @@ -83,7 +83,7 @@ func NewServer(ctx *env.Context, router Router, cfg ServerConfig) *Server { return apiServer } -//Start the server to serve requests. +// Start the server to serve requests. func (s *Server) Start() { s.context.WG.Add(1) @@ -106,7 +106,7 @@ func (s *Server) Start() { }() } -//Stop server gracefully. +// Stop server gracefully. func (s *Server) Stop() { go func() { defer func() { diff --git a/src/jobservice/config/config.go b/src/jobservice/config/config.go index 59ea8fe85..31cac5b65 100644 --- a/src/jobservice/config/config.go +++ b/src/jobservice/config/config.go @@ -1,6 +1,6 @@ // Copyright 2018 The Harbor Authors. All rights reserved. -//Package config provides functions to handle the configurations of job service. +// Package config provides functions to handle the configurations of job service. package config import ( @@ -30,81 +30,81 @@ const ( jobServiceAdminServerEndpoint = "ADMINSERVER_URL" jobServiceAuthSecret = "JOBSERVICE_SECRET" - //JobServiceProtocolHTTPS points to the 'https' protocol + // JobServiceProtocolHTTPS points to the 'https' protocol JobServiceProtocolHTTPS = "https" - //JobServiceProtocolHTTP points to the 'http' protocol + // JobServiceProtocolHTTP points to the 'http' protocol JobServiceProtocolHTTP = "http" - //JobServicePoolBackendRedis represents redis backend + // JobServicePoolBackendRedis represents redis backend JobServicePoolBackendRedis = "redis" - //secret of UI + // secret of UI uiAuthSecret = "UI_SECRET" - //redis protocol schema + // redis protocol schema redisSchema = "redis://" ) -//DefaultConfig is the default configuration reference +// DefaultConfig is the default configuration reference var DefaultConfig = &Configuration{} -//Configuration loads and keeps the related configuration items of job service. +// Configuration loads and keeps the related configuration items of job service. type Configuration struct { - //Protocol server listening on: https/http + // Protocol server listening on: https/http Protocol string `yaml:"protocol"` - //Server listening port + // Server listening port Port uint `yaml:"port"` AdminServer string `yaml:"admin_server"` - //Additional config when using https + // Additional config when using https HTTPSConfig *HTTPSConfig `yaml:"https_config,omitempty"` - //Configurations of worker pool + // Configurations of worker pool PoolConfig *PoolConfig `yaml:"worker_pool,omitempty"` - //Logger configurations + // Logger configurations LoggerConfig *LoggerConfig `yaml:"logger,omitempty"` } -//HTTPSConfig keeps additional configurations when using https protocol +// HTTPSConfig keeps additional configurations when using https protocol type HTTPSConfig struct { Cert string `yaml:"cert"` Key string `yaml:"key"` } -//RedisPoolConfig keeps redis pool info. +// RedisPoolConfig keeps redis pool info. type RedisPoolConfig struct { RedisURL string `yaml:"redis_url"` Namespace string `yaml:"namespace"` } -//PoolConfig keeps worker pool configurations. +// PoolConfig keeps worker pool configurations. type PoolConfig struct { - //Worker concurrency + // Worker concurrency WorkerCount uint `yaml:"workers"` Backend string `yaml:"backend"` RedisPoolCfg *RedisPoolConfig `yaml:"redis_pool,omitempty"` } -//LoggerConfig keeps logger configurations. +// LoggerConfig keeps logger configurations. type LoggerConfig struct { BasePath string `yaml:"path"` LogLevel string `yaml:"level"` ArchivePeriod uint `yaml:"archive_period"` } -//Load the configuration options from the specified yaml file. -//If the yaml file is specified and existing, load configurations from yaml file first; -//If detecting env variables is specified, load configurations from env variables; -//Please pay attentions, the detected env variable will override the same configuration item loading from file. +// Load the configuration options from the specified yaml file. +// If the yaml file is specified and existing, load configurations from yaml file first; +// If detecting env variables is specified, load configurations from env variables; +// Please pay attentions, the detected env variable will override the same configuration item loading from file. // -//yamlFilePath string: The path config yaml file -//readEnv bool : Whether detect the environment variables or not +// yamlFilePath string: The path config yaml file +// readEnv bool : Whether detect the environment variables or not func (c *Configuration) Load(yamlFilePath string, detectEnv bool) error { if !utils.IsEmptyStr(yamlFilePath) { - //Try to load from file first + // Try to load from file first data, err := ioutil.ReadFile(yamlFilePath) if err != nil { return err @@ -115,11 +115,11 @@ func (c *Configuration) Load(yamlFilePath string, detectEnv bool) error { } if detectEnv { - //Load from env variables + // Load from env variables c.loadEnvs() } - //translate redis url if needed + // translate redis url if needed if c.PoolConfig != nil && c.PoolConfig.RedisPoolCfg != nil { redisAddress := c.PoolConfig.RedisPoolCfg.RedisURL if !utils.IsEmptyStr(redisAddress) { @@ -135,11 +135,11 @@ func (c *Configuration) Load(yamlFilePath string, detectEnv bool) error { } } - //Validate settings + // Validate settings return c.validate() } -//GetLogBasePath returns the log base path config +// GetLogBasePath returns the log base path config func GetLogBasePath() string { if DefaultConfig.LoggerConfig != nil { return DefaultConfig.LoggerConfig.BasePath @@ -148,7 +148,7 @@ func GetLogBasePath() string { return "" } -//GetLogLevel returns the log level +// GetLogLevel returns the log level func GetLogLevel() string { if DefaultConfig.LoggerConfig != nil { return DefaultConfig.LoggerConfig.LogLevel @@ -157,31 +157,31 @@ func GetLogLevel() string { return "" } -//GetLogArchivePeriod returns the archive period +// GetLogArchivePeriod returns the archive period func GetLogArchivePeriod() uint { if DefaultConfig.LoggerConfig != nil { return DefaultConfig.LoggerConfig.ArchivePeriod } - return 1 //return default + return 1 // return default } -//GetAuthSecret get the auth secret from the env +// GetAuthSecret get the auth secret from the env func GetAuthSecret() string { return utils.ReadEnv(jobServiceAuthSecret) } -//GetUIAuthSecret get the auth secret of UI side +// GetUIAuthSecret get the auth secret of UI side func GetUIAuthSecret() string { return utils.ReadEnv(uiAuthSecret) } -//GetAdminServerEndpoint return the admin server endpoint +// GetAdminServerEndpoint return the admin server endpoint func GetAdminServerEndpoint() string { return DefaultConfig.AdminServer } -//Load env variables +// Load env variables func (c *Configuration) loadEnvs() { prot := utils.ReadEnv(jobServiceProtocol) if !utils.IsEmptyStr(prot) { @@ -195,7 +195,7 @@ func (c *Configuration) loadEnvs() { } } - //Only when protocol is https + // Only when protocol is https if c.Protocol == JobServiceProtocolHTTPS { cert := utils.ReadEnv(jobServiceHTTPCert) if !utils.IsEmptyStr(cert) { @@ -256,7 +256,7 @@ func (c *Configuration) loadEnvs() { } } - //logger + // logger loggerPath := utils.ReadEnv(jobServiceLoggerBasePath) if !utils.IsEmptyStr(loggerPath) { if c.LoggerConfig == nil { @@ -281,14 +281,14 @@ func (c *Configuration) loadEnvs() { } } - //admin server + // admin server if adminServer := utils.ReadEnv(jobServiceAdminServerEndpoint); !utils.IsEmptyStr(adminServer) { c.AdminServer = adminServer } } -//Check if the configurations are valid settings. +// Check if the configurations are valid settings. func (c *Configuration) validate() error { if c.Protocol != JobServiceProtocolHTTPS && c.Protocol != JobServiceProtocolHTTP { @@ -323,7 +323,7 @@ func (c *Configuration) validate() error { return fmt.Errorf("worker pool backend %s does not support", c.PoolConfig.Backend) } - //When backend is redis + // When backend is redis if c.PoolConfig.Backend == JobServicePoolBackendRedis { if c.PoolConfig.RedisPoolCfg == nil { return fmt.Errorf("redis pool must be configured when backend is set to '%s'", c.PoolConfig.Backend) @@ -366,5 +366,5 @@ func (c *Configuration) validate() error { return fmt.Errorf("invalid admin server endpoint: %s", err) } - return nil //valid + return nil // valid } diff --git a/src/jobservice/core/controller.go b/src/jobservice/core/controller.go index 26cbae3cc..f1e3fb4af 100644 --- a/src/jobservice/core/controller.go +++ b/src/jobservice/core/controller.go @@ -21,38 +21,38 @@ const ( hookDeactivated = "error" ) -//Controller implement the core interface and provides related job handle methods. -//Controller will coordinate the lower components to complete the process as a commander role. +// Controller implement the core interface and provides related job handle methods. +// Controller will coordinate the lower components to complete the process as a commander role. type Controller struct { - //Refer the backend pool + // Refer the backend pool backendPool pool.Interface } -//NewController is constructor of Controller. +// NewController is constructor of Controller. func NewController(backendPool pool.Interface) *Controller { return &Controller{ backendPool: backendPool, } } -//LaunchJob is implementation of same method in core interface. +// LaunchJob is implementation of same method in core interface. func (c *Controller) LaunchJob(req models.JobRequest) (models.JobStats, error) { if err := validJobReq(req); err != nil { return models.JobStats{}, err } - //Validate job name + // Validate job name jobType, isKnownJob := c.backendPool.IsKnownJob(req.Job.Name) if !isKnownJob { return models.JobStats{}, fmt.Errorf("job with name '%s' is unknown", req.Job.Name) } - //Validate parameters + // Validate parameters if err := c.backendPool.ValidateJobParameters(jobType, req.Job.Parameters); err != nil { return models.JobStats{}, err } - //Enqueue job regarding of the kind + // Enqueue job regarding of the kind var ( res models.JobStats err error @@ -73,7 +73,7 @@ func (c *Controller) LaunchJob(req models.JobRequest) (models.JobStats, error) { res, err = c.backendPool.Enqueue(req.Job.Name, req.Job.Parameters, req.Job.Metadata.IsUnique) } - //Register status hook? + // Register status hook? if err == nil { if !utils.IsEmptyStr(req.Job.StatusHook) { if err := c.backendPool.RegisterHook(res.Stats.JobID, req.Job.StatusHook); err != nil { @@ -87,7 +87,7 @@ func (c *Controller) LaunchJob(req models.JobRequest) (models.JobStats, error) { return res, err } -//GetJob is implementation of same method in core interface. +// GetJob is implementation of same method in core interface. func (c *Controller) GetJob(jobID string) (models.JobStats, error) { if utils.IsEmptyStr(jobID) { return models.JobStats{}, errors.New("empty job ID") @@ -96,7 +96,7 @@ func (c *Controller) GetJob(jobID string) (models.JobStats, error) { return c.backendPool.GetJobStats(jobID) } -//StopJob is implementation of same method in core interface. +// StopJob is implementation of same method in core interface. func (c *Controller) StopJob(jobID string) error { if utils.IsEmptyStr(jobID) { return errors.New("empty job ID") @@ -105,7 +105,7 @@ func (c *Controller) StopJob(jobID string) error { return c.backendPool.StopJob(jobID) } -//CancelJob is implementation of same method in core interface. +// CancelJob is implementation of same method in core interface. func (c *Controller) CancelJob(jobID string) error { if utils.IsEmptyStr(jobID) { return errors.New("empty job ID") @@ -114,7 +114,7 @@ func (c *Controller) CancelJob(jobID string) error { return c.backendPool.CancelJob(jobID) } -//RetryJob is implementation of same method in core interface. +// RetryJob is implementation of same method in core interface. func (c *Controller) RetryJob(jobID string) error { if utils.IsEmptyStr(jobID) { return errors.New("empty job ID") @@ -123,7 +123,7 @@ func (c *Controller) RetryJob(jobID string) error { return c.backendPool.RetryJob(jobID) } -//GetJobLogData is used to return the log text data for the specified job if exists +// GetJobLogData is used to return the log text data for the specified job if exists func (c *Controller) GetJobLogData(jobID string) ([]byte, error) { if utils.IsEmptyStr(jobID) { return nil, errors.New("empty job ID") @@ -142,7 +142,7 @@ func (c *Controller) GetJobLogData(jobID string) ([]byte, error) { return logData, nil } -//CheckStatus is implementation of same method in core interface. +// CheckStatus is implementation of same method in core interface. func (c *Controller) CheckStatus() (models.JobPoolStats, error) { return c.backendPool.Stats() } diff --git a/src/jobservice/core/interface.go b/src/jobservice/core/interface.go index c9a07cbd1..95d679a27 100644 --- a/src/jobservice/core/interface.go +++ b/src/jobservice/core/interface.go @@ -1,59 +1,59 @@ // Copyright 2018 The Harbor Authors. All rights reserved. -//Package core provides the main job operation interface and components. +// Package core provides the main job operation interface and components. package core import ( "github.com/goharbor/harbor/src/jobservice/models" ) -//Interface defines the related main methods of job operation. +// Interface defines the related main methods of job operation. type Interface interface { - //LaunchJob is used to handle the job submission request. + // LaunchJob is used to handle the job submission request. // - //req JobRequest : Job request contains related required information of queuing job. + // req JobRequest : Job request contains related required information of queuing job. // - //Returns: + // Returns: // JobStats: Job status info with ID and self link returned if job is successfully launched. // error : Error returned if failed to launch the specified job. LaunchJob(req models.JobRequest) (models.JobStats, error) - //GetJob is used to handle the job stats query request. + // GetJob is used to handle the job stats query request. // - //jobID string: ID of job. + // jobID string: ID of job. // - //Returns: + // Returns: // JobStats: Job status info if job exists. // error : Error returned if failed to get the specified job. GetJob(jobID string) (models.JobStats, error) - //StopJob is used to handle the job stopping request. + // StopJob is used to handle the job stopping request. // - //jobID string: ID of job. + // jobID string: ID of job. // - //Return: + // Return: // error : Error returned if failed to stop the specified job. StopJob(jobID string) error - //RetryJob is used to handle the job retrying request. + // RetryJob is used to handle the job retrying request. // - //jobID string : ID of job. + // jobID string : ID of job. // - //Return: + // Return: // error : Error returned if failed to retry the specified job. RetryJob(jobID string) error - //Cancel the job + // Cancel the job // - //jobID string : ID of the enqueued job + // jobID string : ID of the enqueued job // - //Returns: + // Returns: // error : error returned if meet any problems CancelJob(jobID string) error - //CheckStatus is used to handle the job service healthy status checking request. + // CheckStatus is used to handle the job service healthy status checking request. CheckStatus() (models.JobPoolStats, error) - //GetJobLogData is used to return the log text data for the specified job if exists + // GetJobLogData is used to return the log text data for the specified job if exists GetJobLogData(jobID string) ([]byte, error) } diff --git a/src/jobservice/env/context.go b/src/jobservice/env/context.go index 910426672..e9e49a33f 100644 --- a/src/jobservice/env/context.go +++ b/src/jobservice/env/context.go @@ -5,20 +5,20 @@ import ( "sync" ) -//Context keep some sharable materials and system controlling channels. -//The system context.Context interface is also included. +// Context keep some sharable materials and system controlling channels. +// The system context.Context interface is also included. type Context struct { - //The system context with cancel capability. + // The system context with cancel capability. SystemContext context.Context - //Coordination signal + // Coordination signal WG *sync.WaitGroup - //Report errors to bootstrap component - //Once error is reported by lower components, the whole system should exit + // Report errors to bootstrap component + // Once error is reported by lower components, the whole system should exit ErrorChan chan error - //The base job context reference - //It will be the parent conetext of job execution context + // The base job context reference + // It will be the parent conetext of job execution context JobContext JobContext } diff --git a/src/jobservice/env/job_context.go b/src/jobservice/env/job_context.go index ae5021531..fb3ec985c 100644 --- a/src/jobservice/env/job_context.go +++ b/src/jobservice/env/job_context.go @@ -8,54 +8,54 @@ import ( "github.com/goharbor/harbor/src/jobservice/logger" ) -//JobContext is combination of BaseContext and other job specified resources. -//JobContext will be the real execution context for one job. +// JobContext is combination of BaseContext and other job specified resources. +// JobContext will be the real execution context for one job. type JobContext interface { - //Build the context based on the parent context + // Build the context based on the parent context // - //dep JobData : Dependencies for building the context, just in case that the build - //function need some external info + // dep JobData : Dependencies for building the context, just in case that the build + // function need some external info // - //Returns: + // Returns: // new JobContext based on the parent one // error if meet any problems Build(dep JobData) (JobContext, error) - //Get property from the context + // Get property from the context // - //prop string : key of the context property + // prop string : key of the context property // - //Returns: + // Returns: // The data of the specified context property if have // bool to indicate if the property existing Get(prop string) (interface{}, bool) - //SystemContext returns the system context + // SystemContext returns the system context // - //Returns: + // Returns: // context.Context SystemContext() context.Context - //Checkin is bridge func for reporting detailed status + // Checkin is bridge func for reporting detailed status // - //status string : detailed status + // status string : detailed status // - //Returns: + // Returns: // error if meet any problems Checkin(status string) error - //OPCommand return the control operational command like stop/cancel if have + // OPCommand return the control operational command like stop/cancel if have // - //Returns: + // Returns: // op command if have // flag to indicate if have command OPCommand() (string, bool) - //Return the logger + // Return the logger GetLogger() logger.Interface } -//JobData defines job context dependencies. +// JobData defines job context dependencies. type JobData struct { ID string Name string @@ -63,5 +63,5 @@ type JobData struct { ExtraData map[string]interface{} } -//JobContextInitializer is a func to initialize the concrete job context +// JobContextInitializer is a func to initialize the concrete job context type JobContextInitializer func(ctx *Context) (JobContext, error) diff --git a/src/jobservice/errs/errors.go b/src/jobservice/errs/errors.go index 2c58d1c88..4650827a0 100644 --- a/src/jobservice/errs/errors.go +++ b/src/jobservice/errs/errors.go @@ -1,6 +1,6 @@ // Copyright 2018 The Harbor Authors. All rights reserved. -//Package errs define some system errors with specified types. +// Package errs define some system errors with specified types. package errs import ( @@ -8,46 +8,46 @@ import ( ) const ( - //JobStoppedErrorCode is code for jobStoppedError + // JobStoppedErrorCode is code for jobStoppedError JobStoppedErrorCode = 10000 + iota - //JobCancelledErrorCode is code for jobCancelledError + // JobCancelledErrorCode is code for jobCancelledError JobCancelledErrorCode - //ReadRequestBodyErrorCode is code for the error of reading http request body error + // ReadRequestBodyErrorCode is code for the error of reading http request body error ReadRequestBodyErrorCode - //HandleJSONDataErrorCode is code for the error of handling json data error + // HandleJSONDataErrorCode is code for the error of handling json data error HandleJSONDataErrorCode - //MissingBackendHandlerErrorCode is code for the error of missing backend controller + // MissingBackendHandlerErrorCode is code for the error of missing backend controller MissingBackendHandlerErrorCode - //LaunchJobErrorCode is code for the error of launching job + // LaunchJobErrorCode is code for the error of launching job LaunchJobErrorCode - //CheckStatsErrorCode is code for the error of checking stats of worker pool + // CheckStatsErrorCode is code for the error of checking stats of worker pool CheckStatsErrorCode - //GetJobStatsErrorCode is code for the error of getting stats of enqueued job + // GetJobStatsErrorCode is code for the error of getting stats of enqueued job GetJobStatsErrorCode - //StopJobErrorCode is code for the error of stopping job + // StopJobErrorCode is code for the error of stopping job StopJobErrorCode - //CancelJobErrorCode is code for the error of cancelling job + // CancelJobErrorCode is code for the error of cancelling job CancelJobErrorCode - //RetryJobErrorCode is code for the error of retrying job + // RetryJobErrorCode is code for the error of retrying job RetryJobErrorCode - //UnknownActionNameErrorCode is code for the case of unknown action name + // UnknownActionNameErrorCode is code for the case of unknown action name UnknownActionNameErrorCode - //GetJobLogErrorCode is code for the error of getting job log + // GetJobLogErrorCode is code for the error of getting job log GetJobLogErrorCode - //NoObjectFoundErrorCode is code for the error of no object found + // NoObjectFoundErrorCode is code for the error of no object found NoObjectFoundErrorCode - //UnAuthorizedErrorCode is code for the error of unauthorized accessing + // UnAuthorizedErrorCode is code for the error of unauthorized accessing UnAuthorizedErrorCode ) -//baseError ... +// baseError ... type baseError struct { Code uint16 `json:"code"` Err string `json:"message"` Description string `json:"details,omitempty"` } -//Error is implementation of error interface. +// Error is implementation of error interface. func (be baseError) Error() string { if data, err := json.Marshal(be); err == nil { return string(data) @@ -56,7 +56,7 @@ func (be baseError) Error() string { return "{}" } -//New customized errors +// New customized errors func New(code uint16, err string, description string) error { return baseError{ Code: code, @@ -65,72 +65,72 @@ func New(code uint16, err string, description string) error { } } -//ReadRequestBodyError is error wrapper for the error of reading request body. +// ReadRequestBodyError is error wrapper for the error of reading request body. func ReadRequestBodyError(err error) error { return New(ReadRequestBodyErrorCode, "Read request body failed with error", err.Error()) } -//HandleJSONDataError is error wrapper for the error of handling json data. +// HandleJSONDataError is error wrapper for the error of handling json data. func HandleJSONDataError(err error) error { return New(HandleJSONDataErrorCode, "Handle json data failed with error", err.Error()) } -//MissingBackendHandlerError is error wrapper for the error of missing backend controller. +// MissingBackendHandlerError is error wrapper for the error of missing backend controller. func MissingBackendHandlerError(err error) error { return New(MissingBackendHandlerErrorCode, "Missing backend controller to handle the requests", err.Error()) } -//LaunchJobError is error wrapper for the error of launching job failed. +// LaunchJobError is error wrapper for the error of launching job failed. func LaunchJobError(err error) error { return New(LaunchJobErrorCode, "Launch job failed with error", err.Error()) } -//CheckStatsError is error wrapper for the error of checking stats failed +// CheckStatsError is error wrapper for the error of checking stats failed func CheckStatsError(err error) error { return New(CheckStatsErrorCode, "Check stats of server failed with error", err.Error()) } -//GetJobStatsError is error wrapper for the error of getting job stats +// GetJobStatsError is error wrapper for the error of getting job stats func GetJobStatsError(err error) error { return New(GetJobStatsErrorCode, "Get job stats failed with error", err.Error()) } -//StopJobError is error for the case of stopping job failed +// StopJobError is error for the case of stopping job failed func StopJobError(err error) error { return New(StopJobErrorCode, "Stop job failed with error", err.Error()) } -//CancelJobError is error for the case of cancelling job failed +// CancelJobError is error for the case of cancelling job failed func CancelJobError(err error) error { return New(CancelJobErrorCode, "Cancel job failed with error", err.Error()) } -//RetryJobError is error for the case of retrying job failed +// RetryJobError is error for the case of retrying job failed func RetryJobError(err error) error { return New(RetryJobErrorCode, "Retry job failed with error", err.Error()) } -//UnknownActionNameError is error for the case of getting unknown job action +// UnknownActionNameError is error for the case of getting unknown job action func UnknownActionNameError(err error) error { return New(UnknownActionNameErrorCode, "Unknown job action name", err.Error()) } -//GetJobLogError is error for the case of getting job log failed +// GetJobLogError is error for the case of getting job log failed func GetJobLogError(err error) error { return New(GetJobLogErrorCode, "Failed to get the job log", err.Error()) } -//UnauthorizedError is error for the case of unauthorized accessing +// UnauthorizedError is error for the case of unauthorized accessing func UnauthorizedError(err error) error { return New(UnAuthorizedErrorCode, "Unauthorized", err.Error()) } -//jobStoppedError is designed for the case of stopping job. +// jobStoppedError is designed for the case of stopping job. type jobStoppedError struct { baseError } -//JobStoppedError is error wrapper for the case of stopping job. +// JobStoppedError is error wrapper for the case of stopping job. func JobStoppedError() error { return jobStoppedError{ baseError{ @@ -140,12 +140,12 @@ func JobStoppedError() error { } } -//jobCancelledError is designed for the case of cancelling job. +// jobCancelledError is designed for the case of cancelling job. type jobCancelledError struct { baseError } -//JobCancelledError is error wrapper for the case of cancelling job. +// JobCancelledError is error wrapper for the case of cancelling job. func JobCancelledError() error { return jobCancelledError{ baseError{ @@ -155,12 +155,12 @@ func JobCancelledError() error { } } -//objectNotFound is designed for the case of no object found +// objectNotFound is designed for the case of no object found type objectNotFoundError struct { baseError } -//NoObjectFoundError is error wrapper for the case of no object found +// NoObjectFoundError is error wrapper for the case of no object found func NoObjectFoundError(object string) error { return objectNotFoundError{ baseError{ @@ -171,19 +171,19 @@ func NoObjectFoundError(object string) error { } } -//IsJobStoppedError return true if the error is jobStoppedError +// IsJobStoppedError return true if the error is jobStoppedError func IsJobStoppedError(err error) bool { _, ok := err.(jobStoppedError) return ok } -//IsJobCancelledError return true if the error is jobCancelledError +// IsJobCancelledError return true if the error is jobCancelledError func IsJobCancelledError(err error) bool { _, ok := err.(jobCancelledError) return ok } -//IsObjectNotFoundError return true if the error is objectNotFoundError +// IsObjectNotFoundError return true if the error is objectNotFoundError func IsObjectNotFoundError(err error) bool { _, ok := err.(objectNotFoundError) return ok diff --git a/src/jobservice/job/impl/context.go b/src/jobservice/job/impl/context.go index ffe13b6d5..91303d0b3 100644 --- a/src/jobservice/job/impl/context.go +++ b/src/jobservice/job/impl/context.go @@ -25,28 +25,28 @@ const ( maxRetryTimes = 5 ) -//Context ... +// Context ... type Context struct { - //System context + // System context sysContext context.Context - //Logger for job + // Logger for job logger logger.Interface - //op command func + // op command func opCommandFunc job.CheckOPCmdFunc - //checkin func + // checkin func checkInFunc job.CheckInFunc - //other required information + // other required information properties map[string]interface{} - //admin server client + // admin server client adminClient client.Client } -//NewContext ... +// NewContext ... func NewContext(sysCtx context.Context, adminClient client.Client) *Context { return &Context{ sysContext: sysCtx, @@ -55,7 +55,7 @@ func NewContext(sysCtx context.Context, adminClient client.Client) *Context { } } -//Init ... +// Init ... func (c *Context) Init() error { var ( counter = 0 @@ -83,8 +83,8 @@ func (c *Context) Init() error { return dao.InitDatabase(db) } -//Build implements the same method in env.JobContext interface -//This func will build the job execution context before running +// Build implements the same method in env.JobContext interface +// This func will build the job execution context before running func (c *Context) Build(dep env.JobData) (env.JobContext, error) { jContext := &Context{ sysContext: c.sysContext, @@ -92,14 +92,14 @@ func (c *Context) Build(dep env.JobData) (env.JobContext, error) { properties: make(map[string]interface{}), } - //Copy properties + // Copy properties if len(c.properties) > 0 { for k, v := range c.properties { jContext.properties[k] = v } } - //Refresh admin server properties + // Refresh admin server properties props, err := c.adminClient.GetCfgs() if err != nil { return nil, err @@ -108,7 +108,7 @@ func (c *Context) Build(dep env.JobData) (env.JobContext, error) { jContext.properties[k] = v } - //Init logger here + // Init logger here logPath := fmt.Sprintf("%s/%s.log", config.GetLogBasePath(), dep.ID) jContext.logger = jlogger.New(logPath, config.GetLogLevel()) if jContext.logger == nil { @@ -141,18 +141,18 @@ func (c *Context) Build(dep env.JobData) (env.JobContext, error) { return jContext, nil } -//Get implements the same method in env.JobContext interface +// Get implements the same method in env.JobContext interface func (c *Context) Get(prop string) (interface{}, bool) { v, ok := c.properties[prop] return v, ok } -//SystemContext implements the same method in env.JobContext interface +// SystemContext implements the same method in env.JobContext interface func (c *Context) SystemContext() context.Context { return c.sysContext } -//Checkin is bridge func for reporting detailed status +// Checkin is bridge func for reporting detailed status func (c *Context) Checkin(status string) error { if c.checkInFunc != nil { c.checkInFunc(status) @@ -163,7 +163,7 @@ func (c *Context) Checkin(status string) error { return nil } -//OPCommand return the control operational command like stop/cancel if have +// OPCommand return the control operational command like stop/cancel if have func (c *Context) OPCommand() (string, bool) { if c.opCommandFunc != nil { return c.opCommandFunc() @@ -172,7 +172,7 @@ func (c *Context) OPCommand() (string, bool) { return "", false } -//GetLogger returns the logger +// GetLogger returns the logger func (c *Context) GetLogger() logger.Interface { return c.logger } diff --git a/src/jobservice/job/impl/demo_job.go b/src/jobservice/job/impl/demo_job.go index 97e437f75..63a553c31 100644 --- a/src/jobservice/job/impl/demo_job.go +++ b/src/jobservice/job/impl/demo_job.go @@ -17,20 +17,20 @@ import ( "github.com/goharbor/harbor/src/jobservice/env" ) -//DemoJob is the job to demostrate the job interface. +// DemoJob is the job to demostrate the job interface. type DemoJob struct{} -//MaxFails is implementation of same method in Interface. +// MaxFails is implementation of same method in Interface. func (dj *DemoJob) MaxFails() uint { return 3 } -//ShouldRetry ... +// ShouldRetry ... func (dj *DemoJob) ShouldRetry() bool { return true } -//Validate is implementation of same method in Interface. +// Validate is implementation of same method in Interface. func (dj *DemoJob) Validate(params map[string]interface{}) error { if params == nil || len(params) == 0 { return errors.New("parameters required for replication job") @@ -47,7 +47,7 @@ func (dj *DemoJob) Validate(params map[string]interface{}) error { return nil } -//Run the replication logic here. +// Run the replication logic here. func (dj *DemoJob) Run(ctx env.JobContext, params map[string]interface{}) error { logger := ctx.GetLogger() @@ -69,9 +69,9 @@ func (dj *DemoJob) Run(ctx env.JobContext, params map[string]interface{}) error /*if 1 != 0 { return errors.New("I suicide") }*/ - //runtime error - //var runtime_err error = nil - //fmt.Println(runtime_err.Error()) + // runtime error + // var runtime_err error = nil + // fmt.Println(runtime_err.Error()) logger.Info("check in 30%") ctx.Checkin("30%") @@ -83,10 +83,10 @@ func (dj *DemoJob) Run(ctx env.JobContext, params map[string]interface{}) error ctx.Checkin("100%") time.Sleep(1 * time.Second) - //HOLD ON FOR A WHILE + // HOLD ON FOR A WHILE logger.Error("Holding for 20 sec") <-time.After(15 * time.Second) - //logger.Fatal("I'm back, check if I'm stopped/cancelled") + // logger.Fatal("I'm back, check if I'm stopped/cancelled") if cmd, ok := ctx.OPCommand(); ok { logger.Infof("cmd=%s\n", cmd) diff --git a/src/jobservice/job/impl/known_jobs.go b/src/jobservice/job/impl/known_jobs.go index 507ea49b3..5e4a115b0 100644 --- a/src/jobservice/job/impl/known_jobs.go +++ b/src/jobservice/job/impl/known_jobs.go @@ -2,9 +2,9 @@ package impl -//Define the register name constants of known jobs +// Define the register name constants of known jobs const ( - //KnownJobDemo is name of demo job + // KnownJobDemo is name of demo job KnownJobDemo = "DEMO" ) diff --git a/src/jobservice/job/impl/logger/job_logger.go b/src/jobservice/job/impl/logger/job_logger.go index 4b0c78a92..66c25cf52 100644 --- a/src/jobservice/job/impl/logger/job_logger.go +++ b/src/jobservice/job/impl/logger/job_logger.go @@ -8,15 +8,15 @@ import ( "github.com/goharbor/harbor/src/jobservice/logger" ) -//JobLogger is an implementation of logger.Interface. -//It used in the job to output logs to the logfile. +// JobLogger is an implementation of logger.Interface. +// It used in the job to output logs to the logfile. type JobLogger struct { backendLogger *log.Logger streamRef *os.File } -//New logger -//nil might be returned +// New logger +// nil might be returned func New(logPath string, level string) logger.Interface { f, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY, 0644) if err != nil { @@ -31,8 +31,8 @@ func New(logPath string, level string) logger.Interface { } } -//Close the opened io stream -//Implements logger.Closer interface +// Close the opened io stream +// Implements logger.Closer interface func (jl *JobLogger) Close() error { if jl.streamRef != nil { return jl.streamRef.Close() @@ -41,52 +41,52 @@ func (jl *JobLogger) Close() error { return nil } -//Debug ... +// Debug ... func (jl *JobLogger) Debug(v ...interface{}) { jl.backendLogger.Debug(v...) } -//Debugf with format +// Debugf with format func (jl *JobLogger) Debugf(format string, v ...interface{}) { jl.backendLogger.Debugf(format, v...) } -//Info ... +// Info ... func (jl *JobLogger) Info(v ...interface{}) { jl.backendLogger.Info(v...) } -//Infof with format +// Infof with format func (jl *JobLogger) Infof(format string, v ...interface{}) { jl.backendLogger.Infof(format, v...) } -//Warning ... +// Warning ... func (jl *JobLogger) Warning(v ...interface{}) { jl.backendLogger.Warning(v...) } -//Warningf with format +// Warningf with format func (jl *JobLogger) Warningf(format string, v ...interface{}) { jl.backendLogger.Warningf(format, v...) } -//Error ... +// Error ... func (jl *JobLogger) Error(v ...interface{}) { jl.backendLogger.Error(v...) } -//Errorf with format +// Errorf with format func (jl *JobLogger) Errorf(format string, v ...interface{}) { jl.backendLogger.Errorf(format, v...) } -//Fatal error +// Fatal error func (jl *JobLogger) Fatal(v ...interface{}) { jl.backendLogger.Fatal(v...) } -//Fatalf error +// Fatalf error func (jl *JobLogger) Fatalf(format string, v ...interface{}) { jl.backendLogger.Fatalf(format, v...) } diff --git a/src/jobservice/job/impl/logger/service_logger.go b/src/jobservice/job/impl/logger/service_logger.go index 27bdc57fd..c300a4390 100644 --- a/src/jobservice/job/impl/logger/service_logger.go +++ b/src/jobservice/job/impl/logger/service_logger.go @@ -6,14 +6,14 @@ import ( "github.com/goharbor/harbor/src/common/utils/log" ) -//ServiceLogger is an implementation of logger.Interface. -//It used to log info in workerpool components. +// ServiceLogger is an implementation of logger.Interface. +// It used to log info in workerpool components. type ServiceLogger struct { backendLogger *log.Logger } -//NewServiceLogger to create new logger for job service -//nil might be returned +// NewServiceLogger to create new logger for job service +// nil might be returned func NewServiceLogger(level string) *ServiceLogger { logLevel := parseLevel(level) backendLogger := log.New(os.Stdout, log.NewTextFormatter(), logLevel) @@ -23,52 +23,52 @@ func NewServiceLogger(level string) *ServiceLogger { } } -//Debug ... +// Debug ... func (sl *ServiceLogger) Debug(v ...interface{}) { sl.backendLogger.Debug(v...) } -//Debugf with format +// Debugf with format func (sl *ServiceLogger) Debugf(format string, v ...interface{}) { sl.backendLogger.Debugf(format, v...) } -//Info ... +// Info ... func (sl *ServiceLogger) Info(v ...interface{}) { sl.backendLogger.Info(v...) } -//Infof with format +// Infof with format func (sl *ServiceLogger) Infof(format string, v ...interface{}) { sl.backendLogger.Infof(format, v...) } -//Warning ... +// Warning ... func (sl *ServiceLogger) Warning(v ...interface{}) { sl.backendLogger.Warning(v...) } -//Warningf with format +// Warningf with format func (sl *ServiceLogger) Warningf(format string, v ...interface{}) { sl.backendLogger.Warningf(format, v...) } -//Error ... +// Error ... func (sl *ServiceLogger) Error(v ...interface{}) { sl.backendLogger.Error(v...) } -//Errorf with format +// Errorf with format func (sl *ServiceLogger) Errorf(format string, v ...interface{}) { sl.backendLogger.Errorf(format, v...) } -//Fatal error +// Fatal error func (sl *ServiceLogger) Fatal(v ...interface{}) { sl.backendLogger.Fatal(v...) } -//Fatalf error +// Fatalf error func (sl *ServiceLogger) Fatalf(format string, v ...interface{}) { sl.backendLogger.Fatalf(format, v...) } diff --git a/src/jobservice/job/impl/utils/utils.go b/src/jobservice/job/impl/utils/utils.go index e541c3ac7..dd31bdf5b 100644 --- a/src/jobservice/job/impl/utils/utils.go +++ b/src/jobservice/job/impl/utils/utils.go @@ -64,7 +64,7 @@ func BuildBlobURL(endpoint, repository, digest string) string { return fmt.Sprintf("%s/v2/%s/blobs/%s", endpoint, repository, digest) } -//GetTokenForRepo is used for job handler to get a token for clair. +// GetTokenForRepo is used for job handler to get a token for clair. func GetTokenForRepo(repository, secret, internalTokenServiceURL string) (string, error) { credential := httpauth.NewSecretAuthorizer(secret) t, err := auth.GetToken(internalTokenServiceURL, true, credential, diff --git a/src/jobservice/job/interface.go b/src/jobservice/job/interface.go index 06d547603..b53d0f259 100644 --- a/src/jobservice/job/interface.go +++ b/src/jobservice/job/interface.go @@ -4,42 +4,42 @@ package job import "github.com/goharbor/harbor/src/jobservice/env" -//CheckOPCmdFunc is the function to check if the related operation commands -//like STOP or CANCEL is fired for the specified job. If yes, return the -//command code for job to determine if take corresponding action. +// CheckOPCmdFunc is the function to check if the related operation commands +// like STOP or CANCEL is fired for the specified job. If yes, return the +// command code for job to determine if take corresponding action. type CheckOPCmdFunc func() (string, bool) -//CheckInFunc is designed for job to report more detailed progress info +// CheckInFunc is designed for job to report more detailed progress info type CheckInFunc func(message string) -//Interface defines the related injection and run entry methods. +// Interface defines the related injection and run entry methods. type Interface interface { - //Declare how many times the job can be retried if failed. + // Declare how many times the job can be retried if failed. // - //Return: + // Return: // uint: the failure count allowed. If it is set to 0, then default value 4 is used. MaxFails() uint - //Tell the worker pool if retry the failed job when the fails is - //still less that the number declared by the method 'MaxFails'. + // Tell the worker pool if retry the failed job when the fails is + // still less that the number declared by the method 'MaxFails'. // - //Returns: + // Returns: // true for retry and false for none-retry ShouldRetry() bool - //Indicate whether the parameters of job are valid. + // Indicate whether the parameters of job are valid. // - //Return: + // Return: // error if parameters are not valid. NOTES: If no parameters needed, directly return nil. Validate(params map[string]interface{}) error - //Run the business logic here. - //The related arguments will be injected by the workerpool. + // Run the business logic here. + // The related arguments will be injected by the workerpool. // - //ctx env.JobContext : Job execution context. - //params map[string]interface{} : parameters with key-pair style for the job execution. + // ctx env.JobContext : Job execution context. + // params map[string]interface{} : parameters with key-pair style for the job execution. // - //Returns: + // Returns: // error if failed to run. NOTES: If job is stopped or cancelled, a specified error should be returned // Run(ctx env.JobContext, params map[string]interface{}) error diff --git a/src/jobservice/job/job_kinds.go b/src/jobservice/job/job_kinds.go index 742f06375..331a8ed87 100644 --- a/src/jobservice/job/job_kinds.go +++ b/src/jobservice/job/job_kinds.go @@ -3,10 +3,10 @@ package job const ( - //JobKindGeneric : Kind of generic job + // JobKindGeneric : Kind of generic job JobKindGeneric = "Generic" - //JobKindScheduled : Kind of scheduled job + // JobKindScheduled : Kind of scheduled job JobKindScheduled = "Scheduled" - //JobKindPeriodic : Kind of periodic job + // JobKindPeriodic : Kind of periodic job JobKindPeriodic = "Periodic" ) diff --git a/src/jobservice/job/job_status.go b/src/jobservice/job/job_status.go index 500b08c66..2d5b2a03e 100644 --- a/src/jobservice/job/job_status.go +++ b/src/jobservice/job/job_status.go @@ -3,18 +3,18 @@ package job const ( - //JobStatusPending : job status pending + // JobStatusPending : job status pending JobStatusPending = "Pending" - //JobStatusRunning : job status running + // JobStatusRunning : job status running JobStatusRunning = "Running" - //JobStatusStopped : job status stopped + // JobStatusStopped : job status stopped JobStatusStopped = "Stopped" - //JobStatusCancelled : job status cancelled + // JobStatusCancelled : job status cancelled JobStatusCancelled = "Cancelled" - //JobStatusError : job status error + // JobStatusError : job status error JobStatusError = "Error" - //JobStatusSuccess : job status success + // JobStatusSuccess : job status success JobStatusSuccess = "Success" - //JobStatusScheduled : job status scheduled + // JobStatusScheduled : job status scheduled JobStatusScheduled = "Scheduled" ) diff --git a/src/jobservice/logger/closer.go b/src/jobservice/logger/closer.go index 224716956..02f2b5140 100644 --- a/src/jobservice/logger/closer.go +++ b/src/jobservice/logger/closer.go @@ -2,8 +2,8 @@ package logger -//Closer defines method to close the open io stream used by logger. +// Closer defines method to close the open io stream used by logger. type Closer interface { - //Close the opened io stream + // Close the opened io stream Close() error } diff --git a/src/jobservice/logger/interface.go b/src/jobservice/logger/interface.go index b9b9d9d57..7bf2d8ad5 100644 --- a/src/jobservice/logger/interface.go +++ b/src/jobservice/logger/interface.go @@ -2,35 +2,35 @@ package logger -//Interface for logger. +// Interface for logger. type Interface interface { - //For debuging + // For debuging Debug(v ...interface{}) - //For debuging with format + // For debuging with format Debugf(format string, v ...interface{}) - //For logging info + // For logging info Info(v ...interface{}) - //For logging info with format + // For logging info with format Infof(format string, v ...interface{}) - //For warning + // For warning Warning(v ...interface{}) - //For warning with format + // For warning with format Warningf(format string, v ...interface{}) - //For logging error + // For logging error Error(v ...interface{}) - //For logging error with format + // For logging error with format Errorf(format string, v ...interface{}) - //For fatal error + // For fatal error Fatal(v ...interface{}) - //For fatal error with error + // For fatal error with error Fatalf(format string, v ...interface{}) } diff --git a/src/jobservice/logger/service_logger.go b/src/jobservice/logger/service_logger.go index f5877fbba..4d9b8c99d 100644 --- a/src/jobservice/logger/service_logger.go +++ b/src/jobservice/logger/service_logger.go @@ -6,15 +6,15 @@ import ( "log" ) -//sLogger is used to log for workerpool itself +// sLogger is used to log for workerpool itself var sLogger Interface -//SetLogger sets the logger implementation +// SetLogger sets the logger implementation func SetLogger(logger Interface) { sLogger = logger } -//Debug ... +// Debug ... func Debug(v ...interface{}) { if sLogger != nil { sLogger.Debug(v...) @@ -24,7 +24,7 @@ func Debug(v ...interface{}) { log.Println(v...) } -//Debugf for debuging with format +// Debugf for debuging with format func Debugf(format string, v ...interface{}) { if sLogger != nil { sLogger.Debugf(format, v...) @@ -34,7 +34,7 @@ func Debugf(format string, v ...interface{}) { log.Printf(format, v...) } -//Info ... +// Info ... func Info(v ...interface{}) { if sLogger != nil { sLogger.Info(v...) @@ -44,7 +44,7 @@ func Info(v ...interface{}) { log.Println(v...) } -//Infof for logging info with format +// Infof for logging info with format func Infof(format string, v ...interface{}) { if sLogger != nil { sLogger.Infof(format, v...) @@ -54,7 +54,7 @@ func Infof(format string, v ...interface{}) { log.Printf(format, v...) } -//Warning ... +// Warning ... func Warning(v ...interface{}) { if sLogger != nil { sLogger.Warning(v...) @@ -64,7 +64,7 @@ func Warning(v ...interface{}) { log.Println(v...) } -//Warningf for warning with format +// Warningf for warning with format func Warningf(format string, v ...interface{}) { if sLogger != nil { sLogger.Warningf(format, v...) @@ -74,7 +74,7 @@ func Warningf(format string, v ...interface{}) { log.Printf(format, v...) } -//Error for logging error +// Error for logging error func Error(v ...interface{}) { if sLogger != nil { sLogger.Error(v...) @@ -84,7 +84,7 @@ func Error(v ...interface{}) { log.Println(v...) } -//Errorf for logging error with format +// Errorf for logging error with format func Errorf(format string, v ...interface{}) { if sLogger != nil { sLogger.Errorf(format, v...) @@ -94,7 +94,7 @@ func Errorf(format string, v ...interface{}) { log.Printf(format, v...) } -//Fatal ... +// Fatal ... func Fatal(v ...interface{}) { if sLogger != nil { sLogger.Fatal(v...) @@ -104,7 +104,7 @@ func Fatal(v ...interface{}) { log.Fatal(v...) } -//Fatalf for fatal error with error +// Fatalf for fatal error with error func Fatalf(format string, v ...interface{}) { if sLogger != nil { sLogger.Fatalf(format, v...) diff --git a/src/jobservice/logger/service_logger_test.go b/src/jobservice/logger/service_logger_test.go index 8234324b1..9caca9949 100644 --- a/src/jobservice/logger/service_logger_test.go +++ b/src/jobservice/logger/service_logger_test.go @@ -24,52 +24,52 @@ func TestServiceLogger(t *testing.T) { type fakeLogger struct{} -//For debuging +// For debuging func (fl *fakeLogger) Debug(v ...interface{}) { fmt.Println(v...) } -//For debuging with format +// For debuging with format func (fl *fakeLogger) Debugf(format string, v ...interface{}) { fmt.Printf(format, v...) } -//For logging info +// For logging info func (fl *fakeLogger) Info(v ...interface{}) { fmt.Println(v...) } -//For logging info with format +// For logging info with format func (fl *fakeLogger) Infof(format string, v ...interface{}) { fmt.Printf(format, v...) } -//For warning +// For warning func (fl *fakeLogger) Warning(v ...interface{}) { fmt.Println(v...) } -//For warning with format +// For warning with format func (fl *fakeLogger) Warningf(format string, v ...interface{}) { fmt.Printf(format, v...) } -//For logging error +// For logging error func (fl *fakeLogger) Error(v ...interface{}) { fmt.Println(v...) } -//For logging error with format +// For logging error with format func (fl *fakeLogger) Errorf(format string, v ...interface{}) { fmt.Printf(format, v...) } -//For fatal error +// For fatal error func (fl *fakeLogger) Fatal(v ...interface{}) { fmt.Println(v...) } -//For fatal error with error +// For fatal error with error func (fl *fakeLogger) Fatalf(format string, v ...interface{}) { fmt.Printf(format, v...) } diff --git a/src/jobservice/logger/sweeper.go b/src/jobservice/logger/sweeper.go index ad4ab1cff..2e3a73eb2 100644 --- a/src/jobservice/logger/sweeper.go +++ b/src/jobservice/logger/sweeper.go @@ -14,26 +14,26 @@ const ( oneDay = 3600 * 24 ) -//Sweeper takes charge of archive the outdated log files of jobs. +// Sweeper takes charge of archive the outdated log files of jobs. type Sweeper struct { context context.Context workDir string period uint } -//NewSweeper creates new prt of Sweeper +// NewSweeper creates new prt of Sweeper func NewSweeper(ctx context.Context, workDir string, period uint) *Sweeper { return &Sweeper{ctx, workDir, period} } -//Start to work +// Start to work func (s *Sweeper) Start() { go s.loop() Info("Logger sweeper is started") } func (s *Sweeper) loop() { - //Apply default if needed before starting + // Apply default if needed before starting if s.period == 0 { s.period = 1 } @@ -42,7 +42,7 @@ func (s *Sweeper) loop() { Info("Logger sweeper is stopped") }() - //First run + // First run go s.clear() ticker := time.NewTicker(time.Duration(s.period*oneDay+5) * time.Second) diff --git a/src/jobservice/main.go b/src/jobservice/main.go index f6efa6596..9ec3983c6 100644 --- a/src/jobservice/main.go +++ b/src/jobservice/main.go @@ -15,22 +15,22 @@ import ( ) func main() { - //Get parameters + // Get parameters configPath := flag.String("c", "", "Specify the yaml config file path") flag.Parse() - //Missing config file + // Missing config file if configPath == nil || utils.IsEmptyStr(*configPath) { flag.Usage() logger.Fatal("Config file should be specified") } - //Load configurations + // Load configurations if err := config.DefaultConfig.Load(*configPath, true); err != nil { logger.Fatalf("Failed to load configurations with error: %s\n", err) } - //Set job context initializer + // Set job context initializer runtime.JobService.SetJobContextInitializer(func(ctx *env.Context) (env.JobContext, error) { secret := config.GetAuthSecret() if utils.IsEmptyStr(secret) { @@ -47,10 +47,10 @@ func main() { return jobCtx, nil }) - //New logger for job service + // New logger for job service sLogger := ilogger.NewServiceLogger(config.GetLogLevel()) logger.SetLogger(sLogger) - //Start + // Start runtime.JobService.LoadAndRun() } diff --git a/src/jobservice/models/models.go b/src/jobservice/models/models.go index c3f68f4ae..744a5e29b 100644 --- a/src/jobservice/models/models.go +++ b/src/jobservice/models/models.go @@ -2,15 +2,15 @@ package models -//Parameters for job execution. +// Parameters for job execution. type Parameters map[string]interface{} -//JobRequest is the request of launching a job. +// JobRequest is the request of launching a job. type JobRequest struct { Job *JobData `json:"job"` } -//JobData keeps the basic info. +// JobData keeps the basic info. type JobData struct { Name string `json:"name"` Parameters Parameters `json:"parameters"` @@ -18,7 +18,7 @@ type JobData struct { StatusHook string `json:"status_hook"` } -//JobMetadata stores the metadata of job. +// JobMetadata stores the metadata of job. type JobMetadata struct { JobKind string `json:"kind"` ScheduleDelay uint64 `json:"schedule_delay,omitempty"` @@ -26,12 +26,12 @@ type JobMetadata struct { IsUnique bool `json:"unique"` } -//JobStats keeps the result of job launching. +// JobStats keeps the result of job launching. type JobStats struct { Stats *JobStatData `json:"job"` } -//JobStatData keeps the stats of job +// JobStatData keeps the stats of job type JobStatData struct { JobID string `json:"id"` Status string `json:"status"` @@ -49,12 +49,12 @@ type JobStatData struct { HookStatus string `json:"hook_status,omitempty"` } -//JobPoolStats represents the healthy and status of all the running worker pools. +// JobPoolStats represents the healthy and status of all the running worker pools. type JobPoolStats struct { Pools []*JobPoolStatsData `json:"worker_pools"` } -//JobPoolStatsData represent the healthy and status of the worker pool. +// JobPoolStatsData represent the healthy and status of the worker pool. type JobPoolStatsData struct { WorkerPoolID string `json:"worker_pool_id"` StartedAt int64 `json:"started_at"` @@ -64,12 +64,12 @@ type JobPoolStatsData struct { Status string `json:"status"` } -//JobActionRequest defines for triggering job action like stop/cancel. +// JobActionRequest defines for triggering job action like stop/cancel. type JobActionRequest struct { Action string `json:"action"` } -//JobStatusChange is designed for reporting the status change via hook. +// JobStatusChange is designed for reporting the status change via hook. type JobStatusChange struct { JobID string `json:"job_id"` Status string `json:"status"` @@ -77,8 +77,8 @@ type JobStatusChange struct { Metadata *JobStatData `json:"metadata,omitempty"` } -//Message is designed for sub/pub messages +// Message is designed for sub/pub messages type Message struct { Event string - Data interface{} //generic format + Data interface{} // generic format } diff --git a/src/jobservice/opm/hook_client.go b/src/jobservice/opm/hook_client.go index f27256351..91c59f12d 100644 --- a/src/jobservice/opm/hook_client.go +++ b/src/jobservice/opm/hook_client.go @@ -22,15 +22,15 @@ const ( idleConnectionTimeout = 30 * time.Second ) -//DefaultHookClient is for default use. +// DefaultHookClient is for default use. var DefaultHookClient = NewHookClient() -//HookClient is used to post the related data to the interested parties. +// HookClient is used to post the related data to the interested parties. type HookClient struct { client *http.Client } -//NewHookClient return the ptr of the new HookClient +// NewHookClient return the ptr of the new HookClient func NewHookClient() *HookClient { client := &http.Client{ Timeout: clientTimeout, @@ -45,26 +45,26 @@ func NewHookClient() *HookClient { } } -//ReportStatus reports the status change info to the subscribed party. -//The status includes 'checkin' info with format 'check_in:' +// ReportStatus reports the status change info to the subscribed party. +// The status includes 'checkin' info with format 'check_in:' func (hc *HookClient) ReportStatus(hookURL string, status models.JobStatusChange) error { if utils.IsEmptyStr(hookURL) { - return errors.New("empty hook url") //do nothing + return errors.New("empty hook url") // do nothing } - //Parse and validate URL + // Parse and validate URL url, err := url.Parse(hookURL) if err != nil { return err } - //Marshal data + // Marshal data data, err := json.Marshal(&status) if err != nil { return err } - //New post request + // New post request req, err := http.NewRequest(http.MethodPost, url.String(), strings.NewReader(string(data))) if err != nil { return err @@ -75,12 +75,12 @@ func (hc *HookClient) ReportStatus(hookURL string, status models.JobStatusChange return err } - defer res.Body.Close() //close connection for reuse + defer res.Body.Close() // close connection for reuse - //Should be 200 + // Should be 200 if res.StatusCode != http.StatusOK { if res.ContentLength > 0 { - //read error content and return + // read error content and return dt, err := ioutil.ReadAll(res.Body) if err != nil { return err diff --git a/src/jobservice/opm/hook_store.go b/src/jobservice/opm/hook_store.go index c148e7be7..936b36e46 100644 --- a/src/jobservice/opm/hook_store.go +++ b/src/jobservice/opm/hook_store.go @@ -8,14 +8,14 @@ import ( "github.com/goharbor/harbor/src/jobservice/utils" ) -//HookStore is used to cache the hooks in memory. -//Use job ID as key to index +// HookStore is used to cache the hooks in memory. +// Use job ID as key to index type HookStore struct { lock *sync.RWMutex data map[string]string } -//NewHookStore is to create a ptr of new HookStore. +// NewHookStore is to create a ptr of new HookStore. func NewHookStore() *HookStore { return &HookStore{ lock: new(sync.RWMutex), @@ -23,10 +23,10 @@ func NewHookStore() *HookStore { } } -//Add new record +// Add new record func (hs *HookStore) Add(jobID string, hookURL string) { if utils.IsEmptyStr(jobID) { - return //do nothing + return // do nothing } hs.lock.Lock() @@ -35,7 +35,7 @@ func (hs *HookStore) Add(jobID string, hookURL string) { hs.data[jobID] = hookURL } -//Get one hook url by job ID +// Get one hook url by job ID func (hs *HookStore) Get(jobID string) (string, bool) { hs.lock.RLock() defer hs.lock.RUnlock() @@ -45,7 +45,7 @@ func (hs *HookStore) Get(jobID string) (string, bool) { return hookURL, ok } -//Remove the specified one +// Remove the specified one func (hs *HookStore) Remove(jobID string) (string, bool) { hs.lock.Lock() defer hs.lock.Unlock() diff --git a/src/jobservice/opm/job_stats_mgr.go b/src/jobservice/opm/job_stats_mgr.go index e8cf00896..71dd82acf 100644 --- a/src/jobservice/opm/job_stats_mgr.go +++ b/src/jobservice/opm/job_stats_mgr.go @@ -4,79 +4,79 @@ package opm import "github.com/goharbor/harbor/src/jobservice/models" -//JobStatsManager defines the methods to handle stats of job. +// JobStatsManager defines the methods to handle stats of job. type JobStatsManager interface { - //Start to serve + // Start to serve Start() - //Shutdown the manager + // Shutdown the manager Shutdown() - //Save the job stats - //Async method to retry and improve performance + // Save the job stats + // Async method to retry and improve performance // - //jobStats models.JobStats : the job stats to be saved + // jobStats models.JobStats : the job stats to be saved Save(jobStats models.JobStats) - //Get the job stats from backend store - //Sync method as we need the data + // Get the job stats from backend store + // Sync method as we need the data // - //Returns: + // Returns: // models.JobStats : job stats data // error : error if meet any problems Retrieve(jobID string) (models.JobStats, error) - //SetJobStatus will mark the status of job to the specified one - //Async method to retry + // SetJobStatus will mark the status of job to the specified one + // Async method to retry SetJobStatus(jobID string, status string) - //Send command fro the specified job + // Send command fro the specified job // - //jobID string : ID of the being retried job - //command string : the command applied to the job like stop/cancel + // jobID string : ID of the being retried job + // command string : the command applied to the job like stop/cancel // - //Returns: + // Returns: // error if it was not successfully sent SendCommand(jobID string, command string) error - //CtlCommand checks if control command is fired for the specified job. + // CtlCommand checks if control command is fired for the specified job. // - //jobID string : ID of the job + // jobID string : ID of the job // - //Returns: + // Returns: // the command if it was fired // error if it was not fired yet to meet some other problems CtlCommand(jobID string) (string, error) - //CheckIn message for the specified job like detailed progress info. + // CheckIn message for the specified job like detailed progress info. // - //jobID string : ID of the job - //message string : The message being checked in + // jobID string : ID of the job + // message string : The message being checked in // CheckIn(jobID string, message string) - //DieAt marks the failed jobs with the time they put into dead queue. + // DieAt marks the failed jobs with the time they put into dead queue. // - //jobID string : ID of the job - //message string : The message being checked in + // jobID string : ID of the job + // message string : The message being checked in // DieAt(jobID string, dieAt int64) - //RegisterHook is used to save the hook url or cache the url in memory. + // RegisterHook is used to save the hook url or cache the url in memory. // - //jobID string : ID of job - //hookURL string : the hook url being registered - //isCached bool : to indicate if only cache the hook url + // jobID string : ID of job + // hookURL string : the hook url being registered + // isCached bool : to indicate if only cache the hook url // - //Returns: + // Returns: // error if meet any problems RegisterHook(jobID string, hookURL string, isCached bool) error - //Mark the periodic job stats expired + // Mark the periodic job stats expired // - //jobID string : ID of job + // jobID string : ID of job // - //Returns: + // Returns: // error if meet any problems ExpirePeriodicJobStats(jobID string) error } diff --git a/src/jobservice/opm/op_commands.go b/src/jobservice/opm/op_commands.go index 1e90d6d70..450a0db80 100644 --- a/src/jobservice/opm/op_commands.go +++ b/src/jobservice/opm/op_commands.go @@ -19,7 +19,7 @@ import ( const ( commandValidTime = 5 * time.Minute commandSweepTickerTime = 1 * time.Hour - //EventFireCommand for firing command event + // EventFireCommand for firing command event EventFireCommand = "fire_command" ) @@ -28,7 +28,7 @@ type oPCommand struct { fireTime int64 } -//oPCommands maintain commands list +// oPCommands maintain commands list type oPCommands struct { lock *sync.RWMutex commands map[string]*oPCommand @@ -39,7 +39,7 @@ type oPCommands struct { doneChan chan struct{} } -//newOPCommands is constructor of OPCommands +// newOPCommands is constructor of OPCommands func newOPCommands(ctx context.Context, ns string, redisPool *redis.Pool) *oPCommands { return &oPCommands{ lock: new(sync.RWMutex), @@ -52,19 +52,19 @@ func newOPCommands(ctx context.Context, ns string, redisPool *redis.Pool) *oPCom } } -//Start the command sweeper +// Start the command sweeper func (opc *oPCommands) Start() { go opc.loop() logger.Info("OP commands sweeper is started") } -//Stop the command sweeper +// Stop the command sweeper func (opc *oPCommands) Stop() { opc.stopChan <- struct{}{} <-opc.doneChan } -//Fire command +// Fire command func (opc *oPCommands) Fire(jobID string, command string) error { if utils.IsEmptyStr(jobID) { return errors.New("empty job ID") @@ -92,7 +92,7 @@ func (opc *oPCommands) Fire(jobID string, command string) error { return err } -//Push command into the list +// Push command into the list func (opc *oPCommands) Push(jobID string, command string) error { if utils.IsEmptyStr(jobID) { return errors.New("empty job ID") @@ -113,7 +113,7 @@ func (opc *oPCommands) Push(jobID string, command string) error { return nil } -//Pop out the command if existing +// Pop out the command if existing func (opc *oPCommands) Pop(jobID string) (string, bool) { if utils.IsEmptyStr(jobID) { return "", false diff --git a/src/jobservice/opm/redis_job_stats_mgr.go b/src/jobservice/opm/redis_job_stats_mgr.go index ded38e4a5..14e55b650 100644 --- a/src/jobservice/opm/redis_job_stats_mgr.go +++ b/src/jobservice/opm/redis_job_stats_mgr.go @@ -31,14 +31,14 @@ const ( opReportStatus = "report_status" maxFails = 3 - //CtlCommandStop : command stop + // CtlCommandStop : command stop CtlCommandStop = "stop" - //CtlCommandCancel : command cancel + // CtlCommandCancel : command cancel CtlCommandCancel = "cancel" - //CtlCommandRetry : command retry + // CtlCommandRetry : command retry CtlCommandRetry = "retry" - //EventRegisterStatusHook is event name of registering hook + // EventRegisterStatusHook is event name of registering hook EventRegisterStatusHook = "register_hook" ) @@ -48,7 +48,7 @@ type queueItem struct { data interface{} } -//RedisJobStatsManager implements JobStatsManager based on redis. +// RedisJobStatsManager implements JobStatsManager based on redis. type RedisJobStatsManager struct { namespace string redisPool *redis.Pool @@ -57,11 +57,11 @@ type RedisJobStatsManager struct { doneChan chan struct{} processChan chan *queueItem isRunning *atomic.Value - hookStore *HookStore //cache the hook here to avoid requesting backend - opCommands *oPCommands //maintain the OP commands + hookStore *HookStore // cache the hook here to avoid requesting backend + opCommands *oPCommands // maintain the OP commands } -//NewRedisJobStatsManager is constructor of RedisJobStatsManager +// NewRedisJobStatsManager is constructor of RedisJobStatsManager func NewRedisJobStatsManager(ctx context.Context, namespace string, redisPool *redis.Pool) *RedisJobStatsManager { isRunning := &atomic.Value{} isRunning.Store(false) @@ -79,7 +79,7 @@ func NewRedisJobStatsManager(ctx context.Context, namespace string, redisPool *r } } -//Start is implementation of same method in JobStatsManager interface. +// Start is implementation of same method in JobStatsManager interface. func (rjs *RedisJobStatsManager) Start() { if rjs.isRunning.Load().(bool) { return @@ -91,7 +91,7 @@ func (rjs *RedisJobStatsManager) Start() { logger.Info("Redis job stats manager is started") } -//Shutdown is implementation of same method in JobStatsManager interface. +// Shutdown is implementation of same method in JobStatsManager interface. func (rjs *RedisJobStatsManager) Shutdown() { defer func() { rjs.isRunning.Store(false) @@ -106,8 +106,8 @@ func (rjs *RedisJobStatsManager) Shutdown() { <-rjs.doneChan } -//Save is implementation of same method in JobStatsManager interface. -//Async method +// Save is implementation of same method in JobStatsManager interface. +// Async method func (rjs *RedisJobStatsManager) Save(jobStats models.JobStats) { item := &queueItem{ op: opSaveStats, @@ -117,8 +117,8 @@ func (rjs *RedisJobStatsManager) Save(jobStats models.JobStats) { rjs.processChan <- item } -//Retrieve is implementation of same method in JobStatsManager interface. -//Sync method +// Retrieve is implementation of same method in JobStatsManager interface. +// Sync method func (rjs *RedisJobStatsManager) Retrieve(jobID string) (models.JobStats, error) { if utils.IsEmptyStr(jobID) { return models.JobStats{}, errors.New("empty job ID") @@ -127,8 +127,8 @@ func (rjs *RedisJobStatsManager) Retrieve(jobID string) (models.JobStats, error) return rjs.getJobStats(jobID) } -//SetJobStatus is implementation of same method in JobStatsManager interface. -//Async method +// SetJobStatus is implementation of same method in JobStatsManager interface. +// Async method func (rjs *RedisJobStatsManager) SetJobStatus(jobID string, status string) { if utils.IsEmptyStr(jobID) || utils.IsEmptyStr(status) { return @@ -141,7 +141,7 @@ func (rjs *RedisJobStatsManager) SetJobStatus(jobID string, status string) { rjs.processChan <- item - //Report status at the same time + // Report status at the same time rjs.submitStatusReportingItem(jobID, status, "") } @@ -150,7 +150,7 @@ func (rjs *RedisJobStatsManager) loop() { defer func() { rjs.isRunning.Store(false) - //Notify other sub goroutines + // Notify other sub goroutines close(controlChan) logger.Info("Redis job stats manager is stopped") }() @@ -165,7 +165,7 @@ func (rjs *RedisJobStatsManager) loop() { if item.fails < maxFails { logger.Warningf("Failed to process '%s' request with error: %s\n", item.op, err) - //Retry after a random interval + // Retry after a random interval go func() { timer := time.NewTimer(time.Duration(backoff(item.fails)) * time.Second) defer timer.Stop() @@ -190,7 +190,7 @@ func (rjs *RedisJobStatsManager) loop() { } if clearHookCache { - //Clear cache to save memory if job status is success or stopped. + // Clear cache to save memory if job status is success or stopped. data := item.data.([]string) status := data[2] if status == job.JobStatusSuccess || status == job.JobStatusStopped { @@ -208,7 +208,7 @@ func (rjs *RedisJobStatsManager) loop() { } } -//SendCommand for the specified job +// SendCommand for the specified job func (rjs *RedisJobStatsManager) SendCommand(jobID string, command string) error { if utils.IsEmptyStr(jobID) { return errors.New("empty job ID") @@ -222,11 +222,11 @@ func (rjs *RedisJobStatsManager) SendCommand(jobID string, command string) error return err } - //Directly add to op commands maintaining list + // Directly add to op commands maintaining list return rjs.opCommands.Push(jobID, command) } -//CheckIn mesage +// CheckIn mesage func (rjs *RedisJobStatsManager) CheckIn(jobID string, message string) { if utils.IsEmptyStr(jobID) || utils.IsEmptyStr(message) { return @@ -239,11 +239,11 @@ func (rjs *RedisJobStatsManager) CheckIn(jobID string, message string) { rjs.processChan <- item - //Report checkin message at the same time + // Report checkin message at the same time rjs.submitStatusReportingItem(jobID, job.JobStatusRunning, message) } -//CtlCommand checks if control command is fired for the specified job. +// CtlCommand checks if control command is fired for the specified job. func (rjs *RedisJobStatsManager) CtlCommand(jobID string) (string, error) { if utils.IsEmptyStr(jobID) { return "", errors.New("empty job ID") @@ -257,7 +257,7 @@ func (rjs *RedisJobStatsManager) CtlCommand(jobID string) (string, error) { return c, nil } -//DieAt marks the failed jobs with the time they put into dead queue. +// DieAt marks the failed jobs with the time they put into dead queue. func (rjs *RedisJobStatsManager) DieAt(jobID string, dieAt int64) { if utils.IsEmptyStr(jobID) || dieAt == 0 { return @@ -271,7 +271,7 @@ func (rjs *RedisJobStatsManager) DieAt(jobID string, dieAt int64) { rjs.processChan <- item } -//RegisterHook is used to save the hook url or cache the url in memory. +// RegisterHook is used to save the hook url or cache the url in memory. func (rjs *RedisJobStatsManager) RegisterHook(jobID string, hookURL string, isCached bool) error { if utils.IsEmptyStr(jobID) { return errors.New("empty job ID") @@ -290,22 +290,22 @@ func (rjs *RedisJobStatsManager) RegisterHook(jobID string, hookURL string, isCa return nil } -//ExpirePeriodicJobStats marks the periodic job stats expired +// ExpirePeriodicJobStats marks the periodic job stats expired func (rjs *RedisJobStatsManager) ExpirePeriodicJobStats(jobID string) error { conn := rjs.redisPool.Get() defer conn.Close() - //The periodic job (policy) is stopped/unscheduled and then - //the stats of periodic job now can be expired + // The periodic job (policy) is stopped/unscheduled and then + // the stats of periodic job now can be expired key := utils.KeyJobStats(rjs.namespace, jobID) - expireTime := 24 * 60 * 60 //1 day + expireTime := 24 * 60 * 60 // 1 day _, err := conn.Do("EXPIRE", key, expireTime) return err } func (rjs *RedisJobStatsManager) submitStatusReportingItem(jobID string, status, checkIn string) { - //Let it run in a separate goroutine to avoid waiting more time + // Let it run in a separate goroutine to avoid waiting more time go func() { var ( hookURL string @@ -315,10 +315,10 @@ func (rjs *RedisJobStatsManager) submitStatusReportingItem(jobID string, status, hookURL, ok = rjs.hookStore.Get(jobID) if !ok { - //Retrieve from backend + // Retrieve from backend hookURL, err = rjs.getHook(jobID) if err != nil || !utils.IsValidURL(hookURL) { - //logged and exit + // logged and exit logger.Warningf("no status hook found for job %s\n, abandon status reporting", jobID) return } @@ -339,16 +339,16 @@ func (rjs *RedisJobStatsManager) reportStatus(jobID string, hookURL, status, che Status: status, CheckIn: checkIn, } - //Return the whole metadata of the job. - //To support forward compatibility, keep the original fields `Status` and `CheckIn`. - //TODO: If querying job stats causes performance issues, a two-level cache should be enabled. + // Return the whole metadata of the job. + // To support forward compatibility, keep the original fields `Status` and `CheckIn`. + // TODO: If querying job stats causes performance issues, a two-level cache should be enabled. jobStats, err := rjs.getJobStats(jobID) if err != nil { - //Just logged + // Just logged logger.Warningf("Retrieving stats of job %s for hook reporting failed with error: %s", jobID, err) } else { - //Override status/check in message - //Just double confirmation + // Override status/check in message + // Just double confirmation jobStats.Stats.CheckIn = checkIn jobStats.Stats.Status = status reportingStatus.Metadata = jobStats.Stats @@ -365,7 +365,7 @@ func (rjs *RedisJobStatsManager) updateJobStatus(jobID string, status string) er args := make([]interface{}, 0, 6) args = append(args, key, "status", status, "update_time", time.Now().Unix()) if status == job.JobStatusSuccess { - //make sure the 'die_at' is reset in case it's a retrying job + // make sure the 'die_at' is reset in case it's a retrying job args = append(args, "die_at", 0) } _, err := conn.Do("HMSET", args...) @@ -390,7 +390,7 @@ func (rjs *RedisJobStatsManager) dieAt(jobID string, baseTime int64) error { conn := rjs.redisPool.Get() defer conn.Close() - //Query the dead job in the time scope of [baseTime,baseTime+5] + // Query the dead job in the time scope of [baseTime,baseTime+5] key := utils.RedisKeyDead(rjs.namespace) jobWithScores, err := utils.GetZsetByScore(rjs.redisPool, key, []int64{baseTime, baseTime + 5}) if err != nil { @@ -400,7 +400,7 @@ func (rjs *RedisJobStatsManager) dieAt(jobID string, baseTime int64) error { for _, jws := range jobWithScores { if j, err := utils.DeSerializeJob(jws.JobBytes); err == nil { if j.ID == jobID { - //Found + // Found statsKey := utils.KeyJobStats(rjs.namespace, jobID) args := make([]interface{}, 0, 7) args = append(args, statsKey, "die_at", jws.Score, "update_time", time.Now().Unix()) @@ -521,8 +521,8 @@ func (rjs *RedisJobStatsManager) saveJobStats(jobStats models.JobStats) error { } conn.Send("HMSET", args...) - //If job kind is periodic job, expire time should not be set - //If job kind is scheduled job, expire time should be runAt+1day + // If job kind is periodic job, expire time should not be set + // If job kind is scheduled job, expire time should be runAt+1day if jobStats.Stats.JobKind != job.JobKindPeriodic { var expireTime int64 = 60 * 60 * 24 if jobStats.Stats.JobKind == job.JobKindScheduled { @@ -532,7 +532,7 @@ func (rjs *RedisJobStatsManager) saveJobStats(jobStats models.JobStats) error { expireTime += future } } - expireTime += rand.Int63n(30) //Avoid lots of keys being expired at the same time + expireTime += rand.Int63n(30) // Avoid lots of keys being expired at the same time conn.Send("EXPIRE", key, expireTime) } @@ -563,7 +563,7 @@ func (rjs *RedisJobStatsManager) process(item *queueItem) error { return nil } -//HookData keeps the hook url info +// HookData keeps the hook url info type HookData struct { JobID string `json:"job_id"` HookURL string `json:"hook_url"` @@ -588,8 +588,8 @@ func (rjs *RedisJobStatsManager) saveHook(jobID string, hookURL string) error { return err } - //hook is saved into the job stats - //We'll not set expire time here, the expire time of the key will be set when saving job stats + // hook is saved into the job stats + // We'll not set expire time here, the expire time of the key will be set when saving job stats if err := conn.Send("MULTI"); err != nil { return err } diff --git a/src/jobservice/opm/redis_job_stats_mgr_test.go b/src/jobservice/opm/redis_job_stats_mgr_test.go index 88492425a..0a9bd8dad 100644 --- a/src/jobservice/opm/redis_job_stats_mgr_test.go +++ b/src/jobservice/opm/redis_job_stats_mgr_test.go @@ -49,7 +49,7 @@ func TestSetJobStatus(t *testing.T) { mgr.Start() defer mgr.Shutdown() <-time.After(200 * time.Millisecond) - //make sure data existing + // make sure data existing testingStats := createFakeStats() mgr.Save(testingStats) <-time.After(200 * time.Millisecond) @@ -148,7 +148,7 @@ func TestExpireJobStats(t *testing.T) { defer mgr.Shutdown() <-time.After(200 * time.Millisecond) - //make sure data existing + // make sure data existing testingStats := createFakeStats() mgr.Save(testingStats) <-time.After(200 * time.Millisecond) @@ -169,12 +169,12 @@ func TestCheckIn(t *testing.T) { defer mgr.Shutdown() <-time.After(200 * time.Millisecond) - //make sure data existing + // make sure data existing testingStats := createFakeStats() mgr.Save(testingStats) <-time.After(200 * time.Millisecond) - //Start http server + // Start http server ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { data, err := ioutil.ReadAll(r.Body) if err != nil { @@ -223,7 +223,7 @@ func TestCheckIn(t *testing.T) { func getRedisHost() string { redisHost := os.Getenv(testingRedisHost) if redisHost == "" { - redisHost = "localhost" //for local test + redisHost = "localhost" // for local test } return redisHost diff --git a/src/jobservice/period/enqueuer.go b/src/jobservice/period/enqueuer.go index 14f1fff6f..88752bdb6 100644 --- a/src/jobservice/period/enqueuer.go +++ b/src/jobservice/period/enqueuer.go @@ -1,4 +1,4 @@ -//Refer github.com/gocraft/work +// Refer github.com/gocraft/work package period @@ -103,8 +103,8 @@ func (pe *periodicEnqueuer) enqueue() error { for _, pl := range pe.policyStore.list() { schedule, err := cron.Parse(pl.CronSpec) if err != nil { - //The cron spec should be already checked at top components. - //Just in cases, if error occurred, ignore it + // The cron spec should be already checked at top components. + // Just in cases, if error occurred, ignore it continue } pj := &periodicJob{ @@ -116,11 +116,11 @@ func (pe *periodicEnqueuer) enqueue() error { epoch := t.Unix() job := &work.Job{ Name: pj.jobName, - ID: pl.PolicyID, //Same with the id of the policy it's being scheduled for + ID: pl.PolicyID, // Same with the id of the policy it's being scheduled for // This is technically wrong, but this lets the bytes be identical for the same periodic job instance. If we don't do this, we'd need to use a different approach -- probably giving each periodic job its own history of the past 100 periodic jobs, and only scheduling a job if it's not in the history. EnqueuedAt: epoch, - Args: pl.JobParameters, //Pass parameters to scheduled job here + Args: pl.JobParameters, // Pass parameters to scheduled job here } rawJSON, err := utils.SerializeJob(job) @@ -135,8 +135,8 @@ func (pe *periodicEnqueuer) enqueue() error { logger.Infof("Schedule job %s for policy %s at %d\n", pj.jobName, pl.PolicyID, epoch) } - //Directly use redis conn to update the periodic job (policy) status - //Do not care the result + // Directly use redis conn to update the periodic job (policy) status + // Do not care the result conn.Do("HMSET", utils.KeyJobStats(pe.namespace, pl.PolicyID), "status", job.JobStatusScheduled, "update_time", time.Now().Unix()) } diff --git a/src/jobservice/period/interface.go b/src/jobservice/period/interface.go index ed7a97f8f..40a316694 100644 --- a/src/jobservice/period/interface.go +++ b/src/jobservice/period/interface.go @@ -4,56 +4,56 @@ package period import "github.com/goharbor/harbor/src/jobservice/models" -//Interface defines operations the periodic scheduler should have. +// Interface defines operations the periodic scheduler should have. type Interface interface { - //Schedule the specified cron job policy. + // Schedule the specified cron job policy. // - //jobName string : The name of periodical job - //params models.Parameters : The parameters required by the periodical job - //cronSpec string : The periodical settings with cron format + // jobName string : The name of periodical job + // params models.Parameters : The parameters required by the periodical job + // cronSpec string : The periodical settings with cron format // - //Returns: + // Returns: // The uuid of the cron job policy // The latest next trigger time // error if failed to schedule Schedule(jobName string, params models.Parameters, cronSpec string) (string, int64, error) - //Unschedule the specified cron job policy. + // Unschedule the specified cron job policy. // - //cronJobPolicyID string: The ID of cron job policy. + // cronJobPolicyID string: The ID of cron job policy. // - //Return: + // Return: // error if failed to unschedule UnSchedule(cronJobPolicyID string) error - //Load and cache data if needed + // Load and cache data if needed // - //Return: + // Return: // error if failed to do Load() error - //Clear all the cron job policies. + // Clear all the cron job policies. // - //Return: + // Return: // error if failed to do Clear() error - //Start to serve + // Start to serve Start() - //Accept the pushed policy and cache it + // Accept the pushed policy and cache it // - //policy *PeriodicJobPolicy : the periodic policy being accept + // policy *PeriodicJobPolicy : the periodic policy being accept // - //Return: + // Return: // error if failed to do AcceptPeriodicPolicy(policy *PeriodicJobPolicy) error - //Remove the specified policy from the cache if it is existing + // Remove the specified policy from the cache if it is existing // - //policyID string : ID of the policy being removed + // policyID string : ID of the policy being removed // - //Return: + // Return: // the ptr of the being deletd policy RemovePeriodicPolicy(policyID string) *PeriodicJobPolicy } diff --git a/src/jobservice/period/job_policy.go b/src/jobservice/period/job_policy.go index cd531b845..91a1d899c 100644 --- a/src/jobservice/period/job_policy.go +++ b/src/jobservice/period/job_policy.go @@ -10,36 +10,36 @@ import ( ) const ( - //periodicJobPolicyChangeEventSchedule : Schedule periodic job policy event + // periodicJobPolicyChangeEventSchedule : Schedule periodic job policy event periodicJobPolicyChangeEventSchedule = "Schedule" - //periodicJobPolicyChangeEventUnSchedule : UnSchedule periodic job policy event + // periodicJobPolicyChangeEventUnSchedule : UnSchedule periodic job policy event periodicJobPolicyChangeEventUnSchedule = "UnSchedule" ) -//PeriodicJobPolicy ... +// PeriodicJobPolicy ... type PeriodicJobPolicy struct { - //NOTES: The 'PolicyID' should not be set when serialize this policy struct to the zset - //because each 'Policy ID' is different and it may cause issue of losing zset unique capability. + // NOTES: The 'PolicyID' should not be set when serialize this policy struct to the zset + // because each 'Policy ID' is different and it may cause issue of losing zset unique capability. PolicyID string `json:"policy_id,omitempty"` JobName string `json:"job_name"` JobParameters map[string]interface{} `json:"job_params"` CronSpec string `json:"cron_spec"` } -//Serialize the policy to raw data. +// Serialize the policy to raw data. func (pjp *PeriodicJobPolicy) Serialize() ([]byte, error) { return json.Marshal(pjp) } -//DeSerialize the raw json to policy. +// DeSerialize the raw json to policy. func (pjp *PeriodicJobPolicy) DeSerialize(rawJSON []byte) error { return json.Unmarshal(rawJSON, pjp) } -//periodicJobPolicyStore is in-memory cache for the periodic job policies. +// periodicJobPolicyStore is in-memory cache for the periodic job policies. type periodicJobPolicyStore struct { lock *sync.RWMutex - policies map[string]*PeriodicJobPolicy //k-v pair and key is the policy ID + policies map[string]*PeriodicJobPolicy // k-v pair and key is the policy ID } func (ps *periodicJobPolicyStore) addAll(items []*PeriodicJobPolicy) { @@ -51,7 +51,7 @@ func (ps *periodicJobPolicyStore) addAll(items []*PeriodicJobPolicy) { defer ps.lock.Unlock() for _, item := range items { - //Ignore the item with empty uuid + // Ignore the item with empty uuid if !utils.IsEmptyStr(item.PolicyID) { ps.policies[item.PolicyID] = item } diff --git a/src/jobservice/period/redis_scheduler.go b/src/jobservice/period/redis_scheduler.go index cead8d55c..4f6be5fc2 100644 --- a/src/jobservice/period/redis_scheduler.go +++ b/src/jobservice/period/redis_scheduler.go @@ -21,13 +21,13 @@ import ( ) const ( - //EventSchedulePeriodicPolicy is for scheduling periodic policy event + // EventSchedulePeriodicPolicy is for scheduling periodic policy event EventSchedulePeriodicPolicy = "schedule" - //EventUnSchedulePeriodicPolicy is for unscheduling periodic policy event + // EventUnSchedulePeriodicPolicy is for unscheduling periodic policy event EventUnSchedulePeriodicPolicy = "unschedule" ) -//RedisPeriodicScheduler manages the periodic scheduling policies. +// RedisPeriodicScheduler manages the periodic scheduling policies. type RedisPeriodicScheduler struct { context *env.Context redisPool *redis.Pool @@ -36,7 +36,7 @@ type RedisPeriodicScheduler struct { enqueuer *periodicEnqueuer } -//NewRedisPeriodicScheduler is constructor of RedisPeriodicScheduler +// NewRedisPeriodicScheduler is constructor of RedisPeriodicScheduler func NewRedisPeriodicScheduler(ctx *env.Context, namespace string, redisPool *redis.Pool) *RedisPeriodicScheduler { pstore := &periodicJobPolicyStore{ lock: new(sync.RWMutex), @@ -53,29 +53,29 @@ func NewRedisPeriodicScheduler(ctx *env.Context, namespace string, redisPool *re } } -//Start to serve +// Start to serve func (rps *RedisPeriodicScheduler) Start() { defer func() { logger.Info("Redis scheduler is stopped") }() - //Load existing periodic job policies + // Load existing periodic job policies if err := rps.Load(); err != nil { - //exit now + // exit now rps.context.ErrorChan <- err return } - //start enqueuer + // start enqueuer rps.enqueuer.start() defer rps.enqueuer.stop() logger.Info("Redis scheduler is started") - //blocking here + // blocking here <-rps.context.SystemContext.Done() } -//Schedule is implementation of the same method in period.Interface +// Schedule is implementation of the same method in period.Interface func (rps *RedisPeriodicScheduler) Schedule(jobName string, params models.Parameters, cronSpec string) (string, int64, error) { if utils.IsEmptyStr(jobName) { return "", 0, errors.New("empty job name is not allowed") @@ -84,35 +84,35 @@ func (rps *RedisPeriodicScheduler) Schedule(jobName string, params models.Parame return "", 0, errors.New("cron spec is not set") } - //Get next run time + // Get next run time schedule, err := cron.Parse(cronSpec) if err != nil { return "", 0, err } - //Although the ZSET can guarantee no duplicated items, we still need to check the existing - //of the job policy to avoid publish duplicated ones to other nodes as we - //use transaction commands. + // Although the ZSET can guarantee no duplicated items, we still need to check the existing + // of the job policy to avoid publish duplicated ones to other nodes as we + // use transaction commands. jobPolicy := &PeriodicJobPolicy{ JobName: jobName, JobParameters: params, CronSpec: cronSpec, } - //Serialize data + // Serialize data rawJSON, err := jobPolicy.Serialize() if err != nil { return "", 0, nil } - //Check existing - //If existing, treat as a succeed submitting and return the exitsing id + // Check existing + // If existing, treat as a succeed submitting and return the exitsing id if score, ok := rps.exists(string(rawJSON)); ok { id, err := rps.getIDByScore(score) return id, 0, err } uuid, score := utils.MakePeriodicPolicyUUID() - //Set back policy ID + // Set back policy ID jobPolicy.PolicyID = uuid notification := &models.Message{ Event: EventSchedulePeriodicPolicy, @@ -123,7 +123,7 @@ func (rps *RedisPeriodicScheduler) Schedule(jobName string, params models.Parame return "", 0, err } - //Save to redis db and publish notification via redis transaction + // Save to redis db and publish notification via redis transaction conn := rps.redisPool.Get() defer conn.Close() @@ -151,7 +151,7 @@ func (rps *RedisPeriodicScheduler) Schedule(jobName string, params models.Parame return uuid, schedule.Next(time.Now()).Unix(), nil } -//UnSchedule is implementation of the same method in period.Interface +// UnSchedule is implementation of the same method in period.Interface func (rps *RedisPeriodicScheduler) UnSchedule(cronJobPolicyID string) error { if utils.IsEmptyStr(cronJobPolicyID) { return errors.New("cron job policy ID is empty") @@ -169,7 +169,7 @@ func (rps *RedisPeriodicScheduler) UnSchedule(cronJobPolicyID string) error { notification := &models.Message{ Event: EventUnSchedulePeriodicPolicy, Data: &PeriodicJobPolicy{ - PolicyID: cronJobPolicyID, //Only ID required + PolicyID: cronJobPolicyID, // Only ID required }, } @@ -178,7 +178,7 @@ func (rps *RedisPeriodicScheduler) UnSchedule(cronJobPolicyID string) error { return err } - //REM from redis db + // REM from redis db conn := rps.redisPool.Get() defer conn.Close() @@ -186,11 +186,11 @@ func (rps *RedisPeriodicScheduler) UnSchedule(cronJobPolicyID string) error { if err != nil { return err } - err = conn.Send("ZREMRANGEBYSCORE", utils.KeyPeriodicPolicy(rps.namespace), score, score) //Accurately remove the item with the specified score + err = conn.Send("ZREMRANGEBYSCORE", utils.KeyPeriodicPolicy(rps.namespace), score, score) // Accurately remove the item with the specified score if err != nil { return err } - err = conn.Send("ZREMRANGEBYSCORE", utils.KeyPeriodicPolicyScore(rps.namespace), score, score) //Remove key score mapping + err = conn.Send("ZREMRANGEBYSCORE", utils.KeyPeriodicPolicyScore(rps.namespace), score, score) // Remove key score mapping if err != nil { return err } @@ -204,12 +204,12 @@ func (rps *RedisPeriodicScheduler) UnSchedule(cronJobPolicyID string) error { return err } -//Load data from zset +// Load data from zset func (rps *RedisPeriodicScheduler) Load() error { conn := rps.redisPool.Get() defer conn.Close() - //Let's build key score mapping locally first + // Let's build key score mapping locally first bytes, err := redis.MultiBulk(conn.Do("ZRANGE", utils.KeyPeriodicPolicyScore(rps.namespace), 0, -1, "WITHSCORES")) if err != nil { return err @@ -220,7 +220,7 @@ func (rps *RedisPeriodicScheduler) Load() error { rawScore := bytes[i+1].([]byte) score, err := strconv.ParseInt(string(rawScore), 10, 64) if err != nil { - //Ignore + // Ignore continue } keyScoreMap[score] = pid @@ -238,25 +238,25 @@ func (rps *RedisPeriodicScheduler) Load() error { policy := &PeriodicJobPolicy{} if err := policy.DeSerialize(rawPolicy); err != nil { - //Ignore error which means the policy data is not valid - //Only logged + // Ignore error which means the policy data is not valid + // Only logged logger.Warningf("failed to deserialize periodic policy with error:%s; raw data: %s\n", err, rawPolicy) continue } score, err := strconv.ParseInt(string(rawScore), 10, 64) if err != nil { - //Ignore error which means the policy data is not valid - //Only logged + // Ignore error which means the policy data is not valid + // Only logged logger.Warningf("failed to parse the score of the periodic policy with error:%s\n", err) continue } - //Set back the policy ID + // Set back the policy ID if pid, ok := keyScoreMap[score]; ok { policy.PolicyID = pid } else { - //Something wrong, should not be happened - //ignore here + // Something wrong, should not be happened + // ignore here continue } @@ -271,7 +271,7 @@ func (rps *RedisPeriodicScheduler) Load() error { return nil } -//Clear is implementation of the same method in period.Interface +// Clear is implementation of the same method in period.Interface func (rps *RedisPeriodicScheduler) Clear() error { conn := rps.redisPool.Get() defer conn.Close() @@ -281,7 +281,7 @@ func (rps *RedisPeriodicScheduler) Clear() error { return err } -//AcceptPeriodicPolicy is implementation of the same method in period.Interface +// AcceptPeriodicPolicy is implementation of the same method in period.Interface func (rps *RedisPeriodicScheduler) AcceptPeriodicPolicy(policy *PeriodicJobPolicy) error { if policy == nil || utils.IsEmptyStr(policy.PolicyID) { return errors.New("nil periodic policy") @@ -292,7 +292,7 @@ func (rps *RedisPeriodicScheduler) AcceptPeriodicPolicy(policy *PeriodicJobPolic return nil } -//RemovePeriodicPolicy is implementation of the same method in period.Interface +// RemovePeriodicPolicy is implementation of the same method in period.Interface func (rps *RedisPeriodicScheduler) RemovePeriodicPolicy(policyID string) *PeriodicJobPolicy { if utils.IsEmptyStr(policyID) { return nil diff --git a/src/jobservice/period/sweeper.go b/src/jobservice/period/sweeper.go index 21a4371f0..0647c7705 100644 --- a/src/jobservice/period/sweeper.go +++ b/src/jobservice/period/sweeper.go @@ -13,15 +13,15 @@ import ( "github.com/gomodule/redigo/redis" ) -//Sweeper take charge of clearing the outdated data such as scheduled jobs etc.. -//Currently, only used in redis worker pool. +// Sweeper take charge of clearing the outdated data such as scheduled jobs etc.. +// Currently, only used in redis worker pool. type Sweeper struct { redisPool *redis.Pool client *work.Client namespace string } -//NewSweeper is constructor of Sweeper. +// NewSweeper is constructor of Sweeper. func NewSweeper(namespace string, pool *redis.Pool, client *work.Client) *Sweeper { return &Sweeper{ namespace: namespace, @@ -30,17 +30,17 @@ func NewSweeper(namespace string, pool *redis.Pool, client *work.Client) *Sweepe } } -//ClearOutdatedScheduledJobs clears the outdated scheduled jobs. -//Try best to do +// ClearOutdatedScheduledJobs clears the outdated scheduled jobs. +// Try best to do func (s *Sweeper) ClearOutdatedScheduledJobs() error { - //Check if other workpool has done the action + // Check if other workpool has done the action conn := s.redisPool.Get() defer conn.Close() - //Lock + // Lock r, err := conn.Do("SET", utils.KeyPeriodicLock(s.namespace), time.Now().Unix(), "EX", 30, "NX") defer func() { - //Make sure it can be unlocked if it is not expired yet + // Make sure it can be unlocked if it is not expired yet if _, err := conn.Do("DEL", utils.KeyPeriodicLock(s.namespace)); err != nil { logger.Errorf("Unlock key '%s' failed with error: %s\n", utils.KeyPeriodicLock(s.namespace), err.Error()) } @@ -50,7 +50,7 @@ func (s *Sweeper) ClearOutdatedScheduledJobs() error { } if r == nil { - //Action is already locked by other workerpool + // Action is already locked by other workerpool logger.Info("Ignore clear outdated scheduled jobs") return nil } @@ -76,7 +76,7 @@ func (s *Sweeper) ClearOutdatedScheduledJobs() error { logger.Infof("Clear outdated scheduled job: %s run at %#v\n", j.ID, time.Unix(jobScore.Score, 0).String()) } - //Unlock + // Unlock if len(allErrors) == 0 { return nil } diff --git a/src/jobservice/pool/interface.go b/src/jobservice/pool/interface.go index 521ff74cf..71d10596f 100644 --- a/src/jobservice/pool/interface.go +++ b/src/jobservice/pool/interface.go @@ -4,131 +4,131 @@ package pool import "github.com/goharbor/harbor/src/jobservice/models" -//Interface for worker pool. -//More like a driver to transparent the lower queue. +// Interface for worker pool. +// More like a driver to transparent the lower queue. type Interface interface { - //Start to serve + // Start to serve // - //Return: + // Return: // error if failed to start Start() error - //Register job to the pool. + // Register job to the pool. // - //name string : job name for referring - //job interface{}: job handler which must implement the job.Interface. + // name string : job name for referring + // job interface{}: job handler which must implement the job.Interface. // - //Return: + // Return: // error if failed to register RegisterJob(name string, job interface{}) error - //Register multiple jobs. + // Register multiple jobs. // - //jobs map[string]interface{}: job map, key is job name and value is job handler. + // jobs map[string]interface{}: job map, key is job name and value is job handler. // - //Return: + // Return: // error if failed to register RegisterJobs(jobs map[string]interface{}) error - //Enqueue job + // Enqueue job // - //jobName string : the name of enqueuing job - //params models.Parameters : parameters of enqueuing job - //isUnique bool : specify if duplicated job will be discarded + // jobName string : the name of enqueuing job + // params models.Parameters : parameters of enqueuing job + // isUnique bool : specify if duplicated job will be discarded // - //Returns: + // Returns: // models.JobStats: the stats of enqueuing job if succeed // error : if failed to enqueue Enqueue(jobName string, params models.Parameters, isUnique bool) (models.JobStats, error) - //Schedule job to run after the specified interval (seconds). + // Schedule job to run after the specified interval (seconds). // - //jobName string : the name of enqueuing job - //runAfterSeconds uint64 : the waiting interval with seconds - //params models.Parameters : parameters of enqueuing job - //isUnique bool : specify if duplicated job will be discarded + // jobName string : the name of enqueuing job + // runAfterSeconds uint64 : the waiting interval with seconds + // params models.Parameters : parameters of enqueuing job + // isUnique bool : specify if duplicated job will be discarded // - //Returns: + // Returns: // models.JobStats: the stats of enqueuing job if succeed // error : if failed to enqueue Schedule(jobName string, params models.Parameters, runAfterSeconds uint64, isUnique bool) (models.JobStats, error) - //Schedule the job periodically running. + // Schedule the job periodically running. // - //jobName string : the name of enqueuing job - //params models.Parameters : parameters of enqueuing job - //cronSetting string : the periodic duration with cron style like '0 * * * * *' + // jobName string : the name of enqueuing job + // params models.Parameters : parameters of enqueuing job + // cronSetting string : the periodic duration with cron style like '0 * * * * *' // - //Returns: + // Returns: // models.JobStats: the stats of enqueuing job if succeed // error : if failed to enqueue PeriodicallyEnqueue(jobName string, params models.Parameters, cronSetting string) (models.JobStats, error) - //Return the status info of the pool. + // Return the status info of the pool. // - //Returns: + // Returns: // models.JobPoolStats : the stats info of all running pools // error : failed to check Stats() (models.JobPoolStats, error) - //Check if the job has been already registered. + // Check if the job has been already registered. // - //name string : name of job + // name string : name of job // - //Returns: + // Returns: // interface{} : the job type of the known job if it's existing // bool : if the known job requires parameters IsKnownJob(name string) (interface{}, bool) - //Validate the parameters of the known job + // Validate the parameters of the known job // - //jobType interface{} : type of known job + // jobType interface{} : type of known job // params map[string]interface{} : parameters of known job // - //Return: + // Return: // error if parameters are not valid ValidateJobParameters(jobType interface{}, params map[string]interface{}) error - //Get the stats of the specified job + // Get the stats of the specified job // - //jobID string : ID of the enqueued job + // jobID string : ID of the enqueued job // - //Returns: + // Returns: // models.JobStats : job stats data // error : error returned if meet any problems GetJobStats(jobID string) (models.JobStats, error) - //Stop the job + // Stop the job // - //jobID string : ID of the enqueued job + // jobID string : ID of the enqueued job // - //Return: + // Return: // error : error returned if meet any problems StopJob(jobID string) error - //Cancel the job + // Cancel the job // - //jobID string : ID of the enqueued job + // jobID string : ID of the enqueued job // - //Return: + // Return: // error : error returned if meet any problems CancelJob(jobID string) error - //Retry the job + // Retry the job // - //jobID string : ID of the enqueued job + // jobID string : ID of the enqueued job // - //Return: + // Return: // error : error returned if meet any problems RetryJob(jobID string) error - //Register hook + // Register hook // - //jobID string : ID of job - //hookURL string : the hook url + // jobID string : ID of job + // hookURL string : the hook url // - //Return: + // Return: // error : error returned if meet any problems RegisterHook(jobID string, hookURL string) error } diff --git a/src/jobservice/pool/message_server.go b/src/jobservice/pool/message_server.go index 4a8337031..29973886b 100644 --- a/src/jobservice/pool/message_server.go +++ b/src/jobservice/pool/message_server.go @@ -23,15 +23,15 @@ const ( msgServerRetryTimes = 5 ) -//MessageServer implements the sub/pub mechanism via redis to do async message exchanging. +// MessageServer implements the sub/pub mechanism via redis to do async message exchanging. type MessageServer struct { context context.Context redisPool *redis.Pool namespace string - callbacks map[string]reflect.Value //no need to sync + callbacks map[string]reflect.Value // no need to sync } -//NewMessageServer creates a new ptr of MessageServer +// NewMessageServer creates a new ptr of MessageServer func NewMessageServer(ctx context.Context, namespace string, redisPool *redis.Pool) *MessageServer { return &MessageServer{ context: ctx, @@ -41,19 +41,19 @@ func NewMessageServer(ctx context.Context, namespace string, redisPool *redis.Po } } -//Start to serve +// Start to serve func (ms *MessageServer) Start() error { defer func() { logger.Info("Message server is stopped") }() - conn := ms.redisPool.Get() //Get one backend connection! + conn := ms.redisPool.Get() // Get one backend connection! psc := redis.PubSubConn{ Conn: conn, } defer psc.Close() - //Subscribe channel + // Subscribe channel err := psc.Subscribe(redis.Args{}.AddFlat(utils.KeyPeriodicNotification(ms.namespace))...) if err != nil { return err @@ -68,41 +68,41 @@ func (ms *MessageServer) Start() error { case redis.Message: m := &models.Message{} if err := json.Unmarshal(res.Data, m); err != nil { - //logged + // logged logger.Warningf("Read invalid message: %s\n", res.Data) } if callback, ok := ms.callbacks[m.Event]; !ok { - //logged + // logged logger.Warningf("no handler to handle event %s\n", m.Event) } else { - //logged incoming events + // logged incoming events logger.Infof("Receive event '%s' with data(unformatted): %+#v\n", m.Event, m.Data) - //Try to recover the concrete type + // Try to recover the concrete type var converted interface{} switch m.Event { case period.EventSchedulePeriodicPolicy, period.EventUnSchedulePeriodicPolicy: - //ignore error, actually error should not be happened because we did not change data - //after the last unmarshal try. + // ignore error, actually error should not be happened because we did not change data + // after the last unmarshal try. policyObject := &period.PeriodicJobPolicy{} dt, _ := json.Marshal(m.Data) json.Unmarshal(dt, policyObject) converted = policyObject case opm.EventRegisterStatusHook: - //ignore error + // ignore error hookObject := &opm.HookData{} dt, _ := json.Marshal(m.Data) json.Unmarshal(dt, hookObject) converted = hookObject case opm.EventFireCommand: - //no need to convert []string + // no need to convert []string converted = m.Data } res := callback.Call([]reflect.Value{reflect.ValueOf(converted)}) e := res[0].Interface() if e != nil { err := e.(error) - //logged + // logged logger.Errorf("Failed to fire callback with error: %s\n", err) } } @@ -112,7 +112,7 @@ func (ms *MessageServer) Start() error { logger.Infof("Subscribe redis channel %s\n", res.Channel) break case "unsubscribe": - //Unsubscribe all, means main goroutine is exiting + // Unsubscribe all, means main goroutine is exiting logger.Infof("Unsubscribe redis channel %s\n", res.Channel) done <- nil return @@ -126,7 +126,7 @@ func (ms *MessageServer) Start() error { ticker := time.NewTicker(time.Minute) defer ticker.Stop() - //blocking here + // blocking here for err == nil { select { case <-ticker.C: @@ -137,13 +137,13 @@ func (ms *MessageServer) Start() error { } } - //Unsubscribe all + // Unsubscribe all psc.Unsubscribe() return <-done } -//Subscribe event with specified callback +// Subscribe event with specified callback func (ms *MessageServer) Subscribe(event string, callback interface{}) error { if utils.IsEmptyStr(event) { return errors.New("empty event is not allowed") diff --git a/src/jobservice/pool/message_server_test.go b/src/jobservice/pool/message_server_test.go index 1a7bcafee..831a63e34 100644 --- a/src/jobservice/pool/message_server_test.go +++ b/src/jobservice/pool/message_server_test.go @@ -47,7 +47,7 @@ func TestPublishPolicy(t *testing.T) { go func() { defer cancel() - //wait and then publish + // wait and then publish <-time.After(200 * time.Millisecond) p := &period.PeriodicJobPolicy{ @@ -82,7 +82,7 @@ func TestPublishPolicy(t *testing.T) { t.Fatal(err) } - //send quit signal + // send quit signal <-time.After(200 * time.Millisecond) err = tests.Clear(utils.KeyPeriodicNotification(tests.GiveMeTestNamespace()), conn) if err != nil { @@ -131,7 +131,7 @@ func TestPublishHook(t *testing.T) { t.Fatal(err) } - //send quit signal + // send quit signal <-time.After(200 * time.Millisecond) err = tests.Clear(utils.KeyPeriodicNotification(tests.GiveMeTestNamespace()), conn) if err != nil { @@ -185,7 +185,7 @@ func TestPublishCommands(t *testing.T) { t.Fatal(err) } - //hold for a while + // hold for a while <-time.After(200 * time.Millisecond) }() diff --git a/src/jobservice/pool/redis_job_wrapper.go b/src/jobservice/pool/redis_job_wrapper.go index e44796397..b50a11cac 100644 --- a/src/jobservice/pool/redis_job_wrapper.go +++ b/src/jobservice/pool/redis_job_wrapper.go @@ -14,14 +14,14 @@ import ( "github.com/goharbor/harbor/src/jobservice/opm" ) -//RedisJob is a job wrapper to wrap the job.Interface to the style which can be recognized by the redis pool. +// RedisJob is a job wrapper to wrap the job.Interface to the style which can be recognized by the redis pool. type RedisJob struct { - job interface{} //the real job implementation - context *env.Context //context - statsManager opm.JobStatsManager //job stats manager + job interface{} // the real job implementation + context *env.Context // context + statsManager opm.JobStatsManager // job stats manager } -//NewRedisJob is constructor of RedisJob +// NewRedisJob is constructor of RedisJob func NewRedisJob(j interface{}, ctx *env.Context, statsManager opm.JobStatsManager) *RedisJob { return &RedisJob{ job: j, @@ -30,7 +30,7 @@ func NewRedisJob(j interface{}, ctx *env.Context, statsManager opm.JobStatsManag } } -//Run the job +// Run the job func (rj *RedisJob) Run(j *work.Job) error { var ( cancelled = false @@ -43,17 +43,17 @@ func (rj *RedisJob) Run(j *work.Job) error { defer func() { if err == nil { logger.Infof("Job '%s:%s' exit with success", j.Name, j.ID) - return //nothing need to do + return // nothing need to do } - //log error + // log error logger.Errorf("Job '%s:%s' exit with error: %s\n", j.Name, j.ID, err) if buildContextFailed || rj.shouldDisableRetry(runningJob, j, cancelled) { - j.Fails = 10000000000 //Make it big enough to avoid retrying + j.Fails = 10000000000 // Make it big enough to avoid retrying now := time.Now().Unix() go func() { - timer := time.NewTimer(2 * time.Second) //make sure the failed job is already put into the dead queue + timer := time.NewTimer(2 * time.Second) // make sure the failed job is already put into the dead queue defer timer.Stop() <-timer.C @@ -66,33 +66,33 @@ func (rj *RedisJob) Run(j *work.Job) error { defer func() { if r := recover(); r != nil { err = fmt.Errorf("Runtime error: %s", r) - //record runtime error status + // record runtime error status rj.jobFailed(j.ID) } }() - //Wrap job + // Wrap job runningJob = Wrap(rj.job) execContext, err = rj.buildContext(j) if err != nil { buildContextFailed = true - goto FAILED //no need to retry + goto FAILED // no need to retry } defer func() { - //Close open io stream first + // Close open io stream first if closer, ok := execContext.GetLogger().(logger.Closer); ok { closer.Close() } }() - //Start to run + // Start to run rj.jobRunning(j.ID) - //Inject data + // Inject data err = runningJob.Run(execContext, j.Args) - //update the proper status + // update the proper status if err == nil { rj.jobSucceed(j.ID) return nil @@ -106,7 +106,7 @@ func (rj *RedisJob) Run(j *work.Job) error { if errs.IsJobCancelledError(err) { rj.jobCancelled(j.ID) cancelled = true - return err //need to resume + return err // need to resume } FAILED: @@ -135,7 +135,7 @@ func (rj *RedisJob) jobSucceed(jobID string) { } func (rj *RedisJob) buildContext(j *work.Job) (env.JobContext, error) { - //Build job execution context + // Build job execution context jData := env.JobData{ ID: j.ID, Name: j.Name, @@ -169,10 +169,10 @@ func (rj *RedisJob) buildContext(j *work.Job) (env.JobContext, error) { func (rj *RedisJob) shouldDisableRetry(j job.Interface, wj *work.Job, cancelled bool) bool { maxFails := j.MaxFails() if maxFails == 0 { - maxFails = 4 //Consistent with backend worker pool + maxFails = 4 // Consistent with backend worker pool } fails := wj.Fails - fails++ //as the fail is not returned to backend pool yet + fails++ // as the fail is not returned to backend pool yet if cancelled && fails < int64(maxFails) { return true diff --git a/src/jobservice/pool/redis_pool.go b/src/jobservice/pool/redis_pool.go index df737c9bc..ef23d935b 100644 --- a/src/jobservice/pool/redis_pool.go +++ b/src/jobservice/pool/redis_pool.go @@ -28,13 +28,13 @@ const ( workerPoolStatusHealthy = "Healthy" workerPoolStatusDead = "Dead" - //Copy from period.enqueuer + // Copy from period.enqueuer periodicEnqueuerHorizon = 4 * time.Minute pingRedisMaxTimes = 10 ) -//GoCraftWorkPool is the pool implementation based on gocraft/work powered by redis. +// GoCraftWorkPool is the pool implementation based on gocraft/work powered by redis. type GoCraftWorkPool struct { namespace string redisPool *redis.Pool @@ -47,17 +47,17 @@ type GoCraftWorkPool struct { statsManager opm.JobStatsManager messageServer *MessageServer - //no need to sync as write once and then only read - //key is name of known job - //value is the type of known job + // no need to sync as write once and then only read + // key is name of known job + // value is the type of known job knownJobs map[string]interface{} } -//RedisPoolContext ... -//We did not use this context to pass context info so far, just a placeholder. +// RedisPoolContext ... +// We did not use this context to pass context info so far, just a placeholder. type RedisPoolContext struct{} -//NewGoCraftWorkPool is constructor of goCraftWorkPool. +// NewGoCraftWorkPool is constructor of goCraftWorkPool. func NewGoCraftWorkPool(ctx *env.Context, namespace string, workerCount uint, redisPool *redis.Pool) *GoCraftWorkPool { pool := work.NewWorkerPool(RedisPoolContext{}, workerCount, namespace, redisPool) enqueuer := work.NewEnqueuer(namespace, redisPool) @@ -81,17 +81,17 @@ func NewGoCraftWorkPool(ctx *env.Context, namespace string, workerCount uint, re } } -//Start to serve -//Unblock action +// Start to serve +// Unblock action func (gcwp *GoCraftWorkPool) Start() error { if gcwp.redisPool == nil || gcwp.pool == nil || gcwp.context.SystemContext == nil { - //report and exit + // report and exit return errors.New("Redis worker pool can not start as it's not correctly configured") } - //Test the redis connection + // Test the redis connection if err := gcwp.ping(); err != nil { return err } @@ -105,13 +105,13 @@ func (gcwp *GoCraftWorkPool) Start() error { defer func() { gcwp.context.WG.Done() if err != nil { - //report error + // report error gcwp.context.ErrorChan <- err - done <- struct{}{} //exit immediately + done <- struct{}{} // exit immediately } }() - //Register callbacks + // Register callbacks if err = gcwp.messageServer.Subscribe(period.EventSchedulePeriodicPolicy, func(data interface{}) error { return gcwp.handleSchedulePolicy(data) @@ -139,7 +139,7 @@ func (gcwp *GoCraftWorkPool) Start() error { startTimes := 0 START_MSG_SERVER: - //Start message server + // Start message server if err = gcwp.messageServer.Start(); err != nil { logger.Errorf("Message server exits with error: %s\n", err.Error()) if startTimes < msgServerRetryTimes { @@ -159,11 +159,11 @@ func (gcwp *GoCraftWorkPool) Start() error { gcwp.context.WG.Done() gcwp.statsManager.Shutdown() }() - //Start stats manager - //None-blocking + // Start stats manager + // None-blocking gcwp.statsManager.Start() - //blocking call + // blocking call gcwp.scheduler.Start() }() @@ -174,19 +174,19 @@ func (gcwp *GoCraftWorkPool) Start() error { logger.Infof("Redis worker pool is stopped") }() - //Clear dirty data before pool starting + // Clear dirty data before pool starting if err := gcwp.sweeper.ClearOutdatedScheduledJobs(); err != nil { - //Only logged + // Only logged logger.Errorf("Clear outdated data before pool starting failed with error:%s\n", err) } - //Append middlewares + // Append middlewares gcwp.pool.Middleware((*RedisPoolContext).logJob) gcwp.pool.Start() logger.Infof("Redis worker pool is started") - //Block on listening context and done signal + // Block on listening context and done signal select { case <-gcwp.context.SystemContext.Done(): case <-done: @@ -198,35 +198,35 @@ func (gcwp *GoCraftWorkPool) Start() error { return nil } -//RegisterJob is used to register the job to the pool. -//j is the type of job +// RegisterJob is used to register the job to the pool. +// j is the type of job func (gcwp *GoCraftWorkPool) RegisterJob(name string, j interface{}) error { if utils.IsEmptyStr(name) || j == nil { return errors.New("job can not be registered with empty name or nil interface") } - //j must be job.Interface + // j must be job.Interface if _, ok := j.(job.Interface); !ok { return errors.New("job must implement the job.Interface") } redisJob := NewRedisJob(j, gcwp.context, gcwp.statsManager) - //Get more info from j + // Get more info from j theJ := Wrap(j) gcwp.pool.JobWithOptions(name, work.JobOptions{MaxFails: theJ.MaxFails()}, func(job *work.Job) error { return redisJob.Run(job) - }, //Use generic handler to handle as we do not accept context with this way. + }, // Use generic handler to handle as we do not accept context with this way. ) - gcwp.knownJobs[name] = j //keep the name of registered jobs as known jobs for future validation + gcwp.knownJobs[name] = j // keep the name of registered jobs as known jobs for future validation return nil } -//RegisterJobs is used to register multiple jobs to pool. +// RegisterJobs is used to register multiple jobs to pool. func (gcwp *GoCraftWorkPool) RegisterJobs(jobs map[string]interface{}) error { if jobs == nil || len(jobs) == 0 { return nil @@ -241,14 +241,14 @@ func (gcwp *GoCraftWorkPool) RegisterJobs(jobs map[string]interface{}) error { return nil } -//Enqueue job +// Enqueue job func (gcwp *GoCraftWorkPool) Enqueue(jobName string, params models.Parameters, isUnique bool) (models.JobStats, error) { var ( j *work.Job err error ) - //Enqueue job + // Enqueue job if isUnique { j, err = gcwp.enqueuer.EnqueueUnique(jobName, params) } else { @@ -259,27 +259,27 @@ func (gcwp *GoCraftWorkPool) Enqueue(jobName string, params models.Parameters, i return models.JobStats{}, err } - //avoid backend pool bug + // avoid backend pool bug if j == nil { return models.JobStats{}, fmt.Errorf("job '%s' can not be enqueued, please check the job metatdata", jobName) } res := generateResult(j, job.JobKindGeneric, isUnique) - //Save data with async way. Once it fails to do, let it escape - //The client method may help if the job is still in progress when get stats of this job + // Save data with async way. Once it fails to do, let it escape + // The client method may help if the job is still in progress when get stats of this job gcwp.statsManager.Save(res) return res, nil } -//Schedule job +// Schedule job func (gcwp *GoCraftWorkPool) Schedule(jobName string, params models.Parameters, runAfterSeconds uint64, isUnique bool) (models.JobStats, error) { var ( j *work.ScheduledJob err error ) - //Enqueue job in + // Enqueue job in if isUnique { j, err = gcwp.enqueuer.EnqueueUniqueIn(jobName, int64(runAfterSeconds), params) } else { @@ -290,7 +290,7 @@ func (gcwp *GoCraftWorkPool) Schedule(jobName string, params models.Parameters, return models.JobStats{}, err } - //avoid backend pool bug + // avoid backend pool bug if j == nil { return models.JobStats{}, fmt.Errorf("job '%s' can not be enqueued, please check the job metatdata", jobName) } @@ -298,14 +298,14 @@ func (gcwp *GoCraftWorkPool) Schedule(jobName string, params models.Parameters, res := generateResult(j.Job, job.JobKindScheduled, isUnique) res.Stats.RunAt = j.RunAt - //As job is already scheduled, we should not block this call - //Once it fails to do, use client method to help get the status of the escape job + // As job is already scheduled, we should not block this call + // Once it fails to do, use client method to help get the status of the escape job gcwp.statsManager.Save(res) return res, nil } -//PeriodicallyEnqueue job +// PeriodicallyEnqueue job func (gcwp *GoCraftWorkPool) PeriodicallyEnqueue(jobName string, params models.Parameters, cronSetting string) (models.JobStats, error) { id, nextRun, err := gcwp.scheduler.Schedule(jobName, params, cronSetting) if err != nil { @@ -331,7 +331,7 @@ func (gcwp *GoCraftWorkPool) PeriodicallyEnqueue(jobName string, params models.P return res, nil } -//GetJobStats return the job stats of the specified enqueued job. +// GetJobStats return the job stats of the specified enqueued job. func (gcwp *GoCraftWorkPool) GetJobStats(jobID string) (models.JobStats, error) { if utils.IsEmptyStr(jobID) { return models.JobStats{}, errors.New("empty job ID") @@ -340,19 +340,19 @@ func (gcwp *GoCraftWorkPool) GetJobStats(jobID string) (models.JobStats, error) return gcwp.statsManager.Retrieve(jobID) } -//Stats of pool +// Stats of pool func (gcwp *GoCraftWorkPool) Stats() (models.JobPoolStats, error) { - //Get the status of workerpool via client + // Get the status of workerpool via client hbs, err := gcwp.client.WorkerPoolHeartbeats() if err != nil { return models.JobPoolStats{}, err } - //Find the heartbeat of this pool via pid + // Find the heartbeat of this pool via pid stats := make([]*models.JobPoolStatsData, 0) for _, hb := range hbs { if hb.HeartbeatAt == 0 { - continue //invalid ones + continue // invalid ones } wPoolStatus := workerPoolStatusHealthy @@ -379,7 +379,7 @@ func (gcwp *GoCraftWorkPool) Stats() (models.JobPoolStats, error) { }, nil } -//StopJob will stop the job +// StopJob will stop the job func (gcwp *GoCraftWorkPool) StopJob(jobID string) error { if utils.IsEmptyStr(jobID) { return errors.New("empty job ID") @@ -394,13 +394,13 @@ func (gcwp *GoCraftWorkPool) StopJob(jobID string) error { switch theJob.Stats.JobKind { case job.JobKindGeneric: - //Only running job can be stopped + // Only running job can be stopped if theJob.Stats.Status != job.JobStatusRunning { return fmt.Errorf("job '%s' is not a running job", jobID) } case job.JobKindScheduled: - //we need to delete the scheduled job in the queue if it is not running yet - //otherwise, nothing need to do + // we need to delete the scheduled job in the queue if it is not running yet + // otherwise, nothing need to do if theJob.Stats.Status == job.JobStatusScheduled { if err := gcwp.client.DeleteScheduledJob(theJob.Stats.RunAt, jobID); err != nil { return err @@ -408,15 +408,15 @@ func (gcwp *GoCraftWorkPool) StopJob(jobID string) error { needSetStopStatus = true } case job.JobKindPeriodic: - //firstly delete the periodic job policy + // firstly delete the periodic job policy if err := gcwp.scheduler.UnSchedule(jobID); err != nil { return err } - //secondly we need try to delete the job instances scheduled for this periodic job, a try best action - gcwp.deleteScheduledJobsOfPeriodicPolicy(theJob.Stats.JobID, theJob.Stats.CronSpec) //ignore error as we have logged - //thirdly expire the job stats of this periodic job if exists + // secondly we need try to delete the job instances scheduled for this periodic job, a try best action + gcwp.deleteScheduledJobsOfPeriodicPolicy(theJob.Stats.JobID, theJob.Stats.CronSpec) // ignore error as we have logged + // thirdly expire the job stats of this periodic job if exists if err := gcwp.statsManager.ExpirePeriodicJobStats(theJob.Stats.JobID); err != nil { - //only logged + // only logged logger.Errorf("Expire the stats of job %s failed with error: %s\n", theJob.Stats.JobID, err) } @@ -425,17 +425,17 @@ func (gcwp *GoCraftWorkPool) StopJob(jobID string) error { break } - //Check if the job has 'running' instance + // Check if the job has 'running' instance if theJob.Stats.Status == job.JobStatusRunning { - //Send 'stop' ctl command to the running instance + // Send 'stop' ctl command to the running instance if err := gcwp.statsManager.SendCommand(jobID, opm.CtlCommandStop); err != nil { return err } - //The job running instance will set the status to 'stopped' + // The job running instance will set the status to 'stopped' needSetStopStatus = false } - //If needed, update the job status to 'stopped' + // If needed, update the job status to 'stopped' if needSetStopStatus { gcwp.statsManager.SetJobStatus(jobID, job.JobStatusStopped) } @@ -443,7 +443,7 @@ func (gcwp *GoCraftWorkPool) StopJob(jobID string) error { return nil } -//CancelJob will cancel the job +// CancelJob will cancel the job func (gcwp *GoCraftWorkPool) CancelJob(jobID string) error { if utils.IsEmptyStr(jobID) { return errors.New("empty job ID") @@ -460,7 +460,7 @@ func (gcwp *GoCraftWorkPool) CancelJob(jobID string) error { return fmt.Errorf("only running job can be cancelled, job '%s' seems not running now", theJob.Stats.JobID) } - //Send 'cancel' ctl command to the running instance + // Send 'cancel' ctl command to the running instance if err := gcwp.statsManager.SendCommand(jobID, opm.CtlCommandCancel); err != nil { return err } @@ -472,7 +472,7 @@ func (gcwp *GoCraftWorkPool) CancelJob(jobID string) error { return nil } -//RetryJob retry the job +// RetryJob retry the job func (gcwp *GoCraftWorkPool) RetryJob(jobID string) error { if utils.IsEmptyStr(jobID) { return errors.New("empty job ID") @@ -490,13 +490,13 @@ func (gcwp *GoCraftWorkPool) RetryJob(jobID string) error { return gcwp.client.RetryDeadJob(theJob.Stats.DieAt, jobID) } -//IsKnownJob ... +// IsKnownJob ... func (gcwp *GoCraftWorkPool) IsKnownJob(name string) (interface{}, bool) { v, ok := gcwp.knownJobs[name] return v, ok } -//ValidateJobParameters ... +// ValidateJobParameters ... func (gcwp *GoCraftWorkPool) ValidateJobParameters(jobType interface{}, params map[string]interface{}) error { if jobType == nil { return errors.New("nil job type") @@ -506,8 +506,8 @@ func (gcwp *GoCraftWorkPool) ValidateJobParameters(jobType interface{}, params m return theJ.Validate(params) } -//RegisterHook registers status hook url -//sync method +// RegisterHook registers status hook url +// sync method func (gcwp *GoCraftWorkPool) RegisterHook(jobID string, hookURL string) error { if utils.IsEmptyStr(jobID) { return errors.New("empty job ID") @@ -531,12 +531,12 @@ func (gcwp *GoCraftWorkPool) deleteScheduledJobsOfPeriodicPolicy(policyID string nowTime := time.Unix(now, 0) horizon := nowTime.Add(periodicEnqueuerHorizon) - //try to delete more - //return the last error if occurred + // try to delete more + // return the last error if occurred for t := schedule.Next(nowTime); t.Before(horizon); t = schedule.Next(t) { epoch := t.Unix() if err = gcwp.client.DeleteScheduledJob(epoch, policyID); err != nil { - //only logged + // only logged logger.Warningf("delete scheduled instance for periodic job %s failed with error: %s\n", policyID, err) } } @@ -606,13 +606,13 @@ func (gcwp *GoCraftWorkPool) handleOPCommandFiring(data interface{}) error { return gcwp.statsManager.SendCommand(jobID, command) } -//log the job +// log the job func (rpc *RedisPoolContext) logJob(job *work.Job, next work.NextMiddlewareFunc) error { logger.Infof("Job incoming: %s:%s", job.Name, job.ID) return next() } -//Ping the redis server +// Ping the redis server func (gcwp *GoCraftWorkPool) ping() error { conn := gcwp.redisPool.Get() defer conn.Close() @@ -629,7 +629,7 @@ func (gcwp *GoCraftWorkPool) ping() error { return fmt.Errorf("connect to redis server timeout: %s", err.Error()) } -//generate the job stats data +// generate the job stats data func generateResult(j *work.Job, jobKind string, isUnique bool) models.JobStats { if j == nil { return models.JobStats{} diff --git a/src/jobservice/pool/redis_pool_test.go b/src/jobservice/pool/redis_pool_test.go index 683bc2231..9c1c53aea 100644 --- a/src/jobservice/pool/redis_pool_test.go +++ b/src/jobservice/pool/redis_pool_test.go @@ -139,8 +139,8 @@ func TestEnqueuePeriodicJob(t *testing.T) { t.Error(err) } - //cancel() - //<-time.After(1 * time.Second) + // cancel() + // <-time.After(1 * time.Second) } /*func TestCancelAndRetryJobWithHook(t *testing.T) { @@ -173,7 +173,7 @@ func TestEnqueuePeriodicJob(t *testing.T) { if err := wp.RegisterHook(res.Stats.JobID, ts.URL); err != nil { t.Fatal(err) } - //make sure it's running + // make sure it's running timer := time.NewTimer(1 * time.Second) defer timer.Stop() @@ -188,7 +188,7 @@ CHECK: } } - //cancel + // cancel if err := wp.CancelJob(res.Stats.JobID); err != nil { t.Fatal(err) } @@ -204,7 +204,7 @@ CHECK: t.Fatalf("expect none zero 'DieAt' but got 0 value") } - //retry + // retry if err := wp.RetryJob(updatedRes.Stats.JobID); err != nil { t.Fatal(err) } @@ -315,16 +315,16 @@ func (j *fakeRunnableJob) Run(ctx env.JobContext, params map[string]interface{}) } type fakeContext struct { - //System context + // System context sysContext context.Context - //op command func + // op command func opCommandFunc job.CheckOPCmdFunc - //checkin func + // checkin func checkInFunc job.CheckInFunc - //other required information + // other required information properties map[string]interface{} } @@ -335,15 +335,15 @@ func newContext(sysCtx context.Context) *fakeContext { } } -//Build implements the same method in env.JobContext interface -//This func will build the job execution context before running +// Build implements the same method in env.JobContext interface +// This func will build the job execution context before running func (c *fakeContext) Build(dep env.JobData) (env.JobContext, error) { jContext := &fakeContext{ sysContext: c.sysContext, properties: make(map[string]interface{}), } - //Copy properties + // Copy properties if len(c.properties) > 0 { for k, v := range c.properties { jContext.properties[k] = v @@ -376,18 +376,18 @@ func (c *fakeContext) Build(dep env.JobData) (env.JobContext, error) { return jContext, nil } -//Get implements the same method in env.JobContext interface +// Get implements the same method in env.JobContext interface func (c *fakeContext) Get(prop string) (interface{}, bool) { v, ok := c.properties[prop] return v, ok } -//SystemContext implements the same method in env.JobContext interface +// SystemContext implements the same method in env.JobContext interface func (c *fakeContext) SystemContext() context.Context { return c.sysContext } -//Checkin is bridge func for reporting detailed status +// Checkin is bridge func for reporting detailed status func (c *fakeContext) Checkin(status string) error { if c.checkInFunc != nil { c.checkInFunc(status) @@ -398,7 +398,7 @@ func (c *fakeContext) Checkin(status string) error { return nil } -//OPCommand return the control operational command like stop/cancel if have +// OPCommand return the control operational command like stop/cancel if have func (c *fakeContext) OPCommand() (string, bool) { if c.opCommandFunc != nil { return c.opCommandFunc() @@ -407,7 +407,7 @@ func (c *fakeContext) OPCommand() (string, bool) { return "", false } -//GetLogger returns the logger +// GetLogger returns the logger func (c *fakeContext) GetLogger() logger.Interface { return nil } diff --git a/src/jobservice/pool/runner.go b/src/jobservice/pool/runner.go index 256003df6..540b0cbf3 100644 --- a/src/jobservice/pool/runner.go +++ b/src/jobservice/pool/runner.go @@ -8,7 +8,7 @@ import ( "github.com/goharbor/harbor/src/jobservice/job" ) -//Wrap returns a new job.Interface based on the wrapped job handler reference. +// Wrap returns a new job.Interface based on the wrapped job handler reference. func Wrap(j interface{}) job.Interface { theType := reflect.TypeOf(j) @@ -16,7 +16,7 @@ func Wrap(j interface{}) job.Interface { theType = theType.Elem() } - //Crate new + // Crate new v := reflect.New(theType).Elem() return v.Addr().Interface().(job.Interface) } diff --git a/src/jobservice/runtime/bootstrap.go b/src/jobservice/runtime/bootstrap.go index 655f87d19..2a2e098c7 100644 --- a/src/jobservice/runtime/bootstrap.go +++ b/src/jobservice/runtime/bootstrap.go @@ -32,35 +32,35 @@ const ( dialWriteTimeout = 10 * time.Second ) -//JobService ... +// JobService ... var JobService = &Bootstrap{} -//Bootstrap is coordinating process to help load and start the other components to serve. +// Bootstrap is coordinating process to help load and start the other components to serve. type Bootstrap struct { jobConextInitializer env.JobContextInitializer } -//SetJobContextInitializer set the job context initializer +// SetJobContextInitializer set the job context initializer func (bs *Bootstrap) SetJobContextInitializer(initializer env.JobContextInitializer) { if initializer != nil { bs.jobConextInitializer = initializer } } -//LoadAndRun will load configurations, initialize components and then start the related process to serve requests. -//Return error if meet any problems. +// LoadAndRun will load configurations, initialize components and then start the related process to serve requests. +// Return error if meet any problems. func (bs *Bootstrap) LoadAndRun() { - //Create the root context + // Create the root context ctx, cancel := context.WithCancel(context.Background()) defer cancel() rootContext := &env.Context{ SystemContext: ctx, WG: &sync.WaitGroup{}, - ErrorChan: make(chan error, 1), //with 1 buffer + ErrorChan: make(chan error, 1), // with 1 buffer } - //Build specified job context + // Build specified job context if bs.jobConextInitializer != nil { if jobCtx, err := bs.jobConextInitializer(rootContext); err == nil { rootContext.JobContext = jobCtx @@ -69,7 +69,7 @@ func (bs *Bootstrap) LoadAndRun() { } } - //Start the pool + // Start the pool var ( backendPool pool.Interface wpErr error @@ -83,19 +83,19 @@ func (bs *Bootstrap) LoadAndRun() { logger.Fatalf("Worker pool backend '%s' is not supported", config.DefaultConfig.PoolConfig.Backend) } - //Initialize controller + // Initialize controller ctl := core.NewController(backendPool) - //Start the API server + // Start the API server apiServer := bs.loadAndRunAPIServer(rootContext, config.DefaultConfig, ctl) logger.Infof("Server is started at %s:%d with %s", "", config.DefaultConfig.Port, config.DefaultConfig.Protocol) - //Start outdated log files sweeper + // Start outdated log files sweeper logSweeper := logger.NewSweeper(ctx, config.GetLogBasePath(), config.GetLogArchivePeriod()) logSweeper.Start() - //To indicate if any errors occurred + // To indicate if any errors occurred var err error - //Block here + // Block here sig := make(chan os.Signal, 1) signal.Notify(sig, os.Interrupt, syscall.SIGTERM, os.Kill) select { @@ -103,13 +103,13 @@ func (bs *Bootstrap) LoadAndRun() { case err = <-rootContext.ErrorChan: } - //Call cancel to send termination signal to other interested parts. + // Call cancel to send termination signal to other interested parts. cancel() - //Gracefully shutdown + // Gracefully shutdown apiServer.Stop() - //In case stop is called before the server is ready + // In case stop is called before the server is ready close := make(chan bool, 1) go func() { timer := time.NewTimer(10 * time.Second) @@ -117,7 +117,7 @@ func (bs *Bootstrap) LoadAndRun() { select { case <-timer.C: - //Try again + // Try again apiServer.Stop() case <-close: return @@ -135,9 +135,9 @@ func (bs *Bootstrap) LoadAndRun() { logger.Infof("Server gracefully exit") } -//Load and run the API server. +// Load and run the API server. func (bs *Bootstrap) loadAndRunAPIServer(ctx *env.Context, cfg *config.Configuration, ctl *core.Controller) *api.Server { - //Initialized API server + // Initialized API server authProvider := &api.SecretAuthenticator{} handler := api.NewDefaultHandler(ctl) router := api.NewBaseRouter(handler, authProvider) @@ -151,13 +151,13 @@ func (bs *Bootstrap) loadAndRunAPIServer(ctx *env.Context, cfg *config.Configura } server := api.NewServer(ctx, router, serverConfig) - //Start processes + // Start processes server.Start() return server } -//Load and run the worker pool +// Load and run the worker pool func (bs *Bootstrap) loadAndRunRedisWorkerPool(ctx *env.Context, cfg *config.Configuration) (pool.Interface, error) { redisPool := &redis.Pool{ MaxActive: 6, @@ -177,9 +177,9 @@ func (bs *Bootstrap) loadAndRunRedisWorkerPool(ctx *env.Context, cfg *config.Con fmt.Sprintf("{%s}", cfg.PoolConfig.RedisPoolCfg.Namespace), cfg.PoolConfig.WorkerCount, redisPool) - //Register jobs here + // Register jobs here if err := redisWorkerPool.RegisterJob(impl.KnownJobDemo, (*impl.DemoJob)(nil)); err != nil { - //exit + // exit return nil, err } if err := redisWorkerPool.RegisterJobs( @@ -190,7 +190,7 @@ func (bs *Bootstrap) loadAndRunRedisWorkerPool(ctx *env.Context, cfg *config.Con job.ImageReplicate: (*replication.Replicator)(nil), job.ImageGC: (*gc.GarbageCollector)(nil), }); err != nil { - //exit + // exit return nil, err } diff --git a/src/jobservice/tests/utils.go b/src/jobservice/tests/utils.go index 630dc027c..9c5ab7c82 100644 --- a/src/jobservice/tests/utils.go +++ b/src/jobservice/tests/utils.go @@ -1,6 +1,6 @@ // Copyright 2018 The Harbor Authors. All rights reserved. -//Package tests provide test utilities +// Package tests provide test utilities package tests import ( @@ -21,7 +21,7 @@ const ( testingNamespace = "testing_job_service_v2" ) -//GiveMeRedisPool ... +// GiveMeRedisPool ... func GiveMeRedisPool() *redis.Pool { redisHost := getRedisHost() redisPool := &redis.Pool{ @@ -42,12 +42,12 @@ func GiveMeRedisPool() *redis.Pool { return redisPool } -//GiveMeTestNamespace ... +// GiveMeTestNamespace ... func GiveMeTestNamespace() string { return testingNamespace } -//Clear ... +// Clear ... func Clear(key string, conn redis.Conn) error { if conn != nil { defer conn.Close() @@ -58,7 +58,7 @@ func Clear(key string, conn redis.Conn) error { return errors.New("failed to clear") } -//ClearAll ... +// ClearAll ... func ClearAll(namespace string, conn redis.Conn) error { defer conn.Close() @@ -83,7 +83,7 @@ func ClearAll(namespace string, conn redis.Conn) error { func getRedisHost() string { redisHost := os.Getenv(testingRedisHost) if redisHost == "" { - redisHost = "10.160.178.186" //for local test + redisHost = "10.160.178.186" // for local test } return redisHost diff --git a/src/jobservice/utils/gocarft_work.go b/src/jobservice/utils/gocarft_work.go index 73a6148ba..3036e4e6c 100644 --- a/src/jobservice/utils/gocarft_work.go +++ b/src/jobservice/utils/gocarft_work.go @@ -10,10 +10,10 @@ import ( "github.com/gocraft/work" ) -//Functions defined here are mainly from dep lib "github.com/gocraft/work". -//Only for compatible +// Functions defined here are mainly from dep lib "github.com/gocraft/work". +// Only for compatible -//MakeIdentifier creates uuid for job. +// MakeIdentifier creates uuid for job. func MakeIdentifier() string { b := make([]byte, 12) _, err := io.ReadFull(rand.Reader, b) @@ -23,34 +23,34 @@ func MakeIdentifier() string { return fmt.Sprintf("%x", b) } -//MakeUniquePeriodicID creates id for the periodic job. +// MakeUniquePeriodicID creates id for the periodic job. func MakeUniquePeriodicID(name, spec string, epoch int64) string { return fmt.Sprintf("periodic:job:%s:%s:%d", name, spec, epoch) } -//RedisNamespacePrefix ... Same with 'KeyNamespacePrefix', only for compatibility. +// RedisNamespacePrefix ... Same with 'KeyNamespacePrefix', only for compatibility. func RedisNamespacePrefix(namespace string) string { return KeyNamespacePrefix(namespace) } -//RedisKeyScheduled returns key of scheduled job. +// RedisKeyScheduled returns key of scheduled job. func RedisKeyScheduled(namespace string) string { return RedisNamespacePrefix(namespace) + "scheduled" } -//RedisKeyLastPeriodicEnqueue returns key of timestamp if last periodic enqueue. +// RedisKeyLastPeriodicEnqueue returns key of timestamp if last periodic enqueue. func RedisKeyLastPeriodicEnqueue(namespace string) string { return RedisNamespacePrefix(namespace) + "last_periodic_enqueue" } -//RedisKeyDead returns key of the dead jobs. +// RedisKeyDead returns key of the dead jobs. func RedisKeyDead(namespace string) string { return RedisNamespacePrefix(namespace) + "dead" } var nowMock int64 -//NowEpochSeconds ... +// NowEpochSeconds ... func NowEpochSeconds() int64 { if nowMock != 0 { return nowMock @@ -58,17 +58,17 @@ func NowEpochSeconds() int64 { return time.Now().Unix() } -//SetNowEpochSecondsMock ... +// SetNowEpochSecondsMock ... func SetNowEpochSecondsMock(t int64) { nowMock = t } -//SerializeJob encodes work.Job to json data. +// SerializeJob encodes work.Job to json data. func SerializeJob(job *work.Job) ([]byte, error) { return json.Marshal(job) } -//DeSerializeJob decodes bytes to ptr of work.Job. +// DeSerializeJob decodes bytes to ptr of work.Job. func DeSerializeJob(jobBytes []byte) (*work.Job, error) { var j work.Job err := json.Unmarshal(jobBytes, &j) diff --git a/src/jobservice/utils/keys.go b/src/jobservice/utils/keys.go index 888d7b16b..98913c520 100644 --- a/src/jobservice/utils/keys.go +++ b/src/jobservice/utils/keys.go @@ -12,16 +12,16 @@ import ( func generateScore() int64 { ticks := time.Now().Unix() rand := rand.New(rand.NewSource(ticks)) - return ticks + rand.Int63n(1000) //Double confirm to avoid potential duplications + return ticks + rand.Int63n(1000) // Double confirm to avoid potential duplications } -//MakePeriodicPolicyUUID returns an UUID for the periodic policy. +// MakePeriodicPolicyUUID returns an UUID for the periodic policy. func MakePeriodicPolicyUUID() (string, int64) { score := generateScore() return MakeIdentifier(), score } -//KeyNamespacePrefix returns the based key based on the namespace. +// KeyNamespacePrefix returns the based key based on the namespace. func KeyNamespacePrefix(namespace string) string { ns := strings.TrimSpace(namespace) if !strings.HasSuffix(ns, ":") { @@ -31,37 +31,37 @@ func KeyNamespacePrefix(namespace string) string { return ns } -//KeyPeriod returns the key of period +// KeyPeriod returns the key of period func KeyPeriod(namespace string) string { return fmt.Sprintf("%s%s", KeyNamespacePrefix(namespace), "period") } -//KeyPeriodicPolicy returns the key of periodic policies. +// KeyPeriodicPolicy returns the key of periodic policies. func KeyPeriodicPolicy(namespace string) string { return fmt.Sprintf("%s:%s", KeyPeriod(namespace), "policies") } -//KeyPeriodicPolicyScore returns the key of policy key and score mapping. +// KeyPeriodicPolicyScore returns the key of policy key and score mapping. func KeyPeriodicPolicyScore(namespace string) string { return fmt.Sprintf("%s:%s", KeyPeriod(namespace), "key_score") } -//KeyPeriodicNotification returns the key of periodic pub/sub channel. +// KeyPeriodicNotification returns the key of periodic pub/sub channel. func KeyPeriodicNotification(namespace string) string { return fmt.Sprintf("%s:%s", KeyPeriodicPolicy(namespace), "notifications") } -//KeyPeriodicLock returns the key of locker under period +// KeyPeriodicLock returns the key of locker under period func KeyPeriodicLock(namespace string) string { return fmt.Sprintf("%s:%s", KeyPeriod(namespace), "lock") } -//KeyJobStats returns the key of job stats +// KeyJobStats returns the key of job stats func KeyJobStats(namespace string, jobID string) string { return fmt.Sprintf("%s%s:%s", KeyNamespacePrefix(namespace), "job_stats", jobID) } -//KeyJobCtlCommands give the key for publishing ctl commands like 'stop' etc. +// KeyJobCtlCommands give the key for publishing ctl commands like 'stop' etc. func KeyJobCtlCommands(namespace string, jobID string) string { return fmt.Sprintf("%s%s:%s", KeyNamespacePrefix(namespace), "ctl_commands", jobID) } diff --git a/src/jobservice/utils/utils.go b/src/jobservice/utils/utils.go index aca0fb99f..6b880f73d 100644 --- a/src/jobservice/utils/utils.go +++ b/src/jobservice/utils/utils.go @@ -1,6 +1,6 @@ // Copyright 2018 The Harbor Authors. All rights reserved. -//Package utils provides reusable and sharable utilities for other packages and components. +// Package utils provides reusable and sharable utilities for other packages and components. package utils import ( @@ -14,17 +14,17 @@ import ( "github.com/gomodule/redigo/redis" ) -//IsEmptyStr check if the specified str is empty (len ==0) after triming prefix and suffix spaces. +// IsEmptyStr check if the specified str is empty (len ==0) after triming prefix and suffix spaces. func IsEmptyStr(str string) bool { return len(strings.TrimSpace(str)) == 0 } -//ReadEnv return the value of env variable. +// ReadEnv return the value of env variable. func ReadEnv(key string) string { return os.Getenv(key) } -//FileExists check if the specified exists. +// FileExists check if the specified exists. func FileExists(file string) bool { if !IsEmptyStr(file) { _, err := os.Stat(file) @@ -41,7 +41,7 @@ func FileExists(file string) bool { return false } -//DirExists check if the specified dir exists +// DirExists check if the specified dir exists func DirExists(path string) bool { if IsEmptyStr(path) { return false @@ -55,12 +55,12 @@ func DirExists(path string) bool { return f.IsDir() } -//IsValidPort check if port is valid. +// IsValidPort check if port is valid. func IsValidPort(port uint) bool { return port != 0 && port < 65536 } -//IsValidURL validates if the url is well-formted +// IsValidURL validates if the url is well-formted func IsValidURL(address string) bool { if IsEmptyStr(address) { return false @@ -73,7 +73,7 @@ func IsValidURL(address string) bool { return true } -//TranslateRedisAddress translates the comma format to redis URL +// TranslateRedisAddress translates the comma format to redis URL func TranslateRedisAddress(commaFormat string) (string, bool) { if IsEmptyStr(commaFormat) { return "", false @@ -86,14 +86,14 @@ func TranslateRedisAddress(commaFormat string) (string, bool) { } urlParts := []string{} - //section[0] should be host:port + // section[0] should be host:port redisURL := fmt.Sprintf("redis://%s", sections[0]) if _, err := url.Parse(redisURL); err != nil { return "", false } urlParts = append(urlParts, "redis://", sections[0]) - //Ignore weight - //Check password + // Ignore weight + // Check password if totalSections >= 3 && !IsEmptyStr(sections[2]) { urlParts = []string{urlParts[0], fmt.Sprintf("%s:%s@", "arbitrary_username", sections[2]), urlParts[1]} } @@ -107,13 +107,13 @@ func TranslateRedisAddress(commaFormat string) (string, bool) { return strings.Join(urlParts, ""), true } -//JobScore represents the data item with score in the redis db. +// JobScore represents the data item with score in the redis db. type JobScore struct { JobBytes []byte Score int64 } -//GetZsetByScore get the items from the zset filtered by the specified score scope. +// GetZsetByScore get the items from the zset filtered by the specified score scope. func GetZsetByScore(pool *redis.Pool, key string, scores []int64) ([]JobScore, error) { if pool == nil || IsEmptyStr(key) || len(scores) < 2 { return nil, errors.New("bad arguments") diff --git a/src/registryctl/auth/secret.go b/src/registryctl/auth/secret.go index f3851c58b..1a8d6b45e 100644 --- a/src/registryctl/auth/secret.go +++ b/src/registryctl/auth/secret.go @@ -22,7 +22,7 @@ import ( "github.com/goharbor/harbor/src/common/secret" ) -//HarborSecret is the prefix of the value of Authorization header. +// HarborSecret is the prefix of the value of Authorization header. const HarborSecret = secret.HeaderPrefix var ( diff --git a/src/registryctl/config/config.go b/src/registryctl/config/config.go index f7565fa17..04771a063 100644 --- a/src/registryctl/config/config.go +++ b/src/registryctl/config/config.go @@ -21,10 +21,10 @@ import ( yaml "gopkg.in/yaml.v2" ) -//DefaultConfig ... +// DefaultConfig ... var DefaultConfig = &Configuration{} -//Configuration loads the configuration of registry controller. +// Configuration loads the configuration of registry controller. type Configuration struct { Protocol string `yaml:"protocol"` Port string `yaml:"port"` @@ -35,10 +35,10 @@ type Configuration struct { } `yaml:"https_config,omitempty"` } -//Load the configuration options from the specified yaml file. +// Load the configuration options from the specified yaml file. func (c *Configuration) Load(yamlFilePath string, detectEnv bool) error { if len(yamlFilePath) != 0 { - //Try to load from file first + // Try to load from file first data, err := ioutil.ReadFile(yamlFilePath) if err != nil { return err @@ -55,22 +55,22 @@ func (c *Configuration) Load(yamlFilePath string, detectEnv bool) error { return nil } -//GetLogLevel returns the log level +// GetLogLevel returns the log level func GetLogLevel() string { return DefaultConfig.LogLevel } -//GetJobAuthSecret get the auth secret from the env +// GetJobAuthSecret get the auth secret from the env func GetJobAuthSecret() string { return os.Getenv("JOBSERVICE_SECRET") } -//GetUIAuthSecret get the auth secret of UI side +// GetUIAuthSecret get the auth secret of UI side func GetUIAuthSecret() string { return os.Getenv("UI_SECRET") } -//loadEnvs Load env variables +// loadEnvs Load env variables func (c *Configuration) loadEnvs() { prot := os.Getenv("REGISTRYCTL_PROTOCOL") if len(prot) != 0 { @@ -82,7 +82,7 @@ func (c *Configuration) loadEnvs() { c.Port = p } - //Only when protocol is https + // Only when protocol is https if c.Protocol == "HTTPS" { cert := os.Getenv("REGISTRYCTL_HTTPS_CERT") if len(cert) != 0 { diff --git a/src/replication/consts.go b/src/replication/consts.go index 8773ab27d..70b1781c8 100644 --- a/src/replication/consts.go +++ b/src/replication/consts.go @@ -1,27 +1,27 @@ package replication const ( - //FilterItemKindProject : Kind of filter item is 'project' + // FilterItemKindProject : Kind of filter item is 'project' FilterItemKindProject = "project" - //FilterItemKindRepository : Kind of filter item is 'repository' + // FilterItemKindRepository : Kind of filter item is 'repository' FilterItemKindRepository = "repository" - //FilterItemKindTag : Kind of filter item is 'tag' + // FilterItemKindTag : Kind of filter item is 'tag' FilterItemKindTag = "tag" - //FilterItemKindLabel : Kind of filter item is 'label' + // FilterItemKindLabel : Kind of filter item is 'label' FilterItemKindLabel = "label" - //AdaptorKindHarbor : Kind of adaptor of Harbor + // AdaptorKindHarbor : Kind of adaptor of Harbor AdaptorKindHarbor = "Harbor" - //TriggerKindImmediate : Kind of trigger is 'Immediate' + // TriggerKindImmediate : Kind of trigger is 'Immediate' TriggerKindImmediate = "Immediate" - //TriggerKindSchedule : Kind of trigger is 'Scheduled' + // TriggerKindSchedule : Kind of trigger is 'Scheduled' TriggerKindSchedule = "Scheduled" - //TriggerKindManual : Kind of trigger is 'Manual' + // TriggerKindManual : Kind of trigger is 'Manual' TriggerKindManual = "Manual" - //TriggerScheduleDaily : type of scheduling is 'Daily' + // TriggerScheduleDaily : type of scheduling is 'Daily' TriggerScheduleDaily = "Daily" - //TriggerScheduleWeekly : type of scheduling is 'Weekly' + // TriggerScheduleWeekly : type of scheduling is 'Weekly' TriggerScheduleWeekly = "Weekly" ) diff --git a/src/replication/core/controller.go b/src/replication/core/controller.go index 58e8cb1e8..c74b391e9 100644 --- a/src/replication/core/controller.go +++ b/src/replication/core/controller.go @@ -36,42 +36,42 @@ type Controller interface { Replicate(policyID int64, metadata ...map[string]interface{}) error } -//DefaultController is core module to cordinate and control the overall workflow of the -//replication modules. +// DefaultController is core module to cordinate and control the overall workflow of the +// replication modules. type DefaultController struct { - //Indicate whether the controller has been initialized or not + // Indicate whether the controller has been initialized or not initialized bool - //Manage the policies + // Manage the policies policyManager policy.Manager - //Manage the targets + // Manage the targets targetManager target.Manager - //Handle the things related with source + // Handle the things related with source sourcer *source.Sourcer - //Manage the triggers of policies + // Manage the triggers of policies triggerManager *trigger.Manager - //Handle the replication work + // Handle the replication work replicator replicator.Replicator } -//Keep controller as singleton instance +// Keep controller as singleton instance var ( GlobalController Controller ) -//ControllerConfig includes related configurations required by the controller +// ControllerConfig includes related configurations required by the controller type ControllerConfig struct { - //The capacity of the cache storing enabled triggers + // The capacity of the cache storing enabled triggers CacheCapacity int } -//NewDefaultController is the constructor of DefaultController. +// NewDefaultController is the constructor of DefaultController. func NewDefaultController(cfg ControllerConfig) *DefaultController { - //Controller refer the default instances + // Controller refer the default instances ctl := &DefaultController{ policyManager: policy.NewDefaultManager(), targetManager: target.NewDefaultManager(), @@ -86,17 +86,17 @@ func NewDefaultController(cfg ControllerConfig) *DefaultController { // Init creates the GlobalController and inits it func Init() error { - GlobalController = NewDefaultController(ControllerConfig{}) //Use default data + GlobalController = NewDefaultController(ControllerConfig{}) // Use default data return GlobalController.Init() } -//Init will initialize the controller and the sub components +// Init will initialize the controller and the sub components func (ctl *DefaultController) Init() error { if ctl.initialized { return nil } - //Initialize sourcer + // Initialize sourcer ctl.sourcer.Init() ctl.initialized = true @@ -104,7 +104,7 @@ func (ctl *DefaultController) Init() error { return nil } -//CreatePolicy is used to create a new policy and enable it if necessary +// CreatePolicy is used to create a new policy and enable it if necessary func (ctl *DefaultController) CreatePolicy(newPolicy models.ReplicationPolicy) (int64, error) { id, err := ctl.policyManager.CreatePolicy(newPolicy) if err != nil { @@ -119,8 +119,8 @@ func (ctl *DefaultController) CreatePolicy(newPolicy models.ReplicationPolicy) ( return id, nil } -//UpdatePolicy will update the policy with new content. -//Parameter updatedPolicy must have the ID of the updated policy. +// UpdatePolicy will update the policy with new content. +// Parameter updatedPolicy must have the ID of the updated policy. func (ctl *DefaultController) UpdatePolicy(updatedPolicy models.ReplicationPolicy) error { id := updatedPolicy.ID originPolicy, err := ctl.policyManager.GetPolicy(id) @@ -164,7 +164,7 @@ func (ctl *DefaultController) UpdatePolicy(updatedPolicy models.ReplicationPolic return nil } -//RemovePolicy will remove the specified policy and clean the related settings +// RemovePolicy will remove the specified policy and clean the related settings func (ctl *DefaultController) RemovePolicy(policyID int64) error { // TODO check pre-conditions @@ -184,18 +184,18 @@ func (ctl *DefaultController) RemovePolicy(policyID int64) error { return ctl.policyManager.RemovePolicy(policyID) } -//GetPolicy is delegation of GetPolicy of Policy.Manager +// GetPolicy is delegation of GetPolicy of Policy.Manager func (ctl *DefaultController) GetPolicy(policyID int64) (models.ReplicationPolicy, error) { return ctl.policyManager.GetPolicy(policyID) } -//GetPolicies is delegation of GetPoliciemodels.ReplicationPolicy{}s of Policy.Manager +// GetPolicies is delegation of GetPoliciemodels.ReplicationPolicy{}s of Policy.Manager func (ctl *DefaultController) GetPolicies(query models.QueryParameter) (*models.ReplicationPolicyQueryResult, error) { return ctl.policyManager.GetPolicies(query) } -//Replicate starts one replication defined in the specified policy; -//Can be launched by the API layer and related triggers. +// Replicate starts one replication defined in the specified policy; +// Can be launched by the API layer and related triggers. func (ctl *DefaultController) Replicate(policyID int64, metadata ...map[string]interface{}) error { policy, err := ctl.GetPolicy(policyID) if err != nil { diff --git a/src/replication/event/init.go b/src/replication/event/init.go index 8813725e2..c0808f67a 100644 --- a/src/replication/event/init.go +++ b/src/replication/event/init.go @@ -20,9 +20,9 @@ import ( "github.com/goharbor/harbor/src/replication/event/topic" ) -//Subscribe related topics +// Subscribe related topics func init() { - //Listen the related event topics + // Listen the related event topics handlers := map[string]notifier.NotificationHandler{ topic.StartReplicationTopic: &StartReplicationHandler{}, topic.ReplicationEventTopicOnPush: &OnPushHandler{}, diff --git a/src/replication/event/notification/notification.go b/src/replication/event/notification/notification.go index fa2309b78..ecfda4c87 100644 --- a/src/replication/event/notification/notification.go +++ b/src/replication/event/notification/notification.go @@ -14,21 +14,21 @@ package notification -//OnPushNotification contains the data required by this handler +// OnPushNotification contains the data required by this handler type OnPushNotification struct { - //The name of the image that is being pushed + // The name of the image that is being pushed Image string } -//OnDeletionNotification contains the data required by this handler +// OnDeletionNotification contains the data required by this handler type OnDeletionNotification struct { - //The name of the image that is being deleted + // The name of the image that is being deleted Image string } -//StartReplicationNotification contains data required by this handler +// StartReplicationNotification contains data required by this handler type StartReplicationNotification struct { - //ID of the policy + // ID of the policy PolicyID int64 Metadata map[string]interface{} } diff --git a/src/replication/event/on_deletion_handler.go b/src/replication/event/on_deletion_handler.go index bb7308040..72f95cb0f 100644 --- a/src/replication/event/on_deletion_handler.go +++ b/src/replication/event/on_deletion_handler.go @@ -23,10 +23,10 @@ import ( "github.com/goharbor/harbor/src/replication/event/notification" ) -//OnDeletionHandler implements the notification handler interface to handle image on push event. +// OnDeletionHandler implements the notification handler interface to handle image on push event. type OnDeletionHandler struct{} -//Handle implements the same method of notification handler interface +// Handle implements the same method of notification handler interface func (oph *OnDeletionHandler) Handle(value interface{}) error { if value == nil { return errors.New("OnDeletionHandler can not handle nil value") @@ -41,8 +41,8 @@ func (oph *OnDeletionHandler) Handle(value interface{}) error { return checkAndTriggerReplication(notification.Image, models.RepOpDelete) } -//IsStateful implements the same method of notification handler interface +// IsStateful implements the same method of notification handler interface func (oph *OnDeletionHandler) IsStateful() bool { - //Statless + // Statless return false } diff --git a/src/replication/event/on_push_handler.go b/src/replication/event/on_push_handler.go index b190ad924..a2b376443 100644 --- a/src/replication/event/on_push_handler.go +++ b/src/replication/event/on_push_handler.go @@ -30,10 +30,10 @@ import ( "github.com/goharbor/harbor/src/replication/trigger" ) -//OnPushHandler implements the notification handler interface to handle image on push event. +// OnPushHandler implements the notification handler interface to handle image on push event. type OnPushHandler struct{} -//Handle implements the same method of notification handler interface +// Handle implements the same method of notification handler interface func (oph *OnPushHandler) Handle(value interface{}) error { if value == nil { return errors.New("OnPushHandler can not handle nil value") @@ -49,9 +49,9 @@ func (oph *OnPushHandler) Handle(value interface{}) error { return checkAndTriggerReplication(notification.Image, common_models.RepOpTransfer) } -//IsStateful implements the same method of notification handler interface +// IsStateful implements the same method of notification handler interface func (oph *OnPushHandler) IsStateful() bool { - //Statless + // Statless return false } diff --git a/src/replication/event/start_replication_handler.go b/src/replication/event/start_replication_handler.go index e4ef14d3c..baad229ae 100644 --- a/src/replication/event/start_replication_handler.go +++ b/src/replication/event/start_replication_handler.go @@ -23,10 +23,10 @@ import ( "github.com/goharbor/harbor/src/replication/event/notification" ) -//StartReplicationHandler implements the notification handler interface to handle start replication requests. +// StartReplicationHandler implements the notification handler interface to handle start replication requests. type StartReplicationHandler struct{} -//Handle implements the same method of notification handler interface +// Handle implements the same method of notification handler interface func (srh *StartReplicationHandler) Handle(value interface{}) error { if value == nil { return errors.New("StartReplicationHandler can not handle nil value") @@ -42,12 +42,12 @@ func (srh *StartReplicationHandler) Handle(value interface{}) error { return errors.New("Invalid policy") } - //Start replication + // Start replication return core.GlobalController.Replicate(notification.PolicyID, notification.Metadata) } -//IsStateful implements the same method of notification handler interface +// IsStateful implements the same method of notification handler interface func (srh *StartReplicationHandler) IsStateful() bool { - //Stateless + // Stateless return false } diff --git a/src/replication/event/topic/topics.go b/src/replication/event/topic/topics.go index fce3b9c81..71bcf95cb 100644 --- a/src/replication/event/topic/topics.go +++ b/src/replication/event/topic/topics.go @@ -1,12 +1,12 @@ package topic const ( - //ReplicationEventTopicOnPush : OnPush event + // ReplicationEventTopicOnPush : OnPush event ReplicationEventTopicOnPush = "OnPush" - //ReplicationEventTopicOnDeletion : OnDeletion event + // ReplicationEventTopicOnDeletion : OnDeletion event ReplicationEventTopicOnDeletion = "OnDeletion" - //StartReplicationTopic : Start application request + // StartReplicationTopic : Start application request StartReplicationTopic = "StartReplication" ) diff --git a/src/replication/models/filter_config.go b/src/replication/models/filter_config.go index 149780eaa..33e450d9a 100644 --- a/src/replication/models/filter_config.go +++ b/src/replication/models/filter_config.go @@ -1,7 +1,7 @@ package models -//FilterConfig is data model to provide configurations to the filters. +// FilterConfig is data model to provide configurations to the filters. type FilterConfig struct { - //The pattern for fuzzy matching + // The pattern for fuzzy matching Pattern string } diff --git a/src/replication/models/filter_item.go b/src/replication/models/filter_item.go index 82497dd90..d045d4600 100644 --- a/src/replication/models/filter_item.go +++ b/src/replication/models/filter_item.go @@ -14,22 +14,22 @@ package models -//FilterItem is the general data model represents the filtering resources which are used as input and output for the filters. +// FilterItem is the general data model represents the filtering resources which are used as input and output for the filters. type FilterItem struct { - //The kind of the filtering resources. Support 'project','repository' and 'tag' etc. + // The kind of the filtering resources. Support 'project','repository' and 'tag' etc. Kind string `json:"kind"` - //The key value of resource which can be used to filter out the resource matched with specified pattern. - //E.g: - //kind == 'project', value will be project name; - //kind == 'repository', value will be repository name - //kind == 'tag', value will be tag name. + // The key value of resource which can be used to filter out the resource matched with specified pattern. + // E.g: + // kind == 'project', value will be project name; + // kind == 'repository', value will be repository name + // kind == 'tag', value will be tag name. Value string `json:"value"` Operation string `json:"operation"` - //Extension placeholder. - //To append more additional information if required by the filter. + // Extension placeholder. + // To append more additional information if required by the filter. Metadata map[string]interface{} `json:"metadata"` } diff --git a/src/replication/models/policy.go b/src/replication/models/policy.go index 022d84a14..ae4fa5dc7 100644 --- a/src/replication/models/policy.go +++ b/src/replication/models/policy.go @@ -4,33 +4,33 @@ import ( "time" ) -//ReplicationPolicy defines the structure of a replication policy. +// ReplicationPolicy defines the structure of a replication policy. type ReplicationPolicy struct { - ID int64 //UUID of the policy + ID int64 // UUID of the policy Name string Description string Filters []Filter ReplicateDeletion bool - Trigger *Trigger //The trigger of the replication - ProjectIDs []int64 //Projects attached to this policy + Trigger *Trigger // The trigger of the replication + ProjectIDs []int64 // Projects attached to this policy TargetIDs []int64 Namespaces []string // The namespaces are used to set immediate trigger CreationTime time.Time UpdateTime time.Time } -//QueryParameter defines the parameters used to do query selection. +// QueryParameter defines the parameters used to do query selection. type QueryParameter struct { - //Query by page, couple with pageSize + // Query by page, couple with pageSize Page int64 - //Size of each page, couple with page + // Size of each page, couple with page PageSize int64 - //Query by project ID + // Query by project ID ProjectID int64 - //Query by name + // Query by name Name string } diff --git a/src/replication/models/registry_models.go b/src/replication/models/registry_models.go index 69be2268c..6fa28c15b 100644 --- a/src/replication/models/registry_models.go +++ b/src/replication/models/registry_models.go @@ -1,34 +1,34 @@ package models -//Namespace is the resource group/scope like project in Harbor and organization in docker hub. +// Namespace is the resource group/scope like project in Harbor and organization in docker hub. type Namespace struct { - //Name of the namespace + // Name of the namespace Name string - //Extensions to provide flexibility + // Extensions to provide flexibility Metadata map[string]interface{} } -//Repository is to keep the info of image repository. +// Repository is to keep the info of image repository. type Repository struct { - //Name of the repository + // Name of the repository Name string - //Project reference of this repository belongs to + // Project reference of this repository belongs to Namespace Namespace - //Extensions to provide flexibility + // Extensions to provide flexibility Metadata map[string]interface{} } -//Tag keeps the info of image with specified version +// Tag keeps the info of image with specified version type Tag struct { - //Name of the tag + // Name of the tag Name string - //The repository reference of this tag belongs to + // The repository reference of this tag belongs to Repository Repository - //Extensions to provide flexibility + // Extensions to provide flexibility Metadata map[string]interface{} } diff --git a/src/replication/models/trigger.go b/src/replication/models/trigger.go index 3600e95c9..38a982d67 100644 --- a/src/replication/models/trigger.go +++ b/src/replication/models/trigger.go @@ -21,7 +21,7 @@ import ( "github.com/goharbor/harbor/src/replication" ) -//Trigger is replication launching approach definition +// Trigger is replication launching approach definition type Trigger struct { Kind string `json:"kind"` // the type of the trigger ScheduleParam *ScheduleParam `json:"schedule_param"` // optional, only used when kind is 'schedule' @@ -46,9 +46,9 @@ func (t *Trigger) Valid(v *validation.Validation) { // ScheduleParam defines the parameters used by schedule trigger type ScheduleParam struct { - Type string `json:"type"` //daily or weekly - Weekday int8 `json:"weekday"` //Optional, only used when type is 'weekly' - Offtime int64 `json:"offtime"` //The time offset with the UTC 00:00 in seconds + Type string `json:"type"` // daily or weekly + Weekday int8 `json:"weekday"` // Optional, only used when type is 'weekly' + Offtime int64 `json:"offtime"` // The time offset with the UTC 00:00 in seconds } // Valid ... diff --git a/src/replication/policy/manager.go b/src/replication/policy/manager.go index f0f7b9886..2c179f1be 100644 --- a/src/replication/policy/manager.go +++ b/src/replication/policy/manager.go @@ -34,15 +34,15 @@ type Manager interface { RemovePolicy(int64) error } -//DefaultManager provides replication policy CURD capabilities. +// DefaultManager provides replication policy CURD capabilities. type DefaultManager struct{} -//NewDefaultManager is the constructor of DefaultManager. +// NewDefaultManager is the constructor of DefaultManager. func NewDefaultManager() *DefaultManager { return &DefaultManager{} } -//GetPolicies returns all the policies +// GetPolicies returns all the policies func (m *DefaultManager) GetPolicies(query models.QueryParameter) (*models.ReplicationPolicyQueryResult, error) { result := &models.ReplicationPolicyQueryResult{ Policies: []*models.ReplicationPolicy{}, @@ -70,7 +70,7 @@ func (m *DefaultManager) GetPolicies(query models.QueryParameter) (*models.Repli return result, nil } -//GetPolicy returns the policy with the specified ID +// GetPolicy returns the policy with the specified ID func (m *DefaultManager) GetPolicy(policyID int64) (models.ReplicationPolicy, error) { policy, err := dao.GetRepPolicy(policyID) if err != nil { @@ -168,9 +168,9 @@ func convertToPersistModel(policy models.ReplicationPolicy) (*persist_models.Rep return ply, nil } -//CreatePolicy creates a new policy with the provided data; -//If creating failed, error will be returned; -//If creating succeed, ID of the new created policy will be returned. +// CreatePolicy creates a new policy with the provided data; +// If creating failed, error will be returned; +// If creating succeed, ID of the new created policy will be returned. func (m *DefaultManager) CreatePolicy(policy models.ReplicationPolicy) (int64, error) { now := time.Now() policy.CreationTime = now @@ -182,8 +182,8 @@ func (m *DefaultManager) CreatePolicy(policy models.ReplicationPolicy) (int64, e return dao.AddRepPolicy(*ply) } -//UpdatePolicy updates the policy; -//If updating failed, error will be returned. +// UpdatePolicy updates the policy; +// If updating failed, error will be returned. func (m *DefaultManager) UpdatePolicy(policy models.ReplicationPolicy) error { policy.UpdateTime = time.Now() ply, err := convertToPersistModel(policy) @@ -193,8 +193,8 @@ func (m *DefaultManager) UpdatePolicy(policy models.ReplicationPolicy) error { return dao.UpdateRepPolicy(ply) } -//RemovePolicy removes the specified policy; -//If removing failed, error will be returned. +// RemovePolicy removes the specified policy; +// If removing failed, error will be returned. func (m *DefaultManager) RemovePolicy(policyID int64) error { return dao.DeleteRepPolicy(policyID) } diff --git a/src/replication/registry/adaptor.go b/src/replication/registry/adaptor.go index f7ccbe0c1..fc011edca 100644 --- a/src/replication/registry/adaptor.go +++ b/src/replication/registry/adaptor.go @@ -4,31 +4,31 @@ import ( "github.com/goharbor/harbor/src/replication/models" ) -//Adaptor defines the unified operations for all the supported registries such as Harbor or DockerHub. -//It's used to adapt the different interfaces provied by the different registry providers. -//Use external registry with restful api providing as example, these intrefaces may depends on the -//related restful apis like: +// Adaptor defines the unified operations for all the supported registries such as Harbor or DockerHub. +// It's used to adapt the different interfaces provied by the different registry providers. +// Use external registry with restful api providing as example, these intrefaces may depends on the +// related restful apis like: // /api/vx/repositories/{namespace}/{repositoryName}/tags/{name} // /api/v0/accounts/{namespace} type Adaptor interface { - //Return the unique kind identifier of the adaptor + // Return the unique kind identifier of the adaptor Kind() string - //Get all the namespaces + // Get all the namespaces GetNamespaces() []models.Namespace - //Get the namespace with the specified name + // Get the namespace with the specified name GetNamespace(name string) models.Namespace - //Get all the repositories under the specified namespace + // Get all the repositories under the specified namespace GetRepositories(namespace string) []models.Repository - //Get the repository with the specified name under the specified namespace + // Get the repository with the specified name under the specified namespace GetRepository(name string, namespace string) models.Repository - //Get all the tags of the specified repository under the namespace + // Get all the tags of the specified repository under the namespace GetTags(repositoryName string, namespace string) []models.Tag - //Get the tag with the specified name of the repository under the namespace + // Get the tag with the specified name of the repository under the namespace GetTag(name string, repositoryName string, namespace string) models.Tag } diff --git a/src/replication/registry/harbor_adaptor.go b/src/replication/registry/harbor_adaptor.go index 626f93005..d0406497c 100644 --- a/src/replication/registry/harbor_adaptor.go +++ b/src/replication/registry/harbor_adaptor.go @@ -11,25 +11,25 @@ import ( // TODO refacotor the methods of HarborAdaptor by caling Harbor's API -//HarborAdaptor is defined to adapt the Harbor registry +// HarborAdaptor is defined to adapt the Harbor registry type HarborAdaptor struct{} -//Kind returns the unique kind identifier of the adaptor +// Kind returns the unique kind identifier of the adaptor func (ha *HarborAdaptor) Kind() string { return replication.AdaptorKindHarbor } -//GetNamespaces is ued to get all the namespaces +// GetNamespaces is ued to get all the namespaces func (ha *HarborAdaptor) GetNamespaces() []models.Namespace { return nil } -//GetNamespace is used to get the namespace with the specified name +// GetNamespace is used to get the namespace with the specified name func (ha *HarborAdaptor) GetNamespace(name string) models.Namespace { return models.Namespace{} } -//GetRepositories is used to get all the repositories under the specified namespace +// GetRepositories is used to get all the repositories under the specified namespace func (ha *HarborAdaptor) GetRepositories(namespace string) []models.Repository { repos, err := dao.GetRepositories(&common_models.RepositoryQuery{ ProjectName: namespace, @@ -48,12 +48,12 @@ func (ha *HarborAdaptor) GetRepositories(namespace string) []models.Repository { return repositories } -//GetRepository is used to get the repository with the specified name under the specified namespace +// GetRepository is used to get the repository with the specified name under the specified namespace func (ha *HarborAdaptor) GetRepository(name string, namespace string) models.Repository { return models.Repository{} } -//GetTags is used to get all the tags of the specified repository under the namespace +// GetTags is used to get all the tags of the specified repository under the namespace func (ha *HarborAdaptor) GetTags(repositoryName string, namespace string) []models.Tag { client, err := utils.NewRepositoryClientForUI("harbor-ui", repositoryName) if err != nil { @@ -77,7 +77,7 @@ func (ha *HarborAdaptor) GetTags(repositoryName string, namespace string) []mode return tags } -//GetTag is used to get the tag with the specified name of the repository under the namespace +// GetTag is used to get the tag with the specified name of the repository under the namespace func (ha *HarborAdaptor) GetTag(name string, repositoryName string, namespace string) models.Tag { return models.Tag{} } diff --git a/src/replication/replicator/replicator.go b/src/replication/replicator/replicator.go index 59ae27e94..754487e35 100644 --- a/src/replication/replicator/replicator.go +++ b/src/replication/replicator/replicator.go @@ -99,7 +99,7 @@ func (d *DefaultReplicator) Replicate(replication *Replication) error { "tags": tags, "src_registry_url": url, "src_registry_insecure": true, - //"src_token_service_url":"", + // "src_token_service_url":"", "dst_registry_url": target.URL, "dst_registry_insecure": target.Insecure, "dst_registry_username": target.Username, diff --git a/src/replication/source/convertor.go b/src/replication/source/convertor.go index dbe2d712c..1cf6bbee5 100644 --- a/src/replication/source/convertor.go +++ b/src/replication/source/convertor.go @@ -4,13 +4,13 @@ import ( "github.com/goharbor/harbor/src/replication/models" ) -//Convertor is designed to covert the format of output from upstream filter to the input format -//required by the downstream filter if needed. -//Each convertor covers only one specified conversion process between the two filters. -//E.g: -//If project filter connects to repository filter, then one convertor should be defined for this connection; -//If project filter connects to tag filter, then another one should be defined. The above one can not be reused. +// Convertor is designed to covert the format of output from upstream filter to the input format +// required by the downstream filter if needed. +// Each convertor covers only one specified conversion process between the two filters. +// E.g: +// If project filter connects to repository filter, then one convertor should be defined for this connection; +// If project filter connects to tag filter, then another one should be defined. The above one can not be reused. type Convertor interface { - //Accept the items from upstream filter as input and then covert them to the required format and returned. + // Accept the items from upstream filter as input and then covert them to the required format and returned. Convert(itemsOfUpstream []models.FilterItem) (itemsOfDownstream []models.FilterItem) } diff --git a/src/replication/source/filter.go b/src/replication/source/filter.go index 054855c01..535af350f 100644 --- a/src/replication/source/filter.go +++ b/src/replication/source/filter.go @@ -4,15 +4,15 @@ import ( "github.com/goharbor/harbor/src/replication/models" ) -//Filter define the operations of selecting the matched resources from the candidates -//according to the specified pattern. +// Filter define the operations of selecting the matched resources from the candidates +// according to the specified pattern. type Filter interface { - //Initialize the filter + // Initialize the filter Init() error - //Return the convertor if existing or nil if never set + // Return the convertor if existing or nil if never set GetConvertor() Convertor - //Filter the items + // Filter the items DoFilter(filterItems []models.FilterItem) []models.FilterItem } diff --git a/src/replication/source/filter_chain.go b/src/replication/source/filter_chain.go index 195ba4e04..1e27f9fed 100644 --- a/src/replication/source/filter_chain.go +++ b/src/replication/source/filter_chain.go @@ -4,18 +4,18 @@ import ( "github.com/goharbor/harbor/src/replication/models" ) -//FilterChain is the interface to define the operations of coordinating multiple filters -//to work together as a whole pipeline. -//E.g: -//(original resources)---->[project filter]---->[repository filter]---->[tag filter]---->[......]---->(filter resources) +// FilterChain is the interface to define the operations of coordinating multiple filters +// to work together as a whole pipeline. +// E.g: +// (original resources)---->[project filter]---->[repository filter]---->[tag filter]---->[......]---->(filter resources) type FilterChain interface { - //Build the filter chain with the filters provided; - //if failed, an error will be returned. + // Build the filter chain with the filters provided; + // if failed, an error will be returned. Build(filter []Filter) error - //Return all the filters in the chain. + // Return all the filters in the chain. Filters() []Filter - //Filter the items and returned the filtered items via the appended filters in the chain. + // Filter the items and returned the filtered items via the appended filters in the chain. DoFilter(filterItems []models.FilterItem) []models.FilterItem } diff --git a/src/replication/source/sourcer.go b/src/replication/source/sourcer.go index a8f548ed1..622713303 100644 --- a/src/replication/source/sourcer.go +++ b/src/replication/source/sourcer.go @@ -5,28 +5,28 @@ import ( "github.com/goharbor/harbor/src/replication/registry" ) -//Sourcer is used to manage and/or handle all the artifacts and information related with source registry. -//All the things with replication source should be covered in this object. +// Sourcer is used to manage and/or handle all the artifacts and information related with source registry. +// All the things with replication source should be covered in this object. type Sourcer struct { - //Keep the adaptors we support now + // Keep the adaptors we support now adaptors map[string]registry.Adaptor } -//NewSourcer is the constructor of Sourcer +// NewSourcer is the constructor of Sourcer func NewSourcer() *Sourcer { return &Sourcer{ adaptors: make(map[string]registry.Adaptor), } } -//Init will do some initialization work like registrying all the adaptors we support +// Init will do some initialization work like registrying all the adaptors we support func (sc *Sourcer) Init() { - //Register Harbor adaptor + // Register Harbor adaptor sc.adaptors[replication.AdaptorKindHarbor] = ®istry.HarborAdaptor{} } -//GetAdaptor returns the required adaptor with the specified kind. -//If no adaptor with the specified kind existing, nil will be returned. +// GetAdaptor returns the required adaptor with the specified kind. +// If no adaptor with the specified kind existing, nil will be returned. func (sc *Sourcer) GetAdaptor(kind string) registry.Adaptor { if len(kind) == 0 { return nil diff --git a/src/replication/source/tag_convertor.go b/src/replication/source/tag_convertor.go index 8070d164e..d8ef2941f 100644 --- a/src/replication/source/tag_convertor.go +++ b/src/replication/source/tag_convertor.go @@ -32,7 +32,7 @@ func NewTagConvertor(registry registry.Adaptor) *TagConvertor { } } -//Convert repositories to tags +// Convert repositories to tags func (t *TagConvertor) Convert(items []models.FilterItem) []models.FilterItem { result := []models.FilterItem{} for _, item := range items { diff --git a/src/replication/trigger/cache.go b/src/replication/trigger/cache.go index ea694f3eb..979cee14e 100644 --- a/src/replication/trigger/cache.go +++ b/src/replication/trigger/cache.go @@ -8,50 +8,50 @@ import ( ) const ( - //The max count of items the cache can keep + // The max count of items the cache can keep defaultCapacity = 1000 ) -//Item keeps more metadata of the triggers which are stored in the heap. +// Item keeps more metadata of the triggers which are stored in the heap. type Item struct { - //Which policy the trigger belong to + // Which policy the trigger belong to policyID int64 - //Frequency of cache querying - //First compration factor + // Frequency of cache querying + // First compration factor frequency int - //The timestamp of being put into heap - //Second compration factor + // The timestamp of being put into heap + // Second compration factor timestamp int64 - //The index in the heap + // The index in the heap index int } -//MetaQueue implements heap.Interface and holds items which are metadata of trigger +// MetaQueue implements heap.Interface and holds items which are metadata of trigger type MetaQueue []*Item -//Len return the size of the queue +// Len return the size of the queue func (mq MetaQueue) Len() int { return len(mq) } -//Less is a comparator of heap +// Less is a comparator of heap func (mq MetaQueue) Less(i, j int) bool { return mq[i].frequency < mq[j].frequency || (mq[i].frequency == mq[j].frequency && mq[i].timestamp < mq[j].timestamp) } -//Swap the items to rebuild heap +// Swap the items to rebuild heap func (mq MetaQueue) Swap(i, j int) { mq[i], mq[j] = mq[j], mq[i] mq[i].index = i mq[j].index = j } -//Push item into heap +// Push item into heap func (mq *MetaQueue) Push(x interface{}) { item := x.(*Item) n := len(*mq) @@ -60,58 +60,58 @@ func (mq *MetaQueue) Push(x interface{}) { *mq = append(*mq, item) } -//Pop smallest item from heap +// Pop smallest item from heap func (mq *MetaQueue) Pop() interface{} { old := *mq n := len(old) - item := old[n-1] //Smallest item - item.index = -1 //For safety + item := old[n-1] // Smallest item + item.index = -1 // For safety *mq = old[:n-1] return item } -//Update the frequency of item +// Update the frequency of item func (mq *MetaQueue) Update(item *Item) { item.frequency++ heap.Fix(mq, item.index) } -//CacheItem is the data stored in the cache. -//It contains trigger and heap item references. +// CacheItem is the data stored in the cache. +// It contains trigger and heap item references. type CacheItem struct { - //The trigger reference + // The trigger reference trigger Interface - //The heap item reference + // The heap item reference item *Item } -//Cache is used to cache the enabled triggers with specified capacity. -//If exceed the capacity, cached items will be adjusted with the following rules: +// Cache is used to cache the enabled triggers with specified capacity. +// If exceed the capacity, cached items will be adjusted with the following rules: // The item with least usage frequency will be replaced; // If multiple items with same usage frequency, the oldest one will be replaced. type Cache struct { - //The max count of items this cache can keep + // The max count of items this cache can keep capacity int - //Lock to handle concurrent case + // Lock to handle concurrent case lock *sync.RWMutex - //Hash map for quick locating cached item + // Hash map for quick locating cached item hash map[string]CacheItem - //Heap for quick locating the trigger with least usage + // Heap for quick locating the trigger with least usage queue *MetaQueue } -//NewCache is constructor of cache +// NewCache is constructor of cache func NewCache(capacity int) *Cache { cap := capacity if cap <= 0 { cap = defaultCapacity } - //Initialize heap + // Initialize heap mq := make(MetaQueue, 0) heap.Init(&mq) @@ -123,7 +123,7 @@ func NewCache(capacity int) *Cache { } } -//Get the trigger interface with the specified policy ID +// Get the trigger interface with the specified policy ID func (c *Cache) Get(policyID int64) Interface { if policyID <= 0 { return nil @@ -135,7 +135,7 @@ func (c *Cache) Get(policyID int64) Interface { k := c.key(policyID) if cacheItem, ok := c.hash[k]; ok { - //Update frequency + // Update frequency c.queue.Update(cacheItem.item) return cacheItem.trigger } @@ -143,7 +143,7 @@ func (c *Cache) Get(policyID int64) Interface { return nil } -//Put the item into cache with ID of ploicy as key +// Put the item into cache with ID of ploicy as key func (c *Cache) Put(policyID int64, trigger Interface) { if policyID <= 0 || trigger == nil { return @@ -152,23 +152,23 @@ func (c *Cache) Put(policyID int64, trigger Interface) { c.lock.Lock() defer c.lock.Unlock() - //Exceed the capacity? + // Exceed the capacity? if c.Size() >= c.capacity { - //Pop one for the new one + // Pop one for the new one v := heap.Pop(c.queue) item := v.(*Item) - //Remove from hash + // Remove from hash delete(c.hash, c.key(item.policyID)) } - //Add to meta queue + // Add to meta queue item := &Item{ policyID: policyID, frequency: 1, } heap.Push(c.queue, item) - //Cache + // Cache cacheItem := CacheItem{ trigger: trigger, item: item, @@ -178,19 +178,19 @@ func (c *Cache) Put(policyID int64, trigger Interface) { c.hash[k] = cacheItem } -//Remove the trigger attached to the specified policy +// Remove the trigger attached to the specified policy func (c *Cache) Remove(policyID int64) Interface { if policyID > 0 { c.lock.Lock() defer c.lock.Unlock() - //If existing + // If existing k := c.key(policyID) if cacheItem, ok := c.hash[k]; ok { - //Remove from heap + // Remove from heap heap.Remove(c.queue, cacheItem.item.index) - //Remove from hash + // Remove from hash delete(c.hash, k) return cacheItem.trigger @@ -201,12 +201,12 @@ func (c *Cache) Remove(policyID int64) Interface { return nil } -//Size return the count of triggers in the cache +// Size return the count of triggers in the cache func (c *Cache) Size() int { return len(c.hash) } -//Generate a hash key with the policy ID +// Generate a hash key with the policy ID func (c *Cache) key(policyID int64) string { return fmt.Sprintf("trigger-%d", policyID) } diff --git a/src/replication/trigger/immediate.go b/src/replication/trigger/immediate.go index c35eeaa4f..e373ecb2d 100644 --- a/src/replication/trigger/immediate.go +++ b/src/replication/trigger/immediate.go @@ -4,27 +4,27 @@ import ( "github.com/goharbor/harbor/src/replication" ) -//ImmediateTrigger will setup watcher at the image pushing action to fire -//replication event at pushing happening time. +// ImmediateTrigger will setup watcher at the image pushing action to fire +// replication event at pushing happening time. type ImmediateTrigger struct { params ImmediateParam } -//NewImmediateTrigger is constructor of ImmediateTrigger +// NewImmediateTrigger is constructor of ImmediateTrigger func NewImmediateTrigger(params ImmediateParam) *ImmediateTrigger { return &ImmediateTrigger{ params: params, } } -//Kind is the implementation of same method defined in Trigger interface +// Kind is the implementation of same method defined in Trigger interface func (st *ImmediateTrigger) Kind() string { return replication.TriggerKindImmediate } -//Setup is the implementation of same method defined in Trigger interface +// Setup is the implementation of same method defined in Trigger interface func (st *ImmediateTrigger) Setup() error { - //TODO: Need more complicated logic here to handle partial updates + // TODO: Need more complicated logic here to handle partial updates for _, namespace := range st.params.Namespaces { wt := WatchItem{ PolicyID: st.params.PolicyID, @@ -40,7 +40,7 @@ func (st *ImmediateTrigger) Setup() error { return nil } -//Unset is the implementation of same method defined in Trigger interface +// Unset is the implementation of same method defined in Trigger interface func (st *ImmediateTrigger) Unset() error { return DefaultWatchList.Remove(st.params.PolicyID) } diff --git a/src/replication/trigger/interface.go b/src/replication/trigger/interface.go index 38f1f317c..34929ee6b 100644 --- a/src/replication/trigger/interface.go +++ b/src/replication/trigger/interface.go @@ -1,13 +1,13 @@ package trigger -//Interface is certain mechanism to know when fire the replication operation. +// Interface is certain mechanism to know when fire the replication operation. type Interface interface { - //Kind indicates what type of the trigger is. + // Kind indicates what type of the trigger is. Kind() string - //Setup/enable the trigger; if failed, an error would be returned. + // Setup/enable the trigger; if failed, an error would be returned. Setup() error - //Remove/disable the trigger; if failed, an error would be returned. + // Remove/disable the trigger; if failed, an error would be returned. Unset() error } diff --git a/src/replication/trigger/manager.go b/src/replication/trigger/manager.go index 65cbb5d7e..40bed8491 100644 --- a/src/replication/trigger/manager.go +++ b/src/replication/trigger/manager.go @@ -8,51 +8,51 @@ import ( "github.com/goharbor/harbor/src/replication/models" ) -//Manager provides unified methods to manage the triggers of policies; -//Cache the enabled triggers, setup/unset the trigger based on the parameters -//with json format. +// Manager provides unified methods to manage the triggers of policies; +// Cache the enabled triggers, setup/unset the trigger based on the parameters +// with json format. type Manager struct { - //Cache for triggers - //cache *Cache + // Cache for triggers + // cache *Cache } -//NewManager is the constructor of trigger manager. -//capacity is the max number of trigger references manager can keep in memory +// NewManager is the constructor of trigger manager. +// capacity is the max number of trigger references manager can keep in memory func NewManager(capacity int) *Manager { return &Manager{ - //cache: NewCache(capacity), + // cache: NewCache(capacity), } } /* -//GetTrigger returns the enabled trigger reference if existing in the cache. +// GetTrigger returns the enabled trigger reference if existing in the cache. func (m *Manager) GetTrigger(policyID int64) Interface { return m.cache.Get(policyID) } -//RemoveTrigger will disable the trigger and remove it from the cache if existing. +// RemoveTrigger will disable the trigger and remove it from the cache if existing. func (m *Manager) RemoveTrigger(policyID int64) error { trigger := m.cache.Get(policyID) if trigger == nil { return errors.New("Trigger is not cached, please use UnsetTrigger to disable the trigger") } - //Unset trigger + // Unset trigger if err := trigger.Unset(); err != nil { return err } - //Remove from cache - //No need to check the return of remove because the dirty item cached in the cache - //will be removed out finally after a certain while + // Remove from cache + // No need to check the return of remove because the dirty item cached in the cache + // will be removed out finally after a certain while m.cache.Remove(policyID) return nil } */ -//SetupTrigger will create the new trigger based on the provided policy. -//If failed, an error will be returned. +// SetupTrigger will create the new trigger based on the provided policy. +// If failed, an error will be returned. func (m *Manager) SetupTrigger(policy *models.ReplicationPolicy) error { trigger, err := createTrigger(policy) if err != nil { @@ -73,7 +73,7 @@ func (m *Manager) SetupTrigger(policy *models.ReplicationPolicy) error { return nil } -//UnsetTrigger will disable the trigger which is not cached in the trigger cache. +// UnsetTrigger will disable the trigger which is not cached in the trigger cache. func (m *Manager) UnsetTrigger(policy *models.ReplicationPolicy) error { trigger, err := createTrigger(policy) if err != nil { diff --git a/src/replication/trigger/param_immediate.go b/src/replication/trigger/param_immediate.go index bb9b248a5..dde053412 100644 --- a/src/replication/trigger/param_immediate.go +++ b/src/replication/trigger/param_immediate.go @@ -1,22 +1,22 @@ package trigger -//NOTES: Whether replicate the existing images when the type of trigger is -//'Immediate' is a once-effective setting which will not be persisted +// NOTES: Whether replicate the existing images when the type of trigger is +// 'Immediate' is a once-effective setting which will not be persisted // and kept as one parameter of 'Immediate' trigger. It will only be -//covered by the UI logic. +// covered by the UI logic. -//ImmediateParam defines the parameter of immediate trigger +// ImmediateParam defines the parameter of immediate trigger type ImmediateParam struct { - //Basic parameters + // Basic parameters BasicParam - //Namepaces + // Namepaces Namespaces []string } -//Parse is the implementation of same method in TriggerParam interface -//NOTES: No need to implement this method for 'Immediate' trigger as -//it does not have any parameters with json format. +// Parse is the implementation of same method in TriggerParam interface +// NOTES: No need to implement this method for 'Immediate' trigger as +// it does not have any parameters with json format. func (ip ImmediateParam) Parse(param string) error { return nil } diff --git a/src/replication/trigger/param_schedule.go b/src/replication/trigger/param_schedule.go index 84ca46f44..6af2f94fa 100644 --- a/src/replication/trigger/param_schedule.go +++ b/src/replication/trigger/param_schedule.go @@ -5,22 +5,22 @@ import ( "errors" ) -//ScheduleParam defines the parameter of schedule trigger +// ScheduleParam defines the parameter of schedule trigger type ScheduleParam struct { - //Basic parameters + // Basic parameters BasicParam - //Daily or weekly + // Daily or weekly Type string - //Optional, only used when type is 'weekly' + // Optional, only used when type is 'weekly' Weekday int8 - //The time offset with the UTC 00:00 in seconds + // The time offset with the UTC 00:00 in seconds Offtime int64 } -//Parse is the implementation of same method in TriggerParam interface +// Parse is the implementation of same method in TriggerParam interface func (stp ScheduleParam) Parse(param string) error { if len(param) == 0 { return errors.New("Parameter of schedule trigger should not be empty") diff --git a/src/replication/trigger/schedule.go b/src/replication/trigger/schedule.go index 4238b612d..9d4b08323 100644 --- a/src/replication/trigger/schedule.go +++ b/src/replication/trigger/schedule.go @@ -16,24 +16,24 @@ import ( "github.com/goharbor/harbor/src/ui/utils" ) -//ScheduleTrigger will schedule a alternate policy to provide 'daily' and 'weekly' trigger ways. +// ScheduleTrigger will schedule a alternate policy to provide 'daily' and 'weekly' trigger ways. type ScheduleTrigger struct { params ScheduleParam } -//NewScheduleTrigger is constructor of ScheduleTrigger +// NewScheduleTrigger is constructor of ScheduleTrigger func NewScheduleTrigger(params ScheduleParam) *ScheduleTrigger { return &ScheduleTrigger{ params: params, } } -//Kind is the implementation of same method defined in Trigger interface +// Kind is the implementation of same method defined in Trigger interface func (st *ScheduleTrigger) Kind() string { return replication.TriggerKindSchedule } -//Setup is the implementation of same method defined in Trigger interface +// Setup is the implementation of same method defined in Trigger interface func (st *ScheduleTrigger) Setup() error { metadata := &job_models.JobMetadata{ JobKind: job.JobKindPeriodic, @@ -78,7 +78,7 @@ func (st *ScheduleTrigger) Setup() error { return dao.SetRepJobUUID(id, uuid) } -//Unset is the implementation of same method defined in Trigger interface +// Unset is the implementation of same method defined in Trigger interface func (st *ScheduleTrigger) Unset() error { jobs, err := dao.GetRepJobs(&models.RepJobQuery{ PolicyID: st.params.PolicyID, diff --git a/src/replication/trigger/trigger_param.go b/src/replication/trigger/trigger_param.go index cccf3fca3..92449f032 100644 --- a/src/replication/trigger/trigger_param.go +++ b/src/replication/trigger/trigger_param.go @@ -1,17 +1,17 @@ package trigger -//BasicParam contains the general parameters for all triggers +// BasicParam contains the general parameters for all triggers type BasicParam struct { - //ID of the related policy + // ID of the related policy PolicyID int64 - //Whether delete remote replicated images if local ones are deleted + // Whether delete remote replicated images if local ones are deleted OnDeletion bool } -//Parameter defines operation of doing initialization from parameter json text +// Parameter defines operation of doing initialization from parameter json text type Parameter interface { - //Decode parameter with json style to the owner struct - //If failed, an error will be returned + // Decode parameter with json style to the owner struct + // If failed, an error will be returned Parse(param string) error } diff --git a/src/replication/trigger/watch_list.go b/src/replication/trigger/watch_list.go index 4b8e1931d..5c2dc5248 100644 --- a/src/replication/trigger/watch_list.go +++ b/src/replication/trigger/watch_list.go @@ -5,29 +5,29 @@ import ( "github.com/goharbor/harbor/src/common/models" ) -//DefaultWatchList is the default instance of WatchList +// DefaultWatchList is the default instance of WatchList var DefaultWatchList = &WatchList{} -//WatchList contains the items which should be evaluated for replication -//when image pushing or deleting happens. +// WatchList contains the items which should be evaluated for replication +// when image pushing or deleting happens. type WatchList struct{} -//WatchItem keeps the related data for evaluation in WatchList. +// WatchItem keeps the related data for evaluation in WatchList. type WatchItem struct { - //ID of policy + // ID of policy PolicyID int64 - //Corresponding namespace + // Corresponding namespace Namespace string - //For deletion event + // For deletion event OnDeletion bool - //For pushing event + // For pushing event OnPush bool } -//Add item to the list and persist into DB +// Add item to the list and persist into DB func (wl *WatchList) Add(item WatchItem) error { _, err := dao.DefaultDatabaseWatchItemDAO.Add( &models.WatchItem{ @@ -39,12 +39,12 @@ func (wl *WatchList) Add(item WatchItem) error { return err } -//Remove the specified watch item from list +// Remove the specified watch item from list func (wl *WatchList) Remove(policyID int64) error { return dao.DefaultDatabaseWatchItemDAO.DeleteByPolicyID(policyID) } -//Get the watch items according to the namespace and operation +// Get the watch items according to the namespace and operation func (wl *WatchList) Get(namespace, operation string) ([]WatchItem, error) { items, err := dao.DefaultDatabaseWatchItemDAO.Get(namespace, operation) if err != nil { diff --git a/src/ui/api/base.go b/src/ui/api/base.go index 271348a5f..3e607f3e9 100644 --- a/src/ui/api/base.go +++ b/src/ui/api/base.go @@ -36,9 +36,9 @@ type BaseController struct { } const ( - //ReplicationJobType ... + // ReplicationJobType ... ReplicationJobType = "replication" - //ScanJobType ... + // ScanJobType ... ScanJobType = "scan" ) @@ -60,9 +60,9 @@ func (b *BaseController) Prepare() { b.ProjectMgr = pm } -//Init related objects/configurations for the API controllers +// Init related objects/configurations for the API controllers func Init() error { - //If chart repository is not enabled then directly return + // If chart repository is not enabled then directly return if !config.WithChartMuseum() { return nil } diff --git a/src/ui/api/chart_repository.go b/src/ui/api/chart_repository.go index cbbce2605..b3652293c 100644 --- a/src/ui/api/chart_repository.go +++ b/src/ui/api/chart_repository.go @@ -37,34 +37,34 @@ const ( contentTypeMultipart = "multipart/form-data" ) -//chartController is a singleton instance +// chartController is a singleton instance var chartController *chartserver.Controller -//ChartRepositoryAPI provides related API handlers for the chart repository APIs +// ChartRepositoryAPI provides related API handlers for the chart repository APIs type ChartRepositoryAPI struct { - //The base controller to provide common utilities + // The base controller to provide common utilities BaseController - //Keep the namespace if existing + // Keep the namespace if existing namespace string } -//Prepare something for the following actions +// Prepare something for the following actions func (cra *ChartRepositoryAPI) Prepare() { - //Call super prepare method + // Call super prepare method cra.BaseController.Prepare() - //Try to extract namespace for parameter of path - //It may not exist + // Try to extract namespace for parameter of path + // It may not exist cra.namespace = strings.TrimSpace(cra.GetStringFromPath(namespaceParam)) - //Check the existence of namespace - //Exclude the following URI + // Check the existence of namespace + // Exclude the following URI // -/index.yaml // -/api/chartserver/health incomingURI := cra.Ctx.Request.RequestURI if incomingURI == rootUploadingEndpoint { - //Forward to the default repository + // Forward to the default repository cra.namespace = defaultRepo } @@ -75,13 +75,13 @@ func (cra *ChartRepositoryAPI) Prepare() { } } - //Rewrite URL path + // Rewrite URL path cra.rewriteURLPath(cra.Ctx.Request) } -//GetHealthStatus handles GET /api/chartserver/health +// GetHealthStatus handles GET /api/chartserver/health func (cra *ChartRepositoryAPI) GetHealthStatus() { - //Check access + // Check access if !cra.requireAccess(cra.namespace, accessLevelSystem) { return } @@ -89,9 +89,9 @@ func (cra *ChartRepositoryAPI) GetHealthStatus() { chartController.GetBaseHandler().GetHealthStatus(cra.Ctx.ResponseWriter, cra.Ctx.Request) } -//GetIndexByRepo handles GET /:repo/index.yaml +// GetIndexByRepo handles GET /:repo/index.yaml func (cra *ChartRepositoryAPI) GetIndexByRepo() { - //Check access + // Check access if !cra.requireAccess(cra.namespace, accessLevelRead) { return } @@ -99,9 +99,9 @@ func (cra *ChartRepositoryAPI) GetIndexByRepo() { chartController.GetRepositoryHandler().GetIndexFileWithNS(cra.Ctx.ResponseWriter, cra.Ctx.Request) } -//GetIndex handles GET /index.yaml +// GetIndex handles GET /index.yaml func (cra *ChartRepositoryAPI) GetIndex() { - //Check access + // Check access if !cra.requireAccess(cra.namespace, accessLevelSystem) { return } @@ -109,9 +109,9 @@ func (cra *ChartRepositoryAPI) GetIndex() { chartController.GetRepositoryHandler().GetIndexFile(cra.Ctx.ResponseWriter, cra.Ctx.Request) } -//DownloadChart handles GET /:repo/charts/:filename +// DownloadChart handles GET /:repo/charts/:filename func (cra *ChartRepositoryAPI) DownloadChart() { - //Check access + // Check access if !cra.requireAccess(cra.namespace, accessLevelRead) { return } @@ -119,9 +119,9 @@ func (cra *ChartRepositoryAPI) DownloadChart() { chartController.GetRepositoryHandler().DownloadChartObject(cra.Ctx.ResponseWriter, cra.Ctx.Request) } -//ListCharts handles GET /api/:repo/charts +// ListCharts handles GET /api/:repo/charts func (cra *ChartRepositoryAPI) ListCharts() { - //Check access + // Check access if !cra.requireAccess(cra.namespace, accessLevelRead) { return } @@ -129,9 +129,9 @@ func (cra *ChartRepositoryAPI) ListCharts() { chartController.GetManipulationHandler().ListCharts(cra.Ctx.ResponseWriter, cra.Ctx.Request) } -//ListChartVersions GET /api/:repo/charts/:name +// ListChartVersions GET /api/:repo/charts/:name func (cra *ChartRepositoryAPI) ListChartVersions() { - //Check access + // Check access if !cra.requireAccess(cra.namespace, accessLevelRead) { return } @@ -139,23 +139,23 @@ func (cra *ChartRepositoryAPI) ListChartVersions() { chartController.GetManipulationHandler().GetChart(cra.Ctx.ResponseWriter, cra.Ctx.Request) } -//GetChartVersion handles GET /api/:repo/charts/:name/:version +// GetChartVersion handles GET /api/:repo/charts/:name/:version func (cra *ChartRepositoryAPI) GetChartVersion() { - //Check access + // Check access if !cra.requireAccess(cra.namespace, accessLevelRead) { return } - //Let's pass the namespace via the context of request + // Let's pass the namespace via the context of request req := cra.Ctx.Request *req = *(req.WithContext(context.WithValue(req.Context(), chartserver.NamespaceContextKey, cra.namespace))) chartController.GetManipulationHandler().GetChartVersion(cra.Ctx.ResponseWriter, req) } -//DeleteChartVersion handles DELETE /api/:repo/charts/:name/:version +// DeleteChartVersion handles DELETE /api/:repo/charts/:name/:version func (cra *ChartRepositoryAPI) DeleteChartVersion() { - //Check access + // Check access if !cra.requireAccess(cra.namespace, accessLevelAll) { return } @@ -163,16 +163,16 @@ func (cra *ChartRepositoryAPI) DeleteChartVersion() { chartController.GetManipulationHandler().DeleteChartVersion(cra.Ctx.ResponseWriter, cra.Ctx.Request) } -//UploadChartVersion handles POST /api/:repo/charts +// UploadChartVersion handles POST /api/:repo/charts func (cra *ChartRepositoryAPI) UploadChartVersion() { hlog.Debugf("Header of request of uploading chart: %#v, content-len=%d", cra.Ctx.Request.Header, cra.Ctx.Request.ContentLength) - //Check access + // Check access if !cra.requireAccess(cra.namespace, accessLevelWrite) { return } - //Rewrite file content if the content type is "multipart/form-data" + // Rewrite file content if the content type is "multipart/form-data" if isMultipartFormData(cra.Ctx.Request) { formFiles := make([]formFile, 0) formFiles = append(formFiles, @@ -192,14 +192,14 @@ func (cra *ChartRepositoryAPI) UploadChartVersion() { chartController.GetManipulationHandler().UploadChartVersion(cra.Ctx.ResponseWriter, cra.Ctx.Request) } -//UploadChartProvFile handles POST /api/:repo/prov +// UploadChartProvFile handles POST /api/:repo/prov func (cra *ChartRepositoryAPI) UploadChartProvFile() { - //Check access + // Check access if !cra.requireAccess(cra.namespace, accessLevelWrite) { return } - //Rewrite file content if the content type is "multipart/form-data" + // Rewrite file content if the content type is "multipart/form-data" if isMultipartFormData(cra.Ctx.Request) { formFiles := make([]formFile, 0) formFiles = append(formFiles, @@ -216,14 +216,14 @@ func (cra *ChartRepositoryAPI) UploadChartProvFile() { chartController.GetManipulationHandler().UploadProvenanceFile(cra.Ctx.ResponseWriter, cra.Ctx.Request) } -//DeleteChart deletes all the chart versions of the specified chart. +// DeleteChart deletes all the chart versions of the specified chart. func (cra *ChartRepositoryAPI) DeleteChart() { - //Check access + // Check access if !cra.requireAccess(cra.namespace, accessLevelWrite) { return } - //Get other parameters from the request + // Get other parameters from the request chartName := cra.GetStringFromPath(nameParam) if err := chartController.GetUtilityHandler().DeleteChart(cra.namespace, chartName); err != nil { @@ -231,9 +231,9 @@ func (cra *ChartRepositoryAPI) DeleteChart() { } } -//Rewrite the incoming URL with the right backend URL pattern -//Remove 'chartrepo' from the endpoints of manipulation API -//Remove 'chartrepo' from the endpoints of repository services +// Rewrite the incoming URL with the right backend URL pattern +// Remove 'chartrepo' from the endpoints of manipulation API +// Remove 'chartrepo' from the endpoints of repository services func (cra *ChartRepositoryAPI) rewriteURLPath(req *http.Request) { incomingURLPath := req.RequestURI @@ -241,36 +241,36 @@ func (cra *ChartRepositoryAPI) rewriteURLPath(req *http.Request) { hlog.Debugf("Incoming URL '%s' is rewritten to '%s'", incomingURLPath, req.URL.String()) }() - //Health check endpoint + // Health check endpoint if incomingURLPath == chartRepoHealthEndpoint { req.URL.Path = "/health" return } - //Root uploading endpoint + // Root uploading endpoint if incomingURLPath == rootUploadingEndpoint { req.URL.Path = strings.Replace(incomingURLPath, "chartrepo", defaultRepo, 1) return } - //Repository endpoints + // Repository endpoints if strings.HasPrefix(incomingURLPath, "/chartrepo") { req.URL.Path = strings.TrimPrefix(incomingURLPath, "/chartrepo") return } - //API endpoints + // API endpoints if strings.HasPrefix(incomingURLPath, "/api/chartrepo") { req.URL.Path = strings.Replace(incomingURLPath, "/chartrepo", "", 1) return } } -//Check if there exists a valid namespace -//Return true if it does -//Return false if it does not +// Check if there exists a valid namespace +// Return true if it does +// Return false if it does not func (cra *ChartRepositoryAPI) requireNamespace(namespace string) bool { - //Actually, never should be like this + // Actually, never should be like this if len(namespace) == 0 { cra.HandleBadRequest(":repo should be in the request URL") return false @@ -278,12 +278,12 @@ func (cra *ChartRepositoryAPI) requireNamespace(namespace string) bool { existsing, err := cra.ProjectMgr.Exists(namespace) if err != nil { - //Check failed with error + // Check failed with error cra.renderError(http.StatusInternalServerError, fmt.Sprintf("failed to check existence of namespace %s with error: %s", namespace, err.Error())) return false } - //Not existing + // Not existing if !existsing { cra.renderError(http.StatusBadRequest, fmt.Sprintf("namespace %s is not existing", namespace)) return false @@ -292,16 +292,16 @@ func (cra *ChartRepositoryAPI) requireNamespace(namespace string) bool { return true } -//Check if the related access match the expected requirement -//If with right access, return true -//If without right access, return false +// Check if the related access match the expected requirement +// If with right access, return true +// If without right access, return false func (cra *ChartRepositoryAPI) requireAccess(namespace string, accessLevel uint) bool { if accessLevel == accessLevelPublic { - return true //do nothing + return true // do nothing } theLevel := accessLevel - //If repo is empty, system admin role must be required + // If repo is empty, system admin role must be required if len(namespace) == 0 { theLevel = accessLevelSystem } @@ -309,7 +309,7 @@ func (cra *ChartRepositoryAPI) requireAccess(namespace string, accessLevel uint) var err error switch theLevel { - //Should be system admin role + // Should be system admin role case accessLevelSystem: if !cra.SecurityCtx.IsSysAdmin() { err = errors.New("permission denied: system admin role is required") @@ -327,20 +327,20 @@ func (cra *ChartRepositoryAPI) requireAccess(namespace string, accessLevel uint) err = errors.New("permission denied: guest or higher role is required") } default: - //access rejected for invalid scope + // access rejected for invalid scope cra.renderError(http.StatusForbidden, "unrecognized access scope") return false } - //Access is not granted, check if user has authenticated + // Access is not granted, check if user has authenticated if err != nil { - //Unauthenticated, return 401 + // Unauthenticated, return 401 if !cra.SecurityCtx.IsAuthenticated() { cra.renderError(http.StatusUnauthorized, "Unauthorized") return false } - //Authenticated, return 403 + // Authenticated, return 403 cra.renderError(http.StatusForbidden, err.Error()) return false } @@ -348,50 +348,50 @@ func (cra *ChartRepositoryAPI) requireAccess(namespace string, accessLevel uint) return true } -//write error message with unified format +// write error message with unified format func (cra *ChartRepositoryAPI) renderError(code int, text string) { chartserver.WriteError(cra.Ctx.ResponseWriter, code, errors.New(text)) } -//formFile is used to represent the uploaded files in the form +// formFile is used to represent the uploaded files in the form type formFile struct { - //form field key contains the form file + // form field key contains the form file formField string - //flag to indicate if the file identified by the 'formField' - //must exist + // flag to indicate if the file identified by the 'formField' + // must exist mustHave bool } -//If the files are uploaded with multipart/form-data mimetype, beego will extract the data -//from the request automatically. Then the request passed to the backend server with proxying -//way will have empty content. -//This method will refill the requests with file content. +// If the files are uploaded with multipart/form-data mimetype, beego will extract the data +// from the request automatically. Then the request passed to the backend server with proxying +// way will have empty content. +// This method will refill the requests with file content. func (cra *ChartRepositoryAPI) rewriteFileContent(files []formFile, request *http.Request) error { if len(files) == 0 { - return nil //no files, early return + return nil // no files, early return } var body bytes.Buffer w := multipart.NewWriter(&body) defer func() { if err := w.Close(); err != nil { - //Just log it + // Just log it hlog.Errorf("Failed to defer close multipart writer with error: %s", err.Error()) } }() - //Process files by key one by one + // Process files by key one by one for _, f := range files { mFile, mHeader, err := cra.GetFile(f.formField) - //Handle error case by case + // Handle error case by case if err != nil { formatedErr := fmt.Errorf("Get file content with multipart header from key '%s' failed with error: %s", f.formField, err.Error()) if f.mustHave || err != http.ErrMissingFile { return formatedErr } - //Error can be ignored, just log it + // Error can be ignored, just log it hlog.Warning(formatedErr.Error()) continue } @@ -414,7 +414,7 @@ func (cra *ChartRepositoryAPI) rewriteFileContent(files []formFile, request *htt return nil } -//Initialize the chart service controller +// Initialize the chart service controller func initializeChartController() (*chartserver.Controller, error) { addr, err := config.GetChartMuseumEndpoint() if err != nil { @@ -438,7 +438,7 @@ func initializeChartController() (*chartserver.Controller, error) { return controller, nil } -//Check if the request content type is "multipart/form-data" +// Check if the request content type is "multipart/form-data" func isMultipartFormData(req *http.Request) bool { return strings.Contains(req.Header.Get(headerContentType), contentTypeMultipart) } diff --git a/src/ui/api/chart_repository_test.go b/src/ui/api/chart_repository_test.go index b64aa1760..820c24161 100644 --- a/src/ui/api/chart_repository_test.go +++ b/src/ui/api/chart_repository_test.go @@ -9,7 +9,7 @@ import ( "github.com/goharbor/harbor/src/ui/promgr/metamgr" ) -//Test the URL rewrite function +// Test the URL rewrite function func TestURLRewrite(t *testing.T) { chartAPI := &ChartRepositoryAPI{} req, err := createRequest(http.MethodGet, "/api/chartrepo/health") @@ -49,7 +49,7 @@ func TestURLRewrite(t *testing.T) { } } -//Test access checking +// Test access checking func TestRequireAccess(t *testing.T) { chartAPI := &ChartRepositoryAPI{} chartAPI.SecurityCtx = &mockSecurityContext{} @@ -88,7 +88,7 @@ func TestIsMultipartFormData(t *testing.T) { } } -//Test namespace cheking +// Test namespace cheking func TestRequireNamespace(t *testing.T) { chartAPI := &ChartRepositoryAPI{} chartAPI.ProjectMgr = &mockProjectManager{} @@ -108,7 +108,7 @@ func createRequest(method string, url string) (*http.Request, error) { return req, nil } -//Mock project manager +// Mock project manager type mockProjectManager struct{} func (mpm *mockProjectManager) Get(projectIDOrName interface{}) (*models.Project, error) { @@ -168,7 +168,7 @@ func (mpm *mockProjectManager) GetMetadataManager() metamgr.ProjectMetadataManag return nil } -//mock security context +// mock security context type mockSecurityContext struct{} // IsAuthenticated returns whether the context has been authenticated or not @@ -226,12 +226,12 @@ func (msc *mockSecurityContext) HasAllPerm(projectIDOrName interface{}) bool { return msc.HasReadPerm(projectIDOrName) && msc.HasWritePerm(projectIDOrName) } -//Get current user's all project +// Get current user's all project func (msc *mockSecurityContext) GetMyProjects() ([]*models.Project, error) { return []*models.Project{{ProjectID: 0, Name: "repo1"}}, nil } -//Get user's role in provided project +// Get user's role in provided project func (msc *mockSecurityContext) GetProjectRoles(projectIDOrName interface{}) []int { return []int{0, 1, 2, 3} } diff --git a/src/ui/api/config.go b/src/ui/api/config.go index 1f4654f23..293f5d903 100644 --- a/src/ui/api/config.go +++ b/src/ui/api/config.go @@ -107,7 +107,7 @@ func (c *ConfigAPI) Put() { c.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) } - //Everything is ok, detect the configurations to confirm if the option we are caring is changed. + // Everything is ok, detect the configurations to confirm if the option we are caring is changed. if err := watchConfigChanges(cfg); err != nil { log.Errorf("Failed to watch configuration change with error: %s\n", err) } diff --git a/src/ui/api/config_test.go b/src/ui/api/config_test.go index 695aee20e..4b0a6b551 100644 --- a/src/ui/api/config_test.go +++ b/src/ui/api/config_test.go @@ -28,7 +28,7 @@ func TestGetConfig(t *testing.T) { assert := assert.New(t) apiTest := newHarborAPI() - //case 1: get configurations without admin role + // case 1: get configurations without admin role code, _, err := apiTest.GetConfig(*testUser) if err != nil { t.Fatalf("failed to get configurations: %v", err) @@ -36,7 +36,7 @@ func TestGetConfig(t *testing.T) { assert.Equal(401, code, "the status code of getting configurations with non-admin user should be 401") - //case 2: get configurations with admin role + // case 2: get configurations with admin role code, cfg, err := apiTest.GetConfig(*admin) if err != nil { t.Fatalf("failed to get configurations: %v", err) diff --git a/src/ui/api/dataprepare_test.go b/src/ui/api/dataprepare_test.go index 5a04e8fb8..5cbe68e7d 100644 --- a/src/ui/api/dataprepare_test.go +++ b/src/ui/api/dataprepare_test.go @@ -36,7 +36,7 @@ import ( ) const ( - //Prepare Test info + // Prepare Test info TestUserName = "testUser0001" TestUserPwd = "testUser0001" TestUserEmail = "testUser0001@mydomain.com" diff --git a/src/ui/api/email_test.go b/src/ui/api/email_test.go index 154fb69e2..8460cba06 100644 --- a/src/ui/api/email_test.go +++ b/src/ui/api/email_test.go @@ -26,7 +26,7 @@ func TestPingEmail(t *testing.T) { assert := assert.New(t) apiTest := newHarborAPI() - //case 1: ping email server without admin role + // case 1: ping email server without admin role code, _, err := apiTest.PingEmail(*testUser, nil) if err != nil { t.Errorf("failed to test ping email server: %v", err) @@ -35,7 +35,7 @@ func TestPingEmail(t *testing.T) { assert.Equal(401, code, "the status code of ping email server with non-admin user should be 401") - //case 2: empty email host + // case 2: empty email host settings := `{ "email_host": "" }` @@ -48,7 +48,7 @@ func TestPingEmail(t *testing.T) { assert.Equal(400, code) - //case 3: secure connection with admin role + // case 3: secure connection with admin role settings = `{ "email_host": "smtp.gmail.com", "email_port": 465, @@ -65,7 +65,7 @@ func TestPingEmail(t *testing.T) { assert.Equal(400, code) - //case 4: ping email server whose settings are read from config + // case 4: ping email server whose settings are read from config code, _, err = apiTest.PingEmail(*admin, nil) if err != nil { t.Errorf("failed to test ping email server: %v", err) diff --git a/src/ui/api/harborapi_test.go b/src/ui/api/harborapi_test.go index 3b36a87ab..28747dd05 100644 --- a/src/ui/api/harborapi_test.go +++ b/src/ui/api/harborapi_test.go @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -//These APIs provide services for manipulating Harbor project. +// These APIs provide services for manipulating Harbor project. package api @@ -41,7 +41,7 @@ import ( "github.com/astaxie/beego" "github.com/dghubble/sling" - //for test env prepare + // for test env prepare "github.com/goharbor/harbor/src/replication/core" _ "github.com/goharbor/harbor/src/replication/event" _ "github.com/goharbor/harbor/src/ui/auth/db" @@ -176,17 +176,17 @@ func init() { log.Fatalf("failed to initialize GlobalController: %v", err) } - //syncRegistry + // syncRegistry if err := SyncRegistry(config.GlobalProjectMgr); err != nil { log.Fatalf("failed to sync repositories from registry: %v", err) } - //Init user Info + // Init user Info admin = &usrInfo{adminName, adminPwd} unknownUsr = &usrInfo{"unknown", "unknown"} testUser = &usrInfo{TestUserName, TestUserPwd} - //Init mock jobservice + // Init mock jobservice mockServer := test.NewJobServiceServer() defer mockServer.Close() } @@ -206,13 +206,13 @@ func request(_sling *sling.Sling, acceptHeader string, authInfo ...usrInfo) (int return w.Code, body, err } -//Search for projects and repositories -//Implementation Notes -//The Search endpoint returns information about the projects and repositories -//offered at public status or related to the current logged in user. -//The response includes the project and repository list in a proper display order. -//@param q Search parameter for project and repository name. -//@return []Search +// Search for projects and repositories +// Implementation Notes +// The Search endpoint returns information about the projects and repositories +// offered at public status or related to the current logged in user. +// The response includes the project and repository list in a proper display order. +// @param q Search parameter for project and repository name. +// @return []Search func (a testapi) SearchGet(q string, authInfo ...usrInfo) (int, apilib.Search, error) { var httpCode int var body []byte @@ -241,12 +241,12 @@ func (a testapi) SearchGet(q string, authInfo ...usrInfo) (int, apilib.Search, e return httpCode, *successPayload, err } -//Create a new project. -//Implementation Notes -//This endpoint is for user to create a new project. -//@param project New created project. -//@return void -//func (a testapi) ProjectsPost (prjUsr usrInfo, project apilib.Project) (int, error) { +// Create a new project. +// Implementation Notes +// This endpoint is for user to create a new project. +// @param project New created project. +// @return void +// func (a testapi) ProjectsPost (prjUsr usrInfo, project apilib.Project) (int, error) { func (a testapi) ProjectsPost(prjUsr usrInfo, project apilib.ProjectReq) (int, error) { _sling := sling.New().Post(a.basePath) @@ -294,14 +294,14 @@ func (a testapi) LogGet(user usrInfo) (int, []apilib.AccessLog, error) { return code, successPayload, err } -////Delete a repository or a tag in a repository. -////Delete a repository or a tag in a repository. -////This endpoint let user delete repositories and tags with repo name and tag.\n -////@param repoName The name of repository which will be deleted. -////@param tag Tag of a repository. -////@return void -////func (a testapi) RepositoriesDelete(prjUsr UsrInfo, repoName string, tag string) (int, error) { -//func (a testapi) RepositoriesDelete(prjUsr UsrInfo, repoName string, tag string) (int, error) { +// //Delete a repository or a tag in a repository. +// //Delete a repository or a tag in a repository. +// //This endpoint let user delete repositories and tags with repo name and tag.\n +// //@param repoName The name of repository which will be deleted. +// //@param tag Tag of a repository. +// //@return void +// //func (a testapi) RepositoriesDelete(prjUsr UsrInfo, repoName string, tag string) (int, error) { +// func (a testapi) RepositoriesDelete(prjUsr UsrInfo, repoName string, tag string) (int, error) { // _sling := sling.New().Delete(a.basePath) // // create path and map variables @@ -324,7 +324,7 @@ func (a testapi) LogGet(user usrInfo) (int, []apilib.AccessLog, error) { // req, err := _sling.Request() // req.SetBasicAuth(prjUsr.Name, prjUsr.Passwd) -// //fmt.Printf("request %+v", req) +// // fmt.Printf("request %+v", req) // client := &http.Client{} // httpResponse, err := client.Do(req) @@ -334,24 +334,24 @@ func (a testapi) LogGet(user usrInfo) (int, []apilib.AccessLog, error) { // // handle error // } // return httpResponse.StatusCode, err -//} +// } -//Delete project by projectID +// Delete project by projectID func (a testapi) ProjectsDelete(prjUsr usrInfo, projectID string) (int, error) { _sling := sling.New().Delete(a.basePath) - //create api path + // create api path path := "api/projects/" + projectID _sling = _sling.Path(path) httpStatusCode, _, err := request(_sling, jsonAcceptHeader, prjUsr) return httpStatusCode, err } -//Check if the project name user provided already exists +// Check if the project name user provided already exists func (a testapi) ProjectsHead(prjUsr usrInfo, projectName string) (int, error) { _sling := sling.New().Head(a.basePath) - //create api path + // create api path path := "api/projects" _sling = _sling.Path(path) type QueryParams struct { @@ -363,11 +363,11 @@ func (a testapi) ProjectsHead(prjUsr usrInfo, projectName string) (int, error) { return httpStatusCode, err } -//Return specific project detail information +// Return specific project detail information func (a testapi) ProjectsGetByPID(projectID string) (int, apilib.Project, error) { _sling := sling.New().Get(a.basePath) - //create api path + // create api path path := "api/projects/" + projectID _sling = _sling.Path(path) @@ -380,7 +380,7 @@ func (a testapi) ProjectsGetByPID(projectID string) (int, apilib.Project, error) return httpStatusCode, successPayload, err } -//Search projects by projectName and isPublic +// Search projects by projectName and isPublic func (a testapi) ProjectsGet(query *apilib.ProjectQuery, authInfo ...usrInfo) (int, []apilib.Project, error) { _sling := sling.New().Get(a.basePath). Path("api/projects"). @@ -406,7 +406,7 @@ func (a testapi) ProjectsGet(query *apilib.ProjectQuery, authInfo ...usrInfo) (i return httpStatusCode, successPayload, err } -//Update properties for a selected project. +// Update properties for a selected project. func (a testapi) ProjectsPut(prjUsr usrInfo, projectID string, project *models.Project) (int, error) { path := "/api/projects/" + projectID @@ -417,7 +417,7 @@ func (a testapi) ProjectsPut(prjUsr usrInfo, projectID string, } -//Get access logs accompany with a relevant project. +// Get access logs accompany with a relevant project. func (a testapi) ProjectLogs(prjUsr usrInfo, projectID string, query *apilib.LogQuery) (int, []byte, error) { _sling := sling.New().Get(a.basePath). Path("/api/projects/" + projectID + "/logs"). @@ -450,9 +450,9 @@ func (a testapi) ProjectDeletable(prjUsr usrInfo, projectID int64) (int, bool, e return code, deletable.Deletable, nil } -//-------------------------Member Test---------------------------------------// +// -------------------------Member Test---------------------------------------// -//Return relevant role members of projectID +// Return relevant role members of projectID func (a testapi) GetProjectMembersByProID(prjUsr usrInfo, projectID string) (int, []apilib.User, error) { _sling := sling.New().Get(a.basePath) @@ -469,8 +469,8 @@ func (a testapi) GetProjectMembersByProID(prjUsr usrInfo, projectID string) (int return httpStatusCode, successPayload, err } -//Add project role member accompany with projectID -//func (a testapi) AddProjectMember(prjUsr usrInfo, projectID string, roles apilib.RoleParam) (int, error) { +// Add project role member accompany with projectID +// func (a testapi) AddProjectMember(prjUsr usrInfo, projectID string, roles apilib.RoleParam) (int, error) { func (a testapi) AddProjectMember(prjUsr usrInfo, projectID string, member *models.MemberReq) (int, error) { _sling := sling.New().Post(a.basePath) @@ -482,7 +482,7 @@ func (a testapi) AddProjectMember(prjUsr usrInfo, projectID string, member *mode } -//Delete project role member accompany with projectID +// Delete project role member accompany with projectID func (a testapi) DeleteProjectMember(authInfo usrInfo, projectID string, userID string) (int, error) { _sling := sling.New().Delete(a.basePath) @@ -493,7 +493,7 @@ func (a testapi) DeleteProjectMember(authInfo usrInfo, projectID string, userID } -//Get role memberInfo by projectId and UserId +// Get role memberInfo by projectId and UserId func (a testapi) GetMemByPIDUID(authInfo usrInfo, projectID string, userID string) (int, error) { _sling := sling.New().Get(a.basePath) @@ -505,7 +505,7 @@ func (a testapi) GetMemByPIDUID(authInfo usrInfo, projectID string, userID strin return httpStatusCode, err } -//Put:update current project role members accompany with relevant project and user +// Put:update current project role members accompany with relevant project and user func (a testapi) PutProjectMember(authInfo usrInfo, projectID string, userID string, roles apilib.RoleParam) (int, error) { _sling := sling.New().Put(a.basePath) path := "/api/projects/" + projectID + "/members/" + userID @@ -517,8 +517,8 @@ func (a testapi) PutProjectMember(authInfo usrInfo, projectID string, userID str return httpStatusCode, err } -//-------------------------Repositories Test---------------------------------------// -//Return relevant repos of projectID +// -------------------------Repositories Test---------------------------------------// +// Return relevant repos of projectID func (a testapi) GetRepos(authInfo usrInfo, projectID, keyword string) ( int, interface{}, error) { _sling := sling.New().Get(a.basePath) @@ -571,7 +571,7 @@ func (a testapi) GetTag(authInfo usrInfo, repository string, tag string) (int, * return http.StatusOK, &result, nil } -//Get tags of a relevant repository +// Get tags of a relevant repository func (a testapi) GetReposTags(authInfo usrInfo, repoName string) (int, interface{}, error) { _sling := sling.New().Get(a.basePath) @@ -595,7 +595,7 @@ func (a testapi) GetReposTags(authInfo usrInfo, repoName string) (int, interface return http.StatusOK, result, nil } -//Get manifests of a relevant repository +// Get manifests of a relevant repository func (a testapi) GetReposManifests(authInfo usrInfo, repoName string, tag string) (int, error) { _sling := sling.New().Get(a.basePath) @@ -607,7 +607,7 @@ func (a testapi) GetReposManifests(authInfo usrInfo, repoName string, tag string return httpStatusCode, err } -//Get public repositories which are accessed most +// Get public repositories which are accessed most func (a testapi) GetReposTop(authInfo usrInfo, count string) (int, interface{}, error) { _sling := sling.New().Get(a.basePath) @@ -638,8 +638,8 @@ func (a testapi) GetReposTop(authInfo usrInfo, count string) (int, interface{}, return http.StatusOK, result, nil } -//-------------------------Targets Test---------------------------------------// -//Create a new replication target +// -------------------------Targets Test---------------------------------------// +// Create a new replication target func (a testapi) AddTargets(authInfo usrInfo, repTarget apilib.RepTargetPost) (int, string, error) { _sling := sling.New().Post(a.basePath) @@ -652,7 +652,7 @@ func (a testapi) AddTargets(authInfo usrInfo, repTarget apilib.RepTargetPost) (i return httpStatusCode, string(body), err } -//List filters targets by name +// List filters targets by name func (a testapi) ListTargets(authInfo usrInfo, targetName string) (int, []apilib.RepTarget, error) { _sling := sling.New().Get(a.basePath) @@ -670,7 +670,7 @@ func (a testapi) ListTargets(authInfo usrInfo, targetName string) (int, []apilib return httpStatusCode, successPayload, err } -//Ping target +// Ping target func (a testapi) PingTarget(authInfo usrInfo, body interface{}) (int, error) { _sling := sling.New().Post(a.basePath) @@ -683,7 +683,7 @@ func (a testapi) PingTarget(authInfo usrInfo, body interface{}) (int, error) { return httpStatusCode, err } -//Get target by targetID +// Get target by targetID func (a testapi) GetTargetByID(authInfo usrInfo, targetID string) (int, error) { _sling := sling.New().Get(a.basePath) @@ -696,7 +696,7 @@ func (a testapi) GetTargetByID(authInfo usrInfo, targetID string) (int, error) { return httpStatusCode, err } -//Update target by targetID +// Update target by targetID func (a testapi) PutTargetByID(authInfo usrInfo, targetID string, repTarget apilib.RepTargetPost) (int, error) { _sling := sling.New().Put(a.basePath) @@ -710,7 +710,7 @@ func (a testapi) PutTargetByID(authInfo usrInfo, targetID string, repTarget apil return httpStatusCode, err } -//List the target relevant policies by targetID +// List the target relevant policies by targetID func (a testapi) GetTargetPoliciesByID(authInfo usrInfo, targetID string) (int, error) { _sling := sling.New().Get(a.basePath) @@ -723,7 +723,7 @@ func (a testapi) GetTargetPoliciesByID(authInfo usrInfo, targetID string) (int, return httpStatusCode, err } -//Delete target by targetID +// Delete target by targetID func (a testapi) DeleteTargetsByID(authInfo usrInfo, targetID string) (int, error) { _sling := sling.New().Delete(a.basePath) @@ -735,9 +735,9 @@ func (a testapi) DeleteTargetsByID(authInfo usrInfo, targetID string) (int, erro return httpStatusCode, err } -//--------------------Replication_Policy Test--------------------------------// +// --------------------Replication_Policy Test--------------------------------// -//Create a new replication policy +// Create a new replication policy func (a testapi) AddPolicy(authInfo usrInfo, repPolicy apilib.RepPolicyPost) (int, error) { _sling := sling.New().Post(a.basePath) @@ -753,7 +753,7 @@ func (a testapi) AddPolicy(authInfo usrInfo, repPolicy apilib.RepPolicyPost) (in return httpStatusCode, err } -//List policies by policyName and projectID +// List policies by policyName and projectID func (a testapi) ListPolicies(authInfo usrInfo, policyName string, proID string) (int, []apilib.RepPolicy, error) { _sling := sling.New().Get(a.basePath) @@ -777,7 +777,7 @@ func (a testapi) ListPolicies(authInfo usrInfo, policyName string, proID string) return httpStatusCode, successPayload, err } -//Get replication policy by policyID +// Get replication policy by policyID func (a testapi) GetPolicyByID(authInfo usrInfo, policyID string) (int, error) { _sling := sling.New().Get(a.basePath) @@ -790,7 +790,7 @@ func (a testapi) GetPolicyByID(authInfo usrInfo, policyID string) (int, error) { return httpStatusCode, err } -//Update policyInfo by policyID +// Update policyInfo by policyID func (a testapi) PutPolicyInfoByID(authInfo usrInfo, policyID string, policyUpdate apilib.RepPolicyUpdate) (int, error) { _sling := sling.New().Put(a.basePath) @@ -803,7 +803,7 @@ func (a testapi) PutPolicyInfoByID(authInfo usrInfo, policyID string, policyUpda return httpStatusCode, err } -//Update policy enablement flag by policyID +// Update policy enablement flag by policyID func (a testapi) PutPolicyEnableByID(authInfo usrInfo, policyID string, policyEnable apilib.RepPolicyEnablementReq) (int, error) { _sling := sling.New().Put(a.basePath) @@ -816,7 +816,7 @@ func (a testapi) PutPolicyEnableByID(authInfo usrInfo, policyID string, policyEn return httpStatusCode, err } -//Delete policy by policyID +// Delete policy by policyID func (a testapi) DeletePolicyByID(authInfo usrInfo, policyID string) (int, error) { _sling := sling.New().Delete(a.basePath) @@ -828,55 +828,55 @@ func (a testapi) DeletePolicyByID(authInfo usrInfo, policyID string) (int, error return httpStatusCode, err } -//Return projects created by Harbor -//func (a HarborApi) ProjectsGet (projectName string, isPublic int32) ([]Project, error) { +// Return projects created by Harbor +// func (a HarborApi) ProjectsGet (projectName string, isPublic int32) ([]Project, error) { // } -//Check if the project name user provided already exists. -//func (a HarborApi) ProjectsHead (projectName string) (error) { -//} +// Check if the project name user provided already exists. +// func (a HarborApi) ProjectsHead (projectName string) (error) { +// } -//Get access logs accompany with a relevant project. -//func (a HarborApi) ProjectsProjectIdLogsFilterPost (projectID int32, accessLog AccessLog) ([]AccessLog, error) { -//} +// Get access logs accompany with a relevant project. +// func (a HarborApi) ProjectsProjectIdLogsFilterPost (projectID int32, accessLog AccessLog) ([]AccessLog, error) { +// } -//Return a project's relevant role members. -//func (a HarborApi) ProjectsProjectIdMembersGet (projectID int32) ([]Role, error) { -//} +// Return a project's relevant role members. +// func (a HarborApi) ProjectsProjectIdMembersGet (projectID int32) ([]Role, error) { +// } -//Add project role member accompany with relevant project and user. -//func (a HarborApi) ProjectsProjectIdMembersPost (projectID int32, roles RoleParam) (error) { -//} +// Add project role member accompany with relevant project and user. +// func (a HarborApi) ProjectsProjectIdMembersPost (projectID int32, roles RoleParam) (error) { +// } -//Delete project role members accompany with relevant project and user. -//func (a HarborApi) ProjectsProjectIdMembersUserIdDelete (projectID int32, userId int32) (error) { -//} +// Delete project role members accompany with relevant project and user. +// func (a HarborApi) ProjectsProjectIdMembersUserIdDelete (projectID int32, userId int32) (error) { +// } -//Return role members accompany with relevant project and user. -//func (a HarborApi) ProjectsProjectIdMembersUserIdGet (projectID int32, userId int32) ([]Role, error) { -//} +// Return role members accompany with relevant project and user. +// func (a HarborApi) ProjectsProjectIdMembersUserIdGet (projectID int32, userId int32) ([]Role, error) { +// } -//Update project role members accompany with relevant project and user. -//func (a HarborApi) ProjectsProjectIdMembersUserIdPut (projectID int32, userId int32, roles RoleParam) (error) { -//} +// Update project role members accompany with relevant project and user. +// func (a HarborApi) ProjectsProjectIdMembersUserIdPut (projectID int32, userId int32, roles RoleParam) (error) { +// } -//Update properties for a selected project. -//func (a HarborApi) ProjectsProjectIdPut (projectID int32, project Project) (error) { -//} +// Update properties for a selected project. +// func (a HarborApi) ProjectsProjectIdPut (projectID int32, project Project) (error) { +// } -//Get repositories accompany with relevant project and repo name. -//func (a HarborApi) RepositoriesGet (projectID int32, q string) ([]Repository, error) { -//} +// Get repositories accompany with relevant project and repo name. +// func (a HarborApi) RepositoriesGet (projectID int32, q string) ([]Repository, error) { +// } -//Get manifests of a relevant repository. -//func (a HarborApi) RepositoriesManifestGet (repoName string, tag string) (error) { -//} +// Get manifests of a relevant repository. +// func (a HarborApi) RepositoriesManifestGet (repoName string, tag string) (error) { +// } -//Get tags of a relevant repository. -//func (a HarborApi) RepositoriesTagsGet (repoName string) (error) { -//} +// Get tags of a relevant repository. +// func (a HarborApi) RepositoriesTagsGet (repoName string) (error) { +// } -//Get registered users of Harbor. +// Get registered users of Harbor. func (a testapi) UsersGet(userName string, authInfo usrInfo) (int, []apilib.User, error) { _sling := sling.New().Get(a.basePath) // create path and map variables @@ -895,7 +895,7 @@ func (a testapi) UsersGet(userName string, authInfo usrInfo) (int, []apilib.User return httpStatusCode, successPayLoad, err } -//Get registered users by userid. +// Get registered users by userid. func (a testapi) UsersGetByID(userName string, authInfo usrInfo, userID int) (int, apilib.User, error) { _sling := sling.New().Get(a.basePath) // create path and map variables @@ -914,7 +914,7 @@ func (a testapi) UsersGetByID(userName string, authInfo usrInfo, userID int) (in return httpStatusCode, successPayLoad, err } -//Creates a new user account. +// Creates a new user account. func (a testapi) UsersPost(user apilib.User, authInfo ...usrInfo) (int, error) { _sling := sling.New().Post(a.basePath) @@ -936,7 +936,7 @@ func (a testapi) UsersPost(user apilib.User, authInfo ...usrInfo) (int, error) { } -//Update a registered user to change profile. +// Update a registered user to change profile. func (a testapi) UsersPut(userID int, profile apilib.UserProfile, authInfo usrInfo) (int, error) { _sling := sling.New().Put(a.basePath) // create path and map variables @@ -949,7 +949,7 @@ func (a testapi) UsersPut(userID int, profile apilib.UserProfile, authInfo usrIn return httpStatusCode, err } -//Update a registered user to be an administrator of Harbor. +// Update a registered user to be an administrator of Harbor. func (a testapi) UsersToggleAdminRole(userID int, authInfo usrInfo, hasAdminRole bool) (int, error) { _sling := sling.New().Put(a.basePath) // create path and map variables @@ -964,7 +964,7 @@ func (a testapi) UsersToggleAdminRole(userID int, authInfo usrInfo, hasAdminRole return httpStatusCode, err } -//Update password of a registered user. +// Update password of a registered user. func (a testapi) UsersUpdatePassword(userID int, password apilib.Password, authInfo usrInfo) (int, error) { _sling := sling.New().Put(a.basePath) // create path and map variables @@ -976,7 +976,7 @@ func (a testapi) UsersUpdatePassword(userID int, password apilib.Password, authI return httpStatusCode, err } -//Mark a registered user as be removed. +// Mark a registered user as be removed. func (a testapi) UsersDelete(userID int, authInfo usrInfo) (int, error) { _sling := sling.New().Delete(a.basePath) // create path and map variables @@ -1007,7 +1007,7 @@ func updateInitPassword(userID int, password string) error { return nil } -//Get system volume info +// Get system volume info func (a testapi) VolumeInfoGet(authInfo usrInfo) (int, apilib.SystemInfo, error) { _sling := sling.New().Get(a.basePath) path := "/api/systeminfo/volumes" @@ -1031,7 +1031,7 @@ func (a testapi) Ping() (int, []byte, error) { return request(_sling, jsonAcceptHeader) } -//Get system cert +// Get system cert func (a testapi) CertGet(authInfo usrInfo) (int, []byte, error) { _sling := sling.New().Get(a.basePath) path := "/api/systeminfo/getcert" @@ -1040,7 +1040,7 @@ func (a testapi) CertGet(authInfo usrInfo) (int, []byte, error) { return httpStatusCode, body, err } -//Post ldap test +// Post ldap test func (a testapi) LdapPost(authInfo usrInfo, ldapConf apilib.LdapConf) (int, error) { _sling := sling.New().Post(a.basePath) diff --git a/src/ui/api/ldap.go b/src/ui/api/ldap.go index 8320ab198..0f9922431 100644 --- a/src/ui/api/ldap.go +++ b/src/ui/api/ldap.go @@ -124,7 +124,7 @@ func (l *LdapAPI) ImportUser() { } if len(ldapFailedImportUsers) > 0 { - //Some user require json format response. + // Some user require json format response. l.HandleNotFound("") l.Data["json"] = ldapFailedImportUsers l.ServeJSON() @@ -203,7 +203,7 @@ func (l *LdapAPI) SearchGroup() { ldapSession.Open() defer ldapSession.Close() - //Search LDAP group by groupName or group DN + // Search LDAP group by groupName or group DN if len(searchName) > 0 { ldapGroups, err = ldapSession.SearchGroupByName(searchName) if err != nil { @@ -217,7 +217,7 @@ func (l *LdapAPI) SearchGroup() { } ldapGroups, err = ldapSession.SearchGroupByDN(groupDN) if err != nil { - //OpenLDAP usually return an error if DN is not found + // OpenLDAP usually return an error if DN is not found l.HandleNotFound(fmt.Sprintf("Search LDAP group fail, error: %v", err)) return } diff --git a/src/ui/api/log.go b/src/ui/api/log.go index 9d4527eb4..21c015773 100644 --- a/src/ui/api/log.go +++ b/src/ui/api/log.go @@ -22,14 +22,14 @@ import ( "github.com/goharbor/harbor/src/common/utils" ) -//LogAPI handles request api/logs +// LogAPI handles request api/logs type LogAPI struct { BaseController username string isSysAdmin bool } -//Prepare validates the URL and the user +// Prepare validates the URL and the user func (l *LogAPI) Prepare() { l.BaseController.Prepare() if !l.SecurityCtx.IsAuthenticated() { @@ -40,7 +40,7 @@ func (l *LogAPI) Prepare() { l.isSysAdmin = l.SecurityCtx.IsSysAdmin() } -//Get returns the recent logs according to parameters +// Get returns the recent logs according to parameters func (l *LogAPI) Get() { page, size := l.GetPaginationParams() query := &models.LogQueryParam{ diff --git a/src/ui/api/models/reg_gc.go b/src/ui/api/models/reg_gc.go index a498d7c87..b2d1051f6 100644 --- a/src/ui/api/models/reg_gc.go +++ b/src/ui/api/models/reg_gc.go @@ -27,13 +27,13 @@ import ( ) const ( - //ScheduleDaily : 'Daily' + // ScheduleDaily : 'Daily' ScheduleDaily = "Daily" - //ScheduleWeekly : 'Weekly' + // ScheduleWeekly : 'Weekly' ScheduleWeekly = "Weekly" - //ScheduleManual : 'Manual' + // ScheduleManual : 'Manual' ScheduleManual = "Manual" - //ScheduleNone : 'None' + // ScheduleNone : 'None' ScheduleNone = "None" ) @@ -45,13 +45,13 @@ type GCReq struct { Parameters map[string]interface{} `json:"parameters"` } -//ScheduleParam defines the parameter of schedule trigger +// ScheduleParam defines the parameter of schedule trigger type ScheduleParam struct { - //Daily, Weekly, Manual, None + // Daily, Weekly, Manual, None Type string `json:"type"` - //Optional, only used when type is 'weekly' + // Optional, only used when type is 'weekly' Weekday int8 `json:"Weekday"` - //The time offset with the UTC 00:00 in seconds + // The time offset with the UTC 00:00 in seconds Offtime int64 `json:"Offtime"` } diff --git a/src/ui/api/project.go b/src/ui/api/project.go index f77289592..646b46d43 100644 --- a/src/ui/api/project.go +++ b/src/ui/api/project.go @@ -296,7 +296,7 @@ func (p *ProjectAPI) deletable(projectID int64) (*deletableResp, error) { }, nil } - //Check helm charts number + // Check helm charts number if config.WithChartMuseum() { charts, err := chartController.GetUtilityHandler().GetChartsByNs(p.project.Name) if err != nil { @@ -370,7 +370,7 @@ func (p *ProjectAPI) List() { projects = append(projects, mps...) } } - //Query projects by user group + // Query projects by user group if projects != nil { projectIDs := []int64{} diff --git a/src/ui/api/project_test.go b/src/ui/api/project_test.go index 09970fec2..32355eab1 100644 --- a/src/ui/api/project_test.go +++ b/src/ui/api/project_test.go @@ -45,10 +45,10 @@ func TestAddProject(t *testing.T) { apiTest := newHarborAPI() - //prepare for test + // prepare for test InitAddPro() - //case 1: admin not login, expect project creation fail. + // case 1: admin not login, expect project creation fail. result, err := apiTest.ProjectsPost(*unknownUsr, *addProject) if err != nil { @@ -56,10 +56,10 @@ func TestAddProject(t *testing.T) { t.Log(err) } else { assert.Equal(int(401), result, "Case 1: Project creation status should be 401") - //t.Log(result) + // t.Log(result) } - //case 2: admin successful login, expect project creation success. + // case 2: admin successful login, expect project creation success. fmt.Println("case 2: admin successful login, expect project creation success.") result, err = apiTest.ProjectsPost(*admin, *addProject) @@ -68,10 +68,10 @@ func TestAddProject(t *testing.T) { t.Log(err) } else { assert.Equal(int(201), result, "Case 2: Project creation status should be 201") - //t.Log(result) + // t.Log(result) } - //case 3: duplicate project name, create project fail + // case 3: duplicate project name, create project fail fmt.Println("case 3: duplicate project name, create project fail") result, err = apiTest.ProjectsPost(*admin, *addProject) @@ -80,10 +80,10 @@ func TestAddProject(t *testing.T) { t.Log(err) } else { assert.Equal(int(409), result, "Case 3: Project creation status should be 409") - //t.Log(result) + // t.Log(result) } - //case 4: response code = 400 : Project name is illegal in length + // case 4: response code = 400 : Project name is illegal in length fmt.Println("case 4 : response code = 400 : Project name is illegal in length ") result, err = apiTest.ProjectsPost(*admin, apilib.ProjectReq{"t", map[string]string{models.ProMetaPublic: "true"}}) @@ -105,7 +105,7 @@ func TestListProjects(t *testing.T) { apiTest := newHarborAPI() var result []apilib.Project - //----------------------------case 1 : Response Code=200----------------------------// + // ----------------------------case 1 : Response Code=200----------------------------// fmt.Println("case 1: respose code:200") httpStatusCode, result, err := apiTest.ProjectsGet( &apilib.ProjectQuery{ @@ -118,10 +118,10 @@ func TestListProjects(t *testing.T) { assert.Equal(addProject.ProjectName, result[0].ProjectName, "Project name is wrong") assert.Equal("true", result[0].Metadata[models.ProMetaPublic], "Public is wrong") - //find add projectID + // find add projectID addPID = int(result[0].ProjectId) - //-------------------case 3 : check admin project role------------------------// + // -------------------case 3 : check admin project role------------------------// httpStatusCode, result, err = apiTest.ProjectsGet( &apilib.ProjectQuery{ Name: addProject.ProjectName, @@ -138,7 +138,7 @@ func TestListProjects(t *testing.T) { assert.Equal(int32(1), result[0].CurrentUserRoleId, "User project role is wrong") } - //-------------------case 4 : add project member and check his role ------------------------// + // -------------------case 4 : add project member and check his role ------------------------// CommonAddUser() member := &models.MemberReq{ Role: 2, @@ -178,7 +178,7 @@ func TestListProjects(t *testing.T) { CommonDelUser() } -//Get project by proID +// Get project by proID func TestProGetByID(t *testing.T) { fmt.Println("\nTest for Project GET API by project id") assert := assert.New(t) @@ -187,7 +187,7 @@ func TestProGetByID(t *testing.T) { var result apilib.Project projectID := strconv.Itoa(addPID) - //----------------------------case 1 : Response Code=200----------------------------// + // ----------------------------case 1 : Response Code=200----------------------------// fmt.Println("case 1: respose code:200") httpStatusCode, result, err := apiTest.ProjectsGetByPID(projectID) if err != nil { @@ -209,7 +209,7 @@ func TestDeleteProject(t *testing.T) { projectID := strconv.Itoa(addPID) - //--------------------------case 1: Response Code=401,User need to log in first.-----------------------// + // --------------------------case 1: Response Code=401,User need to log in first.-----------------------// fmt.Println("case 1: Response Code=401,User need to log in first.") httpStatusCode, err := apiTest.ProjectsDelete(*unknownUsr, projectID) if err != nil { @@ -219,7 +219,7 @@ func TestDeleteProject(t *testing.T) { assert.Equal(int(401), httpStatusCode, "Case 1: Project creation status should be 401") } - //--------------------------case 2: Response Code=200---------------------------------// + // --------------------------case 2: Response Code=200---------------------------------// fmt.Println("case2: respose code:200") httpStatusCode, err = apiTest.ProjectsDelete(*admin, projectID) if err != nil { @@ -229,7 +229,7 @@ func TestDeleteProject(t *testing.T) { assert.Equal(int(200), httpStatusCode, "Case 2: Project creation status should be 200") } - //--------------------------case 3: Response Code=404,Project does not exist---------------------------------// + // --------------------------case 3: Response Code=404,Project does not exist---------------------------------// fmt.Println("case 3: Response Code=404,Project does not exist") projectID = "11" httpStatusCode, err = apiTest.ProjectsDelete(*admin, projectID) @@ -240,7 +240,7 @@ func TestDeleteProject(t *testing.T) { assert.Equal(int(404), httpStatusCode, "Case 3: Project creation status should be 404") } - //--------------------------case 4: Response Code=400,Invalid project id.---------------------------------// + // --------------------------case 4: Response Code=400,Invalid project id.---------------------------------// fmt.Println("case 4: Response Code=400,Invalid project id.") projectID = "cc" httpStatusCode, err = apiTest.ProjectsDelete(*admin, projectID) @@ -259,7 +259,7 @@ func TestProHead(t *testing.T) { apiTest := newHarborAPI() - //----------------------------case 1 : Response Code=200----------------------------// + // ----------------------------case 1 : Response Code=200----------------------------// fmt.Println("case 1: respose code:200") httpStatusCode, err := apiTest.ProjectsHead(*admin, "library") if err != nil { @@ -269,7 +269,7 @@ func TestProHead(t *testing.T) { assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200") } - //----------------------------case 2 : Response Code=404:Project name does not exist.----------------------------// + // ----------------------------case 2 : Response Code=404:Project name does not exist.----------------------------// fmt.Println("case 2: respose code:404,Project name does not exist.") httpStatusCode, err = apiTest.ProjectsHead(*admin, "libra") if err != nil { @@ -331,7 +331,7 @@ func TestProjectLogsFilter(t *testing.T) { EndTimestamp: time.Now().Unix(), } - //-------------------case1: Response Code=200------------------------------// + // -------------------case1: Response Code=200------------------------------// fmt.Println("case 1: respose code:200") projectID := "1" httpStatusCode, _, err := apiTest.ProjectLogs(*admin, projectID, query) @@ -341,7 +341,7 @@ func TestProjectLogsFilter(t *testing.T) { } else { assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200") } - //-------------------case2: Response Code=401:User need to log in first.------------------------------// + // -------------------case2: Response Code=401:User need to log in first.------------------------------// fmt.Println("case 2: respose code:401:User need to log in first.") projectID = "1" httpStatusCode, _, err = apiTest.ProjectLogs(*unknownUsr, projectID, query) @@ -351,7 +351,7 @@ func TestProjectLogsFilter(t *testing.T) { } else { assert.Equal(int(401), httpStatusCode, "httpStatusCode should be 401") } - //-------------------case3: Response Code=404:Project does not exist.-------------------------// + // -------------------case3: Response Code=404:Project does not exist.-------------------------// fmt.Println("case 3: respose code:404:Illegal format of provided ID value.") projectID = "11111" httpStatusCode, _, err = apiTest.ProjectLogs(*admin, projectID, query) @@ -410,7 +410,7 @@ func TestDeletable(t *testing.T) { assert.False(t, del) } -//Provides a mock chart controller for deletable test cases +// Provides a mock chart controller for deletable test cases func mockChartController() (*httptest.Server, *chartserver.Controller, error) { mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.RequestURI { @@ -436,7 +436,7 @@ func mockChartController() (*httptest.Server, *chartserver.Controller, error) { return nil, nil, err } - //Override current controller and keep the old one for restoring + // Override current controller and keep the old one for restoring oldController = chartController chartController = newController diff --git a/src/ui/api/projectmember.go b/src/ui/api/projectmember.go index 3fbfe40c0..ac4705649 100644 --- a/src/ui/api/projectmember.go +++ b/src/ui/api/projectmember.go @@ -90,7 +90,7 @@ func (pma *ProjectMemberAPI) Prepare() { pma.id = int(pmid) } -//Get ... +// Get ... func (pma *ProjectMemberAPI) Get() { projectID := pma.project.ProjectID queryMember := models.Member{} @@ -108,7 +108,7 @@ func (pma *ProjectMemberAPI) Get() { } } else { - //return a specific member + // return a specific member queryMember.ID = pma.id memberList, err := project.GetProjectMember(queryMember) if err != nil { @@ -201,7 +201,7 @@ func AddProjectMember(projectID int64, request models.MemberReq) (int, error) { member.EntityID = userID } else if len(request.MemberGroup.LdapGroupDN) > 0 { - //If groupname provided, use the provided groupname to name this group + // If groupname provided, use the provided groupname to name this group groupID, err := auth.SearchAndOnBoardGroup(request.MemberGroup.LdapGroupDN, request.MemberGroup.GroupName) if err != nil { return 0, err @@ -213,7 +213,7 @@ func AddProjectMember(projectID int64, request models.MemberReq) (int, error) { return 0, fmt.Errorf("Can not get valid member entity, request: %+v", request) } - //Check if member already exist in current project + // Check if member already exist in current project memberList, err := project.GetProjectMember(models.Member{ ProjectID: member.ProjectID, EntityID: member.EntityID, @@ -227,7 +227,7 @@ func AddProjectMember(projectID int64, request models.MemberReq) (int, error) { } if member.Role < 1 || member.Role > 3 { - //Return invalid role error + // Return invalid role error return 0, ErrInvalidRole } return project.AddProjectMember(member) diff --git a/src/ui/api/projectmember_test.go b/src/ui/api/projectmember_test.go index 043e5ef9e..0c97c1539 100644 --- a/src/ui/api/projectmember_test.go +++ b/src/ui/api/projectmember_test.go @@ -34,7 +34,7 @@ func TestProjectMemberAPI_Get(t *testing.T) { }, code: http.StatusUnauthorized, }, - //200 + // 200 { request: &testingRequest{ method: http.MethodGet, @@ -43,7 +43,7 @@ func TestProjectMemberAPI_Get(t *testing.T) { }, code: http.StatusOK, }, - //400 + // 400 { request: &testingRequest{ method: http.MethodGet, diff --git a/src/ui/api/reg_gc.go b/src/ui/api/reg_gc.go index d6265673c..052d98c43 100644 --- a/src/ui/api/reg_gc.go +++ b/src/ui/api/reg_gc.go @@ -47,7 +47,7 @@ func (gc *GCAPI) Prepare() { } } -//Post ... +// Post ... func (gc *GCAPI) Post() { gr := models.GCReq{} gc.DecodeJSONReqAndValidate(&gr) @@ -55,7 +55,7 @@ func (gc *GCAPI) Post() { gc.Redirect(http.StatusCreated, strconv.FormatInt(gr.ID, 10)) } -//Put ... +// Put ... func (gc *GCAPI) Put() { gr := models.GCReq{} gc.DecodeJSONReqAndValidate(&gr) @@ -146,7 +146,7 @@ func (gc *GCAPI) Get() { gc.ServeJSON() } -//GetLog ... +// GetLog ... func (gc *GCAPI) GetLog() { id, err := gc.GetInt64FromPath(":id") if err != nil { diff --git a/src/ui/api/reg_gc_test.go b/src/ui/api/reg_gc_test.go index e86737093..97b1d7498 100644 --- a/src/ui/api/reg_gc_test.go +++ b/src/ui/api/reg_gc_test.go @@ -15,7 +15,7 @@ func TestAdminJobPost(t *testing.T) { assert := assert.New(t) apiTest := newHarborAPI() - //case 1: add a new admin job + // case 1: add a new admin job code, err := apiTest.AddGC(*admin, adminJob001) if err != nil { t.Error("Error occurred while add a admin job", err.Error()) diff --git a/src/ui/api/replication_job.go b/src/ui/api/replication_job.go index e89fd7f45..54ffe8ee4 100644 --- a/src/ui/api/replication_job.go +++ b/src/ui/api/replication_job.go @@ -247,4 +247,4 @@ func (ra *RepJobAPI) StopJobs() { } } -//TODO:add Post handler to call job service API to submit jobs by policy +// TODO:add Post handler to call job service API to submit jobs by policy diff --git a/src/ui/api/repository.go b/src/ui/api/repository.go index 4e17f5e47..0634abaab 100644 --- a/src/ui/api/repository.go +++ b/src/ui/api/repository.go @@ -727,7 +727,7 @@ func getManifest(client *registry.Repository, return result, nil } -//GetTopRepos returns the most populor repositories +// GetTopRepos returns the most populor repositories func (ra *RepositoryAPI) GetTopRepos() { count, err := ra.GetInt("count", 10) if err != nil || count <= 0 { @@ -802,7 +802,7 @@ func (ra *RepositoryAPI) Put() { } } -//GetSignatures returns signatures of a repository +// GetSignatures returns signatures of a repository func (ra *RepositoryAPI) GetSignatures() { repoName := ra.GetString(":splat") @@ -838,7 +838,7 @@ func (ra *RepositoryAPI) GetSignatures() { ra.ServeJSON() } -//ScanImage handles request POST /api/repository/$repository/tags/$tag/scan to trigger image scan manually. +// ScanImage handles request POST /api/repository/$repository/tags/$tag/scan to trigger image scan manually. func (ra *RepositoryAPI) ScanImage() { if !config.WithClair() { log.Warningf("Harbor is not deployed with Clair, scan is disabled.") @@ -933,7 +933,7 @@ func (ra *RepositoryAPI) ScanAll() { return } projectIDStr := ra.GetString("project_id") - if len(projectIDStr) > 0 { //scan images under the project only. + if len(projectIDStr) > 0 { // scan images under the project only. pid, err := strconv.ParseInt(projectIDStr, 10, 64) if err != nil || pid <= 0 { ra.HandleBadRequest(fmt.Sprintf("Invalid project_id %s", projectIDStr)) @@ -948,7 +948,7 @@ func (ra *RepositoryAPI) ScanAll() { ra.HandleInternalServerError(fmt.Sprintf("Error: %v", err)) return } - } else { //scan all images in Harbor + } else { // scan all images in Harbor if !ra.SecurityCtx.IsSysAdmin() { ra.HandleForbidden(ra.SecurityCtx.GetUsername()) return @@ -1013,7 +1013,7 @@ func (ra *RepositoryAPI) checkExistence(repository, tag string) (bool, string, e return true, digest, nil } -//will return nil when it failed to get data. The parm "tag" is for logging only. +// will return nil when it failed to get data. The parm "tag" is for logging only. func getScanOverview(digest string, tag string) *models.ImgScanOverview { if len(digest) == 0 { log.Debug("digest is nil") @@ -1030,7 +1030,7 @@ func getScanOverview(digest string, tag string) *models.ImgScanOverview { if err != nil { log.Errorf("Failed to get scan job for id:%d, error: %v", data.JobID, err) return nil - } else if job == nil { //job does not exist + } else if job == nil { // job does not exist log.Errorf("The scan job with id: %d does not exist, returning nil", data.JobID) return nil } diff --git a/src/ui/api/repository_test.go b/src/ui/api/repository_test.go index 20307284f..592d9b4a5 100644 --- a/src/ui/api/repository_test.go +++ b/src/ui/api/repository_test.go @@ -33,7 +33,7 @@ func TestGetRepos(t *testing.T) { keyword := "library/hello-world" fmt.Println("Testing Repos Get API") - //-------------------case 1 : response code = 200------------------------// + // -------------------case 1 : response code = 200------------------------// fmt.Println("case 1 : response code = 200") code, repositories, err := apiTest.GetRepos(*admin, projectID, keyword) if err != nil { @@ -48,7 +48,7 @@ func TestGetRepos(t *testing.T) { } } - //-------------------case 2 : response code = 404------------------------// + // -------------------case 2 : response code = 404------------------------// fmt.Println("case 2 : response code = 404:project not found") projectID = "111" httpStatusCode, _, err := apiTest.GetRepos(*admin, projectID, keyword) @@ -59,7 +59,7 @@ func TestGetRepos(t *testing.T) { assert.Equal(int(404), httpStatusCode, "httpStatusCode should be 404") } - //-------------------case 3 : response code = 400------------------------// + // -------------------case 3 : response code = 400------------------------// fmt.Println("case 3 : response code = 400,invalid project_id") projectID = "ccc" httpStatusCode, _, err = apiTest.GetRepos(*admin, projectID, keyword) @@ -78,7 +78,7 @@ func TestGetReposTags(t *testing.T) { assert := assert.New(t) apiTest := newHarborAPI() - //-------------------case 1 : response code = 404------------------------// + // -------------------case 1 : response code = 404------------------------// fmt.Println("case 1 : response code = 404,repo not found") repository := "errorRepos" code, _, err := apiTest.GetReposTags(*admin, repository) @@ -87,7 +87,7 @@ func TestGetReposTags(t *testing.T) { } else { assert.Equal(int(404), code, "httpStatusCode should be 404") } - //-------------------case 2 : response code = 200------------------------// + // -------------------case 2 : response code = 200------------------------// fmt.Println("case 2 : response code = 200") repository = "library/hello-world" code, tags, err := apiTest.GetReposTags(*admin, repository) @@ -103,7 +103,7 @@ func TestGetReposTags(t *testing.T) { } } - //-------------------case 3 : response code = 404------------------------// + // -------------------case 3 : response code = 404------------------------// fmt.Println("case 3 : response code = 404") repository = "library/hello-world" tag := "not_exist_tag" @@ -111,7 +111,7 @@ func TestGetReposTags(t *testing.T) { assert.Nil(err) assert.Equal(http.StatusNotFound, code) - //-------------------case 4 : response code = 200------------------------// + // -------------------case 4 : response code = 200------------------------// fmt.Println("case 4 : response code = 200") repository = "library/hello-world" tag = "latest" @@ -133,7 +133,7 @@ func TestGetReposManifests(t *testing.T) { apiTest := newHarborAPI() fmt.Println("Testing ReposManifests Get API") - //-------------------case 1 : response code = 200------------------------// + // -------------------case 1 : response code = 200------------------------// fmt.Println("case 1 : response code = 200") repoName = "library/hello-world" tag = "latest" @@ -144,7 +144,7 @@ func TestGetReposManifests(t *testing.T) { } else { assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200") } - //-------------------case 2 : response code = 404------------------------// + // -------------------case 2 : response code = 404------------------------// fmt.Println("case 2 : response code = 404:tags error,manifest unknown") tag = "l" httpStatusCode, err = apiTest.GetReposManifests(*admin, repoName, tag) @@ -155,7 +155,7 @@ func TestGetReposManifests(t *testing.T) { assert.Equal(int(404), httpStatusCode, "httpStatusCode should be 404") } - //-------------------case 3 : response code = 404------------------------// + // -------------------case 3 : response code = 404------------------------// fmt.Println("case 3 : response code = 404,repo not found") repoName = "111" httpStatusCode, err = apiTest.GetReposManifests(*admin, repoName, tag) @@ -175,7 +175,7 @@ func TestGetReposTop(t *testing.T) { apiTest := newHarborAPI() fmt.Println("Testing ReposTop Get API") - //-------------------case 1 : response code = 400------------------------// + // -------------------case 1 : response code = 400------------------------// fmt.Println("case 1 : response code = 400,invalid count") count := "cc" code, _, err := apiTest.GetReposTop(*admin, count) @@ -185,7 +185,7 @@ func TestGetReposTop(t *testing.T) { assert.Equal(int(400), code, "response code should be 400") } - //-------------------case 2 : response code = 200------------------------// + // -------------------case 2 : response code = 200------------------------// fmt.Println("case 2 : response code = 200") count = "1" code, repos, err := apiTest.GetReposTop(*admin, count) diff --git a/src/ui/api/scan_job.go b/src/ui/api/scan_job.go index 58bfccfef..5fbbf87ac 100644 --- a/src/ui/api/scan_job.go +++ b/src/ui/api/scan_job.go @@ -62,7 +62,7 @@ func (sj *ScanJobAPI) Prepare() { sj.jobUUID = data.UUID } -//GetLog ... +// GetLog ... func (sj *ScanJobAPI) GetLog() { logBytes, err := utils.GetJobServiceClient().GetJobLog(sj.jobUUID) if err != nil { diff --git a/src/ui/api/statistic.go b/src/ui/api/statistic.go index 049cef3e6..88055ff87 100644 --- a/src/ui/api/statistic.go +++ b/src/ui/api/statistic.go @@ -44,7 +44,7 @@ type StatisticAPI struct { username string } -//Prepare validates the URL and the user +// Prepare validates the URL and the user func (s *StatisticAPI) Prepare() { s.BaseController.Prepare() if !s.SecurityCtx.IsAuthenticated() { diff --git a/src/ui/api/statistic_test.go b/src/ui/api/statistic_test.go index 792496af3..6ab89722c 100644 --- a/src/ui/api/statistic_test.go +++ b/src/ui/api/statistic_test.go @@ -18,7 +18,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - //"github.com/goharbor/harbor/tests/apitests/apilib" + // "github.com/goharbor/harbor/tests/apitests/apilib" ) func TestStatisticGet(t *testing.T) { @@ -28,13 +28,13 @@ func TestStatisticGet(t *testing.T) { apiTest := newHarborAPI() - //prepare for test + // prepare for test var privateProjectCount, privateRepoCount int32 var priPublicProjectCount, priPublicRepoCount int32 var priTotalProjectCount, priTotalRepoCount int32 - //case 1: case 1: user not login, expect fail to get status info. + // case 1: case 1: user not login, expect fail to get status info. fmt.Println("case 1: user not login, expect fail to get status info.") httpStatusCode, result, err := apiTest.StatisticGet(*unknownUsr) if err != nil { @@ -44,7 +44,7 @@ func TestStatisticGet(t *testing.T) { assert.Equal(httpStatusCode, int(401), "Case 1: Get status info without login. (401)") } - //case 2: admin successful login, expect get status info successful. + // case 2: admin successful login, expect get status info successful. fmt.Println("case 2: admin successful login, expect get status info successful.") httpStatusCode, result, err = apiTest.StatisticGet(*admin) if err != nil { @@ -52,7 +52,7 @@ func TestStatisticGet(t *testing.T) { t.Log(err) } else { assert.Equal(httpStatusCode, int(200), "Case 2: Get status info with admin login. (200)") - //fmt.Println("pri status data %+v", result) + // fmt.Println("pri status data %+v", result) privateProjectCount = result.PrivateProjectCount privateRepoCount = result.PrivateRepoCount priPublicProjectCount = result.PublicProjectCount @@ -61,14 +61,14 @@ func TestStatisticGet(t *testing.T) { priTotalRepoCount = result.TotalRepoCount } - //case 3: status info increased after add more project and repo. + // case 3: status info increased after add more project and repo. fmt.Println("case 3: status info increased after add more project and repo.") CommonAddProject() CommonAddRepository() httpStatusCode, result, err = apiTest.StatisticGet(*admin) - //fmt.Println("new status data %+v", result) + // fmt.Println("new status data %+v", result) if err != nil { t.Error("Error while get statistic information", err.Error()) @@ -83,7 +83,7 @@ func TestStatisticGet(t *testing.T) { } - //delete the project and repo + // delete the project and repo CommonDelProject() CommonDelRepository() } diff --git a/src/ui/api/systeminfo.go b/src/ui/api/systeminfo.go index 71e01044a..6678512f3 100644 --- a/src/ui/api/systeminfo.go +++ b/src/ui/api/systeminfo.go @@ -31,7 +31,7 @@ import ( "github.com/goharbor/harbor/src/ui/config" ) -//SystemInfoAPI handle requests for getting system info /api/systeminfo +// SystemInfoAPI handle requests for getting system info /api/systeminfo type SystemInfoAPI struct { BaseController } @@ -39,18 +39,18 @@ type SystemInfoAPI struct { const defaultRootCert = "/etc/ui/ca/ca.crt" const harborVersionFile = "/harbor/UIVERSION" -//SystemInfo models for system info. +// SystemInfo models for system info. type SystemInfo struct { HarborStorage Storage `json:"storage"` } -//Storage models for storage. +// Storage models for storage. type Storage struct { Total uint64 `json:"total"` Free uint64 `json:"free"` } -//namespaces stores all name spaces on Clair, it should be initialised only once. +// namespaces stores all name spaces on Clair, it should be initialised only once. type clairNamespaces struct { sync.RWMutex l []string @@ -84,7 +84,7 @@ var ( namespaces = &clairNamespaces{} ) -//GeneralInfo wraps common systeminfo for anonymous request +// GeneralInfo wraps common systeminfo for anonymous request type GeneralInfo struct { WithNotary bool `json:"with_notary"` WithClair bool `json:"with_clair"` @@ -136,7 +136,7 @@ func (sia *SystemInfoAPI) GetVolumeInfo() { sia.ServeJSON() } -//GetCert gets default self-signed certificate. +// GetCert gets default self-signed certificate. func (sia *SystemInfoAPI) GetCert() { sia.validate() if _, err := os.Stat(defaultRootCert); err == nil { @@ -224,7 +224,7 @@ func getClairVulnStatus() *models.ClairVulnerabilityStatus { m := make(map[string]int64) for _, e := range l { ns := strings.Split(e.Namespace, ":") - //only returns the latest time of one distro, i.e. unbuntu:14.04 and ubuntu:15.4 shares one timestamp + // only returns the latest time of one distro, i.e. unbuntu:14.04 and ubuntu:15.4 shares one timestamp el := e.LastUpdate.UTC().Unix() if ts, ok := m[ns[0]]; !ok || ts < el { m[ns[0]] = el @@ -234,7 +234,7 @@ func getClairVulnStatus() *models.ClairVulnerabilityStatus { if err != nil { log.Errorf("Failed to get namespace list from Clair, error: %v", err) } - //For namespaces not reported by notifier, the timestamp will be the overall db timestamp. + // For namespaces not reported by notifier, the timestamp will be the overall db timestamp. for _, n := range list { if _, ok := m[n]; !ok { m[n] = res.OverallUTC diff --git a/src/ui/api/systeminfo_test.go b/src/ui/api/systeminfo_test.go index 170e47102..435b0b5ce 100644 --- a/src/ui/api/systeminfo_test.go +++ b/src/ui/api/systeminfo_test.go @@ -26,7 +26,7 @@ func TestGetVolumeInfo(t *testing.T) { assert := assert.New(t) apiTest := newHarborAPI() - //case 1: get volume info without admin role + // case 1: get volume info without admin role CommonAddUser() code, _, err := apiTest.VolumeInfoGet(*testUser) if err != nil { @@ -35,7 +35,7 @@ func TestGetVolumeInfo(t *testing.T) { } else { assert.Equal(403, code, "Get system volume info should be 403") } - //case 2: get volume info with admin role + // case 2: get volume info with admin role code, info, err := apiTest.VolumeInfoGet(*admin) if err != nil { t.Error("Error occurred while get system volume info") @@ -72,7 +72,7 @@ func TestGetCert(t *testing.T) { assert := assert.New(t) apiTest := newHarborAPI() - //case 1: get cert without admin role + // case 1: get cert without admin role code, _, err := apiTest.CertGet(*testUser) if err != nil { t.Error("Error occurred while get system cert") @@ -80,7 +80,7 @@ func TestGetCert(t *testing.T) { } else { assert.Equal(403, code, "Get system cert should be 403") } - //case 2: get cert with admin role + // case 2: get cert with admin role code, content, err := apiTest.CertGet(*admin) if err != nil { t.Error("Error occurred while get system cert") diff --git a/src/ui/api/target_test.go b/src/ui/api/target_test.go index f79479dac..8bb8c301e 100644 --- a/src/ui/api/target_test.go +++ b/src/ui/api/target_test.go @@ -43,7 +43,7 @@ func TestTargetsPost(t *testing.T) { fmt.Println("Testing Targets Post API") - //-------------------case 1 : response code = 201------------------------// + // -------------------case 1 : response code = 201------------------------// fmt.Println("case 1 : response code = 201") httpStatusCode, body, err := apiTest.AddTargets(*admin, *repTargets) if err != nil { @@ -54,7 +54,7 @@ func TestTargetsPost(t *testing.T) { t.Log(body) } - //-----------case 2 : response code = 409,name is already used-----------// + // -----------case 2 : response code = 409,name is already used-----------// fmt.Println("case 2 : response code = 409,name is already used") httpStatusCode, _, err = apiTest.AddTargets(*admin, *repTargets) if err != nil { @@ -64,7 +64,7 @@ func TestTargetsPost(t *testing.T) { assert.Equal(int(409), httpStatusCode, "httpStatusCode should be 409") } - //-----------case 3 : response code = 409,name is already used-----------// + // -----------case 3 : response code = 409,name is already used-----------// fmt.Println("case 3 : response code = 409,endPoint is already used") repTargets.Username = "errName" httpStatusCode, _, err = apiTest.AddTargets(*admin, *repTargets) @@ -75,7 +75,7 @@ func TestTargetsPost(t *testing.T) { assert.Equal(int(409), httpStatusCode, "httpStatusCode should be 409") } - //--------case 4 : response code = 401,User need to log in first.--------// + // --------case 4 : response code = 401,User need to log in first.--------// fmt.Println("case 4 : response code = 401,User need to log in first.") httpStatusCode, _, err = apiTest.AddTargets(*unknownUsr, *repTargets) if err != nil { @@ -99,7 +99,7 @@ func TestTargetsGet(t *testing.T) { fmt.Println("Testing Targets Get API") - //-------------------case 1 : response code = 200------------------------// + // -------------------case 1 : response code = 200------------------------// fmt.Println("case 1 : response code = 200") httpStatusCode, reslut, err = apiTest.ListTargets(*admin, addTargetName) if err != nil { @@ -163,7 +163,7 @@ func TestTargetGetByID(t *testing.T) { fmt.Println("Testing Targets Get API by Id") - //-------------------case 1 : response code = 200------------------------// + // -------------------case 1 : response code = 200------------------------// fmt.Println("case 1 : response code = 200") id := strconv.Itoa(addTargetID) httpStatusCode, err = apiTest.GetTargetByID(*admin, id) @@ -174,7 +174,7 @@ func TestTargetGetByID(t *testing.T) { assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200") } - //--------------case 2 : response code = 404,target not found------------// + // --------------case 2 : response code = 404,target not found------------// fmt.Println("case 2 : response code = 404,target not found") id = "1111" httpStatusCode, err = apiTest.GetTargetByID(*admin, id) @@ -200,7 +200,7 @@ func TestTargetsPut(t *testing.T) { fmt.Println("Testing Target Put API") - //-------------------case 1 : response code = 200------------------------// + // -------------------case 1 : response code = 200------------------------// fmt.Println("case 1 : response code = 200") httpStatusCode, err = apiTest.PutTargetByID(*admin, id, *updateRepTargets) if err != nil { @@ -210,7 +210,7 @@ func TestTargetsPut(t *testing.T) { assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200") } - //--------------case 2 : response code = 404,target not found------------// + // --------------case 2 : response code = 404,target not found------------// id = "111" fmt.Println("case 2 : response code = 404,target not found") httpStatusCode, err = apiTest.PutTargetByID(*admin, id, *updateRepTargets) @@ -231,7 +231,7 @@ func TestTargetGetPolicies(t *testing.T) { fmt.Println("Testing Targets Get API to list policies") - //-------------------case 1 : response code = 200------------------------// + // -------------------case 1 : response code = 200------------------------// fmt.Println("case 1 : response code = 200") id := strconv.Itoa(addTargetID) httpStatusCode, err = apiTest.GetTargetPoliciesByID(*admin, id) @@ -242,7 +242,7 @@ func TestTargetGetPolicies(t *testing.T) { assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200") } - //--------------case 2 : response code = 404,target not found------------// + // --------------case 2 : response code = 404,target not found------------// fmt.Println("case 2 : response code = 404,target not found") id = "1111" httpStatusCode, err = apiTest.GetTargetPoliciesByID(*admin, id) @@ -265,7 +265,7 @@ func TestTargetsDelete(t *testing.T) { id := strconv.Itoa(addTargetID) fmt.Println("Testing Targets Delete API") - //-------------------case 1 : response code = 200------------------------// + // -------------------case 1 : response code = 200------------------------// fmt.Println("case 1 : response code = 200") httpStatusCode, err = apiTest.DeleteTargetsByID(*admin, id) if err != nil { @@ -275,7 +275,7 @@ func TestTargetsDelete(t *testing.T) { assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200") } - //--------------case 2 : response code = 404,target not found------------// + // --------------case 2 : response code = 404,target not found------------// fmt.Println("case 2 : response code = 404,target not found") id = "1111" httpStatusCode, err = apiTest.DeleteTargetsByID(*admin, id) diff --git a/src/ui/api/user.go b/src/ui/api/user.go index 771e39240..485fa950a 100644 --- a/src/ui/api/user.go +++ b/src/ui/api/user.go @@ -341,11 +341,11 @@ func (ua *UserAPI) ToggleUserAdminRole() { // modifiable returns whether the modify is allowed based on current auth mode and context func (ua *UserAPI) modifiable() bool { if ua.AuthMode == common.DBAuth { - //When the auth mode is local DB, admin can modify anyone, non-admin can modify himself. + // When the auth mode is local DB, admin can modify anyone, non-admin can modify himself. return ua.IsAdmin || ua.userID == ua.currentUserID } - //When the auth mode is external IDM backend, only the super user can modify himself, - //because he's the only one whose information is stored in local DB. + // When the auth mode is external IDM backend, only the super user can modify himself, + // because he's the only one whose information is stored in local DB. return ua.userID == 1 && ua.userID == ua.currentUserID } @@ -365,7 +365,7 @@ func validate(user models.User) error { return commonValidate(user) } -//commonValidate validates email, realname, comment information when user register or change their profile +// commonValidate validates email, realname, comment information when user register or change their profile func commonValidate(user models.User) error { if len(user.Email) > 0 { diff --git a/src/ui/api/user_test.go b/src/ui/api/user_test.go index 275c5c875..6923768e4 100644 --- a/src/ui/api/user_test.go +++ b/src/ui/api/user_test.go @@ -40,7 +40,7 @@ func TestUsersPost(t *testing.T) { assert := assert.New(t) apiTest := newHarborAPI() - //case 1: register a new user without admin auth, expect 400, because self registration is on + // case 1: register a new user without admin auth, expect 400, because self registration is on fmt.Println("Register user without admin auth") code, err := apiTest.UsersPost(testUser0002) if err != nil { @@ -50,7 +50,7 @@ func TestUsersPost(t *testing.T) { assert.Equal(400, code, "Add user status should be 400") } - //case 2: register a new user with admin auth, but username is empty, expect 400 + // case 2: register a new user with admin auth, but username is empty, expect 400 fmt.Println("Register user with admin auth, but username is empty") code, err = apiTest.UsersPost(testUser0002, *admin) if err != nil { @@ -60,7 +60,7 @@ func TestUsersPost(t *testing.T) { assert.Equal(400, code, "Add user status should be 400") } - //case 3: register a new user with admin auth, but bad username format, expect 400 + // case 3: register a new user with admin auth, but bad username format, expect 400 testUser0002.Username = "test@$" fmt.Println("Register user with admin auth, but bad username format") code, err = apiTest.UsersPost(testUser0002, *admin) @@ -71,7 +71,7 @@ func TestUsersPost(t *testing.T) { assert.Equal(400, code, "Add user status should be 400") } - //case 4: register a new user with admin auth, but bad userpassword format, expect 400 + // case 4: register a new user with admin auth, but bad userpassword format, expect 400 testUser0002.Username = "testUser0002" fmt.Println("Register user with admin auth, but empty password.") code, err = apiTest.UsersPost(testUser0002, *admin) @@ -82,7 +82,7 @@ func TestUsersPost(t *testing.T) { assert.Equal(400, code, "Add user status should be 400") } - //case 5: register a new user with admin auth, but email is empty, expect 400 + // case 5: register a new user with admin auth, but email is empty, expect 400 testUser0002.Password = "testUser0002" fmt.Println("Register user with admin auth, but email is empty") code, err = apiTest.UsersPost(testUser0002, *admin) @@ -93,7 +93,7 @@ func TestUsersPost(t *testing.T) { assert.Equal(400, code, "Add user status should be 400") } - //case 6: register a new user with admin auth, but bad email format, expect 400 + // case 6: register a new user with admin auth, but bad email format, expect 400 testUser0002.Email = "test..." fmt.Println("Register user with admin auth, but bad email format") code, err = apiTest.UsersPost(testUser0002, *admin) @@ -104,7 +104,7 @@ func TestUsersPost(t *testing.T) { assert.Equal(400, code, "Add user status should be 400") } - //case 7: register a new user with admin auth, but userrealname is empty, expect 400 + // case 7: register a new user with admin auth, but userrealname is empty, expect 400 /* testUser0002.Email = "testUser0002@mydomain.com" fmt.Println("Register user with admin auth, but user realname is empty") @@ -116,7 +116,7 @@ func TestUsersPost(t *testing.T) { assert.Equal(400, code, "Add user status should be 400") } */ - //case 8: register a new user with admin auth, but bad userrealname format, expect 400 + // case 8: register a new user with admin auth, but bad userrealname format, expect 400 testUser0002.Email = "testUser0002@mydomain.com" testUser0002.Realname = "test$com" fmt.Println("Register user with admin auth, but bad user realname format") @@ -129,7 +129,7 @@ func TestUsersPost(t *testing.T) { assert.Equal(400, code, "Add user status should be 400") } - //case 9: register a new user with admin auth, but bad user comment, expect 400 + // case 9: register a new user with admin auth, but bad user comment, expect 400 testUser0002.Realname = "testUser0002" testUser0002.Comment = "vmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm" fmt.Println("Register user with admin auth, but user comment length is illegal") @@ -141,7 +141,7 @@ func TestUsersPost(t *testing.T) { assert.Equal(400, code, "Add user status should be 400") } - //case 10: register a new user with admin auth, expect 201 + // case 10: register a new user with admin auth, expect 201 fmt.Println("Register user with admin auth, right parameters") testUser0002.Comment = "test user" code, err = apiTest.UsersPost(testUser0002, *admin) @@ -152,7 +152,7 @@ func TestUsersPost(t *testing.T) { assert.Equal(201, code, "Add user status should be 201") } - //case 11: register duplicate user with admin auth, expect 409 + // case 11: register duplicate user with admin auth, expect 409 fmt.Println("Register duplicate user with admin auth") code, err = apiTest.UsersPost(testUser0002, *admin) if err != nil { @@ -162,7 +162,7 @@ func TestUsersPost(t *testing.T) { assert.Equal(409, code, "Add user status should be 409") } - //case 12: register a new user with admin auth, but duplicate email, expect 409 + // case 12: register a new user with admin auth, but duplicate email, expect 409 fmt.Println("Register user with admin auth, but duplicate email") testUser0002.Username = "testUsertest" testUser0002.Email = "testUser0002@mydomain.com" @@ -182,7 +182,7 @@ func TestUsersGet(t *testing.T) { apiTest := newHarborAPI() testUser0002.Username = "testUser0002" - //case 1: Get user2 with common auth, but no userid in path, expect 403 + // case 1: Get user2 with common auth, but no userid in path, expect 403 testUser0002Auth = &usrInfo{"testUser0002", "testUser0002"} code, users, err := apiTest.UsersGet(testUser0002.Username, *testUser0002Auth) @@ -192,7 +192,7 @@ func TestUsersGet(t *testing.T) { } else { assert.Equal(403, code, "Get users status should be 403") } - //case 2: Get user2 with admin auth, expect 200 + // case 2: Get user2 with admin auth, expect 200 code, users, err = apiTest.UsersGet(testUser0002.Username, *admin) if err != nil { t.Error("Error occurred while get users", err.Error()) @@ -210,7 +210,7 @@ func TestUsersGetByID(t *testing.T) { assert := assert.New(t) apiTest := newHarborAPI() - //case 1: Get user2 with userID and his own auth, expect 200 + // case 1: Get user2 with userID and his own auth, expect 200 code, user, err := apiTest.UsersGetByID(testUser0002.Username, *testUser0002Auth, testUser0002ID) if err != nil { t.Error("Error occurred while get users", err.Error()) @@ -220,7 +220,7 @@ func TestUsersGetByID(t *testing.T) { assert.Equal(testUser0002.Username, user.Username, "Get users username should be equal") assert.Equal(testUser0002.Email, user.Email, "Get users email should be equal") } - //case 2: Get user2 with user3 auth, expect 403 + // case 2: Get user2 with user3 auth, expect 403 testUser0003.Username = "testUser0003" testUser0003.Email = "testUser0003@mydomain.com" testUser0003.Password = "testUser0003" @@ -241,7 +241,7 @@ func TestUsersGetByID(t *testing.T) { } else { assert.Equal(403, code, "Get users status should be 403") } - //case 3: Get user that does not exist with user2 auth, expect 404 not found. + // case 3: Get user that does not exist with user2 auth, expect 404 not found. code, user, err = apiTest.UsersGetByID(testUser0002.Username, *testUser0002Auth, 1000) if err != nil { t.Error("Error occurred while get users", err.Error()) @@ -266,7 +266,7 @@ func TestUsersPut(t *testing.T) { assert := assert.New(t) apiTest := newHarborAPI() var profile apilib.UserProfile - //case 1: change user2 profile with user3 auth + // case 1: change user2 profile with user3 auth code, err := apiTest.UsersPut(testUser0002ID, profile, *testUser0003Auth) if err != nil { t.Error("Error occurred while change user profile", err.Error()) @@ -274,7 +274,7 @@ func TestUsersPut(t *testing.T) { } else { assert.Equal(403, code, "Change user profile status should be 403") } - //case 2: change user2 profile with user2 auth, but bad parameters format. + // case 2: change user2 profile with user2 auth, but bad parameters format. code, err = apiTest.UsersPut(testUser0002ID, profile, *testUser0002Auth) if err != nil { t.Error("Error occurred while change user profile", err.Error()) @@ -282,7 +282,7 @@ func TestUsersPut(t *testing.T) { } else { assert.Equal(400, code, "Change user profile status should be 400") } - //case 3: change user2 profile with user2 auth, but duplicate email. + // case 3: change user2 profile with user2 auth, but duplicate email. profile.Realname = "test user" profile.Email = "testUser0003@mydomain.com" profile.Comment = "change profile" @@ -293,7 +293,7 @@ func TestUsersPut(t *testing.T) { } else { assert.Equal(409, code, "Change user profile status should be 409") } - //case 4: change user2 profile with user2 auth, right parameters format. + // case 4: change user2 profile with user2 auth, right parameters format. profile.Realname = "test user" profile.Email = "testUser0002@vmware.com" profile.Comment = "change profile" @@ -311,7 +311,7 @@ func TestUsersToggleAdminRole(t *testing.T) { fmt.Println("Testing Toggle User Admin Role") assert := assert.New(t) apiTest := newHarborAPI() - //case 1: toggle user2 admin role without admin auth + // case 1: toggle user2 admin role without admin auth code, err := apiTest.UsersToggleAdminRole(testUser0002ID, *testUser0002Auth, true) if err != nil { t.Error("Error occurred while toggle user admin role", err.Error()) @@ -319,7 +319,7 @@ func TestUsersToggleAdminRole(t *testing.T) { } else { assert.Equal(403, code, "Toggle user admin role status should be 403") } - //case 2: toggle user2 admin role with admin auth + // case 2: toggle user2 admin role with admin auth code, err = apiTest.UsersToggleAdminRole(testUser0002ID, *admin, true) if err != nil { t.Error("Error occurred while toggle user admin role", err.Error()) @@ -488,7 +488,7 @@ func TestUsersDelete(t *testing.T) { apiTest := newHarborAPI() t.Log("delete user-case 1") - //case 1:delete user without admin auth + // case 1:delete user without admin auth code, err := apiTest.UsersDelete(testUser0002ID, *testUser0003Auth) if err != nil { t.Error("Error occurred while delete test user", err.Error()) @@ -496,7 +496,7 @@ func TestUsersDelete(t *testing.T) { } else { assert.Equal(403, code, "Delete test user status should be 403") } - //case 2: delete user with admin auth, user2 has already been toggled to admin, but can not delete himself + // case 2: delete user with admin auth, user2 has already been toggled to admin, but can not delete himself t.Log("delete user-case 2") code, err = apiTest.UsersDelete(testUser0002ID, *testUser0002Auth) if err != nil { @@ -505,7 +505,7 @@ func TestUsersDelete(t *testing.T) { } else { assert.Equal(403, code, "Delete test user status should be 403") } - //case 3: delete user with admin auth + // case 3: delete user with admin auth t.Log("delete user-case 3") code, err = apiTest.UsersDelete(testUser0002ID, *admin) if err != nil { @@ -514,7 +514,7 @@ func TestUsersDelete(t *testing.T) { } else { assert.Equal(200, code, "Delete test user status should be 200") } - //delete user3 with admin auth + // delete user3 with admin auth code, err = apiTest.UsersDelete(testUser0003ID, *admin) if err != nil { t.Error("Error occurred while delete test user", err.Error()) diff --git a/src/ui/api/usergroup.go b/src/ui/api/usergroup.go index 59ee20416..d924bf7a6 100644 --- a/src/ui/api/usergroup.go +++ b/src/ui/api/usergroup.go @@ -55,7 +55,7 @@ func (uga *UserGroupAPI) Prepare() { return } uga.id = int(ugid) - //Common user can create/update, only harbor admin can delete user group. + // Common user can create/update, only harbor admin can delete user group. if uga.Ctx.Input.IsDelete() && !uga.SecurityCtx.IsSysAdmin() { uga.HandleForbidden(uga.SecurityCtx.GetUsername()) return @@ -67,8 +67,8 @@ func (uga *UserGroupAPI) Get() { ID := uga.id uga.Data["json"] = make([]models.UserGroup, 0) if ID == 0 { - //user group id not set, return all user group - query := models.UserGroup{GroupType: common.LdapGroupType} //Current query LDAP group only + // user group id not set, return all user group + query := models.UserGroup{GroupType: common.LdapGroupType} // Current query LDAP group only userGroupList, err := group.QueryUserGroup(query) if err != nil { uga.HandleInternalServerError(fmt.Sprintf("Failed to query database for user group list, error: %v", err)) @@ -78,7 +78,7 @@ func (uga *UserGroupAPI) Get() { uga.Data["json"] = userGroupList } } else { - //return a specific user group + // return a specific user group userGroup, err := group.GetUserGroup(ID) if userGroup == nil { uga.HandleNotFound("The user group does not exist.") diff --git a/src/ui/api/usergroup_test.go b/src/ui/api/usergroup_test.go index 5390d5368..fed31f850 100644 --- a/src/ui/api/usergroup_test.go +++ b/src/ui/api/usergroup_test.go @@ -96,7 +96,7 @@ func TestUserGroupAPI_Post(t *testing.T) { defer group.DeleteUserGroup(groupID) cases := []*codeCheckingCase{ - //409 + // 409 { request: &testingRequest{ method: http.MethodPost, @@ -126,7 +126,7 @@ func TestUserGroupAPI_Put(t *testing.T) { t.Errorf("Error occurred when AddUserGroup: %v", err) } cases := []*codeCheckingCase{ - //401 + // 401 { request: &testingRequest{ method: http.MethodPut, @@ -137,7 +137,7 @@ func TestUserGroupAPI_Put(t *testing.T) { }, code: http.StatusUnauthorized, }, - //200 + // 200 { request: &testingRequest{ method: http.MethodPut, diff --git a/src/ui/api/utils.go b/src/ui/api/utils.go index d65cf7c4a..a740bdb47 100644 --- a/src/ui/api/utils.go +++ b/src/ui/api/utils.go @@ -313,8 +313,8 @@ func transformVulnerabilities(layerWithVuln *models.ClairLayerEnvelope) []*model return res } -//Watch the configuration changes. -//Wrap the same method in common utils. +// Watch the configuration changes. +// Wrap the same method in common utils. func watchConfigChanges(cfg map[string]interface{}) error { return notifier.WatchConfigChanges(cfg) } diff --git a/src/ui/auth/authenticator.go b/src/ui/auth/authenticator.go index bde884ae0..9d44958a5 100644 --- a/src/ui/auth/authenticator.go +++ b/src/ui/auth/authenticator.go @@ -43,17 +43,17 @@ var ErrDuplicateLDAPGroup = errors.New("An LDAP user group with same DN already // ErrInvalidLDAPGroupDN ... var ErrInvalidLDAPGroupDN = errors.New("The LDAP group DN is invalid") -//ErrAuth is the type of error to indicate a failed authentication due to user's error. +// ErrAuth is the type of error to indicate a failed authentication due to user's error. type ErrAuth struct { details string } -//Error ... +// Error ... func (ea ErrAuth) Error() string { return fmt.Sprintf("Failed to authenticate user, due to error '%s'", ea.details) } -//NewErrAuth ... +// NewErrAuth ... func NewErrAuth(msg string) ErrAuth { return ErrAuth{details: msg} } @@ -94,12 +94,12 @@ func (d *DefaultAuthenticateHelper) OnBoardUser(u *models.User) error { return errors.New("Not supported") } -//SearchUser - Get user information from account repository +// SearchUser - Get user information from account repository func (d *DefaultAuthenticateHelper) SearchUser(username string) (*models.User, error) { return nil, errors.New("Not supported") } -//PostAuthenticate - Update user information after authenticate, such as OnBoard or sync info etc +// PostAuthenticate - Update user information after authenticate, such as OnBoard or sync info etc func (d *DefaultAuthenticateHelper) PostAuthenticate(u *models.User) error { return nil } diff --git a/src/ui/auth/db/db_test.go b/src/ui/auth/db/db_test.go index 95e32bd88..ecee9e303 100644 --- a/src/ui/auth/db/db_test.go +++ b/src/ui/auth/db/db_test.go @@ -37,7 +37,7 @@ var adminServerTestConfig = map[string]interface{}{ common.PostGreSQLUsername: "postgres", common.PostGreSQLPassword: "root123", common.PostGreSQLDatabase: "registry", - //config.SelfRegistration: true, + // config.SelfRegistration: true, common.LDAPURL: "ldap://127.0.0.1", common.LDAPSearchDN: "cn=admin,dc=example,dc=com", common.LDAPSearchPwd: "admin", @@ -102,7 +102,7 @@ func TestMain(m *testing.M) { } func TestSearchUser(t *testing.T) { - //insert user first + // insert user first user := &models.User{ Username: "existuser", Email: "existuser@placeholder.com", @@ -163,7 +163,7 @@ func TestLdapConnectionTest(t *testing.T) { LdapConnectionTimeout: 10, LdapVerifyCert: false, } - //Test ldap connection under auth_mod is db_auth + // Test ldap connection under auth_mod is db_auth err := ldap.ConnectionTestWithConfig(ldapConfig) if err != nil { t.Fatalf("Failed to test ldap server! error %v", err) diff --git a/src/ui/auth/ldap/ldap.go b/src/ui/auth/ldap/ldap.go index 5f193aabb..dbb76262e 100644 --- a/src/ui/auth/ldap/ldap.go +++ b/src/ui/auth/ldap/ldap.go @@ -86,11 +86,11 @@ func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) { return nil, auth.NewErrAuth(err.Error()) } - //Retrieve ldap related info in login to avoid too many traffic with LDAP server. - //Get group admin dn + // Retrieve ldap related info in login to avoid too many traffic with LDAP server. + // Get group admin dn groupCfg, err := config.LDAPGroupConf() groupAdminDN := strings.TrimSpace(groupCfg.LdapGroupAdminDN) - //Attach user group + // Attach user group for _, groupDN := range ldapUsers[0].GroupDNList { if len(groupAdminDN) > 0 && groupAdminDN == groupDN { @@ -125,13 +125,13 @@ func (l *Auth) OnBoardUser(u *models.User) error { u.Email = u.Username + "@placeholder.com" } } - u.Password = "12345678AbC" //Password is not kept in local db - u.Comment = "from LDAP." //Source is from LDAP + u.Password = "12345678AbC" // Password is not kept in local db + u.Comment = "from LDAP." // Source is from LDAP return dao.OnBoardUser(u) } -//SearchUser -- Search user in ldap +// SearchUser -- Search user in ldap func (l *Auth) SearchUser(username string) (*models.User, error) { var user models.User ldapSession, err := ldapUtils.LoadSystemLdapConfig() @@ -161,7 +161,7 @@ func (l *Auth) SearchUser(username string) (*models.User, error) { return &user, nil } -//SearchGroup -- Search group in ldap authenticator, groupKey is LDAP group DN. +// SearchGroup -- Search group in ldap authenticator, groupKey is LDAP group DN. func (l *Auth) SearchGroup(groupKey string) (*models.UserGroup, error) { if _, err := goldap.ParseDN(groupKey); err != nil { return nil, auth.ErrInvalidLDAPGroupDN @@ -203,7 +203,7 @@ func (l *Auth) OnBoardGroup(u *models.UserGroup, altGroupName string) error { u.GroupName = altGroupName } u.GroupType = common.LdapGroupType - //Check duplicate LDAP DN in usergroup, if usergroup exist, return error + // Check duplicate LDAP DN in usergroup, if usergroup exist, return error userGroupList, err := group.QueryUserGroup(models.UserGroup{LdapGroupDN: u.LdapGroupDN}) if err != nil { return err @@ -214,7 +214,7 @@ func (l *Auth) OnBoardGroup(u *models.UserGroup, altGroupName string) error { return group.OnBoardUserGroup(u, "LdapGroupDN", "GroupType") } -//PostAuthenticate -- If user exist in harbor DB, sync email address, if not exist, call OnBoardUser +// PostAuthenticate -- If user exist in harbor DB, sync email address, if not exist, call OnBoardUser func (l *Auth) PostAuthenticate(u *models.User) error { exist, err := dao.UserExists(*u, "username") @@ -235,7 +235,7 @@ func (l *Auth) PostAuthenticate(u *models.User) error { return nil } u.UserID = dbUser.UserID - //If user has admin role already, do not overwrite by user info in DB. + // If user has admin role already, do not overwrite by user info in DB. u.HasAdminRole = u.HasAdminRole || dbUser.HasAdminRole if dbUser.Email != u.Email { diff --git a/src/ui/auth/ldap/ldap_test.go b/src/ui/auth/ldap/ldap_test.go index 3ade416f5..33026ff4a 100644 --- a/src/ui/auth/ldap/ldap_test.go +++ b/src/ui/auth/ldap/ldap_test.go @@ -15,8 +15,8 @@ package ldap import ( "github.com/stretchr/testify/assert" - //"fmt" - //"strings" + // "fmt" + // "strings" "os" "testing" @@ -41,7 +41,7 @@ var adminServerLdapTestConfig = map[string]interface{}{ common.PostGreSQLUsername: "postgres", common.PostGreSQLPassword: "root123", common.PostGreSQLDatabase: "registry", - //config.SelfRegistration: true, + // config.SelfRegistration: true, common.LDAPURL: "ldap://127.0.0.1", common.LDAPSearchDN: "cn=admin,dc=example,dc=com", common.LDAPSearchPwd: "admin", @@ -109,7 +109,7 @@ func TestMain(m *testing.M) { log.Fatalf("failed to initialize database: %v", err) } - //Extract to test utils + // Extract to test utils initSqls := []string{ "insert into harbor_user (username, email, password, realname) values ('member_test_01', 'member_test_01@example.com', '123456', 'member_test_01')", "insert into project (name, owner_id) values ('member_test_01', 1)", @@ -156,7 +156,7 @@ func TestAuthenticate(t *testing.T) { if _, ok := err.(auth.ErrAuth); !ok { t.Errorf("Expected an ErrAuth on empty credentials, but got: %v", err) } - //authenticate the second time + // authenticate the second time person2 := models.AuthModel{ Principal: "test", Password: "123456", diff --git a/src/ui/auth/uaa/uaa.go b/src/ui/auth/uaa/uaa.go index d9c1b6bf3..5ce771cab 100644 --- a/src/ui/auth/uaa/uaa.go +++ b/src/ui/auth/uaa/uaa.go @@ -36,7 +36,7 @@ type Auth struct { auth.DefaultAuthenticateHelper } -//Authenticate ... +// Authenticate ... func (u *Auth) Authenticate(m models.AuthModel) (*models.User, error) { if err := u.ensureClient(); err != nil { return nil, err @@ -78,7 +78,7 @@ func fillEmailRealName(user *models.User) { user.Realname = user.Username } if len(user.Email) == 0 { - //TODO: handle the case when user.Username itself is an email address. + // TODO: handle the case when user.Username itself is an email address. user.Email = user.Username + "@uaa.placeholder" } } diff --git a/src/ui/auth/uaa/uaa_test.go b/src/ui/auth/uaa/uaa_test.go index 1037e0d2b..a2988333a 100644 --- a/src/ui/auth/uaa/uaa_test.go +++ b/src/ui/auth/uaa/uaa_test.go @@ -132,7 +132,7 @@ func TestPostAuthenticate(t *testing.T) { Username: "test", } err := auth.PostAuthenticate(um) - //need a new user model to simulate a login case... + // need a new user model to simulate a login case... um2 := &models.User{ Username: "test", } @@ -147,7 +147,7 @@ func TestPostAuthenticate(t *testing.T) { user2, _ := dao.GetUser(models.User{Username: "test"}) assert.Equal("newEmail@new.com", user2.Email) assert.Equal("newName", user2.Realname) - //need a new user model to simulate a login case... + // need a new user model to simulate a login case... um3 := &models.User{ Username: "test", } diff --git a/src/ui/config/config.go b/src/ui/config/config.go index 698cf4c34..8bd5a9e70 100644 --- a/src/ui/config/config.go +++ b/src/ui/config/config.go @@ -65,7 +65,7 @@ var ( // Init configurations func Init() error { - //init key provider + // init key provider initKeyProvider() adminServerURL := os.Getenv("ADMINSERVER_URL") if len(adminServerURL) == 0 { @@ -517,7 +517,7 @@ func WithAdmiral() bool { return len(AdmiralEndpoint()) > 0 } -//UAASettings returns the UAASettings to access UAA service. +// UAASettings returns the UAASettings to access UAA service. func UAASettings() (*models.UAASettings, error) { cfg, err := mg.Get() if err != nil { diff --git a/src/ui/controllers/base.go b/src/ui/controllers/base.go index 65d503c23..74f9af6b8 100644 --- a/src/ui/controllers/base.go +++ b/src/ui/controllers/base.go @@ -240,7 +240,7 @@ func isUserResetable(u *models.User) bool { } func init() { - //conf/app.conf -> os.Getenv("config_path") + // conf/app.conf -> os.Getenv("config_path") configPath := os.Getenv("CONFIG_PATH") if len(configPath) != 0 { log.Infof("Config path: %s", configPath) diff --git a/src/ui/controllers/controllers_test.go b/src/ui/controllers/controllers_test.go index 733d34129..517f0ab53 100644 --- a/src/ui/controllers/controllers_test.go +++ b/src/ui/controllers/controllers_test.go @@ -16,7 +16,7 @@ package controllers import ( "net/http" "net/http/httptest" - //"net/url" + // "net/url" "path/filepath" "runtime" "testing" @@ -35,17 +35,17 @@ import ( "github.com/stretchr/testify/assert" ) -//const ( +// const ( // adminName = "admin" // adminPwd = "Harbor12345" -//) +// ) -//type usrInfo struct { +// type usrInfo struct { // Name string // Passwd string -//} +// } -//var admin *usrInfo +// var admin *usrInfo func init() { _, file, _, _ := runtime.Caller(0) @@ -72,8 +72,8 @@ func TestMain(m *testing.M) { if rc != 0 { os.Exit(rc) } - //Init user Info - //admin = &usrInfo{adminName, adminPwd} + // Init user Info + // admin = &usrInfo{adminName, adminPwd} } // TestUserResettable diff --git a/src/ui/controllers/index.go b/src/ui/controllers/index.go index 32ecaf7ff..5adfd0590 100644 --- a/src/ui/controllers/index.go +++ b/src/ui/controllers/index.go @@ -24,7 +24,7 @@ type IndexController struct { beego.Controller } -//Prepare to check if incoming requests should be served +// Prepare to check if incoming requests should be served func (ic *IndexController) Prepare() { if config.WithAdmiral() { ic.Redirect(config.AdmiralEndpoint(), 302) diff --git a/src/ui/filter/mediatype.go b/src/ui/filter/mediatype.go index f01613471..2d4c5616f 100644 --- a/src/ui/filter/mediatype.go +++ b/src/ui/filter/mediatype.go @@ -23,8 +23,8 @@ import ( hlog "github.com/goharbor/harbor/src/common/utils/log" ) -//MediaTypeFilter filters the POST request, it returns 415 if the content type of the request -//doesn't match the preset ones. +// MediaTypeFilter filters the POST request, it returns 415 if the content type of the request +// doesn't match the preset ones. func MediaTypeFilter(mediaType ...string) func(*beegoctx.Context) { return func(ctx *beegoctx.Context) { filterContentType(ctx.Request, ctx.ResponseWriter, mediaType...) diff --git a/src/ui/filter/readonly.go b/src/ui/filter/readonly.go index 5d63a93fd..bafff3e87 100644 --- a/src/ui/filter/readonly.go +++ b/src/ui/filter/readonly.go @@ -29,7 +29,7 @@ const ( labelURL = `^/api/repositories/((?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)+)tags/([\w][\w.-]{0,127})/labels/[0-9]+$` ) -//ReadonlyFilter filters the delete repo/tag request and returns 503. +// ReadonlyFilter filters the delete repo/tag request and returns 503. func ReadonlyFilter(ctx *context.Context) { filter(ctx.Request, ctx.ResponseWriter) } diff --git a/src/ui/filter/security.go b/src/ui/filter/security.go index 8afe0c75a..1a246d07f 100644 --- a/src/ui/filter/security.go +++ b/src/ui/filter/security.go @@ -36,7 +36,7 @@ import ( "github.com/goharbor/harbor/src/ui/promgr/pmsdriver/admiral" ) -//ContextValueKey for content value +// ContextValueKey for content value type ContextValueKey string type pathMethod struct { @@ -45,10 +45,10 @@ type pathMethod struct { } const ( - //SecurCtxKey is context value key for security context + // SecurCtxKey is context value key for security context SecurCtxKey ContextValueKey = "harbor_security_context" - //PmKey is context value key for the project manager + // PmKey is context value key for the project manager PmKey ContextValueKey = "harbor_project_manager" ) diff --git a/src/ui/main.go b/src/ui/main.go index 5a565ba71..1832bb239 100644 --- a/src/ui/main.go +++ b/src/ui/main.go @@ -75,7 +75,7 @@ func updateInitPassword(userID int, password string) error { func main() { beego.BConfig.WebConfig.Session.SessionOn = true - //TODO + // TODO redisURL := os.Getenv("_REDIS_URL") if len(redisURL) > 0 { gob.Register(models.User{}) @@ -106,15 +106,15 @@ func main() { log.Error(err) } - //Init API handler + // Init API handler if err := api.Init(); err != nil { log.Fatalf("Failed to initialize API handlers with error: %s", err.Error()) } - //Enable the policy scheduler here. + // Enable the policy scheduler here. scheduler.DefaultScheduler.Start() - //Subscribe the policy change topic. + // Subscribe the policy change topic. if err = notifier.Subscribe(notifier.ScanAllPolicyTopic, ¬ifier.ScanPolicyNotificationHandler{}); err != nil { log.Errorf("failed to subscribe scan all policy change topic: %v", err) } @@ -127,7 +127,7 @@ func main() { if err := dao.InitClairDB(clairDB); err != nil { log.Fatalf("failed to initialize clair database: %v", err) } - //Get policy configuration. + // Get policy configuration. scanAllPolicy := config.ScanAllPolicy() if scanAllPolicy.Type == notifier.PolicyTypeDaily { dailyTime := 0 @@ -137,7 +137,7 @@ func main() { } } - //Send notification to handle first policy change. + // Send notification to handle first policy change. if err = notifier.Publish(notifier.ScanAllPolicyTopic, notifier.ScanPolicyNotification{Type: scanAllPolicy.Type, DailyTime: (int64)(dailyTime)}); err != nil { log.Errorf("failed to publish scan all policy topic: %v", err) @@ -160,7 +160,7 @@ func main() { sync, err := strconv.ParseBool(syncRegistry) if err != nil { log.Errorf("Failed to parse SYNC_REGISTRY: %v", err) - //if err set it default to false + // if err set it default to false sync = false } if sync { @@ -173,6 +173,6 @@ func main() { log.Info("Init proxy") proxy.Init() - //go proxy.StartProxy() + // go proxy.StartProxy() beego.Run() } diff --git a/src/ui/promgr/pmsdriver/admiral/admiral.go b/src/ui/promgr/pmsdriver/admiral/admiral.go index 12367e7b8..9509732d7 100644 --- a/src/ui/promgr/pmsdriver/admiral/admiral.go +++ b/src/ui/promgr/pmsdriver/admiral/admiral.go @@ -175,7 +175,7 @@ func (d *driver) filter(m map[string]string) ([]*project, error) { // parse the response of GET /projects?xxx to project list func parse(b []byte) ([]*project, error) { documents := &struct { - //DocumentCount int64 `json:"documentCount"` + // DocumentCount int64 `json:"documentCount"` Projects map[string]*project `json:"documents"` }{} if err := json.Unmarshal(b, documents); err != nil { diff --git a/src/ui/promgr/pmsdriver/admiral/admiral_test.go b/src/ui/promgr/pmsdriver/admiral/admiral_test.go index 88c3751e1..0d70328d4 100644 --- a/src/ui/promgr/pmsdriver/admiral/admiral_test.go +++ b/src/ui/promgr/pmsdriver/admiral/admiral_test.go @@ -34,18 +34,18 @@ var ( ) func TestConvert(t *testing.T) { - //nil project + // nil project pro, err := convert(nil) assert.Nil(t, err) assert.Nil(t, pro) - //project without property __projectIndex + // project without property __projectIndex p := &project{} pro, err = convert(p) assert.NotNil(t, err) assert.Nil(t, pro) - //project with invalid __projectIndex + // project with invalid __projectIndex p = &project{ CustomProperties: map[string]string{ "__projectIndex": "invalid_value", @@ -55,7 +55,7 @@ func TestConvert(t *testing.T) { assert.NotNil(t, err) assert.Nil(t, pro) - //project with invalid __enableContentTrust + // project with invalid __enableContentTrust p = &project{ CustomProperties: map[string]string{ "__enableContentTrust": "invalid_value", @@ -65,7 +65,7 @@ func TestConvert(t *testing.T) { assert.NotNil(t, err) assert.Nil(t, pro) - //project with invalid __preventVulnerableImagesFromRunning + // project with invalid __preventVulnerableImagesFromRunning p = &project{ CustomProperties: map[string]string{ "__preventVulnerableImagesFromRunning": "invalid_value", @@ -75,7 +75,7 @@ func TestConvert(t *testing.T) { assert.NotNil(t, err) assert.Nil(t, pro) - //project with invalid __automaticallyScanImagesOnPush + // project with invalid __automaticallyScanImagesOnPush p = &project{ CustomProperties: map[string]string{ "__automaticallyScanImagesOnPush": "invalid_value", @@ -85,7 +85,7 @@ func TestConvert(t *testing.T) { assert.NotNil(t, err) assert.Nil(t, pro) - //valid project + // valid project p = &project{ Name: "test", Public: true, diff --git a/src/ui/promgr/pmsdriver/local/local.go b/src/ui/promgr/pmsdriver/local/local.go index e023b8c08..6b8f159de 100644 --- a/src/ui/promgr/pmsdriver/local/local.go +++ b/src/ui/promgr/pmsdriver/local/local.go @@ -134,7 +134,7 @@ func (d *driver) List(query *models.ProjectQueryParam) (*models.ProjectQueryResu var projects []*models.Project var groupDNCondition string - //List with LDAP group projects + // List with LDAP group projects if query != nil && query.Member != nil { groupDNCondition = group.GetGroupDNQueryCondition(query.Member.GroupList) } diff --git a/src/ui/proxy/interceptor_test.go b/src/ui/proxy/interceptor_test.go index faaf99a84..328b8e7da 100644 --- a/src/ui/proxy/interceptor_test.go +++ b/src/ui/proxy/interceptor_test.go @@ -168,7 +168,7 @@ func TestPMSPolicyChecker(t *testing.T) { func TestMatchNotaryDigest(t *testing.T) { assert := assert.New(t) - //The data from common/utils/notary/helper_test.go + // The data from common/utils/notary/helper_test.go img1 := imageInfo{"notary-demo/busybox", "1.0", "notary-demo", "sha256:1359608115b94599e5641638bac5aef1ddfaa79bb96057ebf41ebc8d33acf8a7"} img2 := imageInfo{"notary-demo/busybox", "2.0", "notary-demo", "sha256:12345678"} diff --git a/src/ui/proxy/interceptors.go b/src/ui/proxy/interceptors.go index 099e49a7e..9e7c91b5b 100644 --- a/src/ui/proxy/interceptors.go +++ b/src/ui/proxy/interceptors.go @@ -27,7 +27,7 @@ const ( manifestURLPattern = `^/v2/((?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)+)manifests/([\w][\w.:-]{0,127})` catalogURLPattern = `/v2/_catalog` imageInfoCtxKey = contextKey("ImageInfo") - //TODO: temp solution, remove after vmware/harbor#2242 is resolved. + // TODO: temp solution, remove after vmware/harbor#2242 is resolved. tokenUsername = "harbor-ui" ) @@ -39,7 +39,7 @@ var NotaryEndpoint = "" // MatchPullManifest checks if the request looks like a request to pull manifest. If it is returns the image and tag/sha256 digest as 2nd and 3rd return values func MatchPullManifest(req *http.Request) (bool, string, string) { - //TODO: add user agent check. + // TODO: add user agent check. if req.Method != http.MethodGet { return false, "", "" } @@ -327,7 +327,7 @@ func matchNotaryDigest(img imageInfo) (bool, error) { return false, nil } -//A sha256 is a string with 64 characters. +// A sha256 is a string with 64 characters. func isDigest(ref string) bool { return strings.HasPrefix(ref, "sha256:") && len(ref) == 71 } diff --git a/src/ui/router.go b/src/ui/router.go index 16ab064ec..a14652736 100644 --- a/src/ui/router.go +++ b/src/ui/router.go @@ -32,21 +32,21 @@ func initRouters() { beego.SetStaticPath("/static", "./static") beego.SetStaticPath("/i18n", "./static/i18n") - //Page Controllers: + // Page Controllers: beego.Router("/", &controllers.IndexController{}) beego.Router("/harbor/*", &controllers.IndexController{}) beego.Router("/reset_password", &controllers.IndexController{}) // standalone if !config.WithAdmiral() { - //Controller API: + // Controller API: beego.Router("/login", &controllers.CommonController{}, "post:Login") beego.Router("/log_out", &controllers.CommonController{}, "get:LogOut") beego.Router("/reset", &controllers.CommonController{}, "post:ResetPassword") beego.Router("/userExists", &controllers.CommonController{}, "post:UserExists") beego.Router("/sendEmail", &controllers.CommonController{}, "get:SendResetEmail") - //API: + // API: beego.Router("/api/projects/:pid([0-9]+)/members/?:pmid([0-9]+)", &api.ProjectMemberAPI{}) beego.Router("/api/projects/", &api.ProjectAPI{}, "head:Head") beego.Router("/api/projects/:id([0-9]+)", &api.ProjectAPI{}) @@ -120,7 +120,7 @@ func initRouters() { beego.Router("/api/internal/syncregistry", &api.InternalAPI{}, "post:SyncRegistry") beego.Router("/api/internal/renameadmin", &api.InternalAPI{}, "post:RenameAdmin") - //external service that hosted on harbor process: + // external service that hosted on harbor process: beego.Router("/service/notifications", ®istry.NotificationHandler{}) beego.Router("/service/notifications/clair", &clair.Handler{}, "post:Handle") beego.Router("/service/notifications/jobs/scan/:id([0-9]+)", &jobs.Handler{}, "post:HandleScan") @@ -130,9 +130,9 @@ func initRouters() { beego.Router("/v2/*", &controllers.RegistryProxy{}, "*:Handle") - //APIs for chart repository + // APIs for chart repository if config.WithChartMuseum() { - //Charts are controlled under projects + // Charts are controlled under projects chartRepositoryAPIType := &api.ChartRepositoryAPI{} beego.Router("/api/chartrepo/health", chartRepositoryAPIType, "get:GetHealthStatus") beego.Router("/api/chartrepo/:repo/charts", chartRepositoryAPIType, "get:ListCharts") @@ -144,13 +144,13 @@ func initRouters() { beego.Router("/api/chartrepo/:repo/prov", chartRepositoryAPIType, "post:UploadChartProvFile") beego.Router("/api/chartrepo/charts", chartRepositoryAPIType, "post:UploadChartVersion") - //Repository services + // Repository services beego.Router("/chartrepo/:repo/index.yaml", chartRepositoryAPIType, "get:GetIndexByRepo") beego.Router("/chartrepo/index.yaml", chartRepositoryAPIType, "get:GetIndex") beego.Router("/chartrepo/:repo/charts/:filename", chartRepositoryAPIType, "get:DownloadChart") } - //Error pages + // Error pages beego.ErrorController(&controllers.ErrorController{}) } diff --git a/src/ui/service/notifications/admin/handler.go b/src/ui/service/notifications/admin/handler.go index 426f0a691..e00774103 100644 --- a/src/ui/service/notifications/admin/handler.go +++ b/src/ui/service/notifications/admin/handler.go @@ -55,7 +55,7 @@ func (h *Handler) Prepare() { id, err := h.GetInt64FromPath(":id") if err != nil { log.Errorf("Failed to get job ID, error: %v", err) - //Avoid job service from resending... + // Avoid job service from resending... h.Abort("200") return } @@ -70,7 +70,7 @@ func (h *Handler) Prepare() { h.status = status } -//HandleAdminJob handles the webhook of admin jobs +// HandleAdminJob handles the webhook of admin jobs func (h *Handler) HandleAdminJob() { log.Infof("received admin job status update event: job-%d, status-%s", h.id, h.status) // create the mapping relationship between the jobs in database and jobservice diff --git a/src/ui/service/notifications/jobs/handler.go b/src/ui/service/notifications/jobs/handler.go index 4aeb442c9..f8ba3f86c 100644 --- a/src/ui/service/notifications/jobs/handler.go +++ b/src/ui/service/notifications/jobs/handler.go @@ -47,7 +47,7 @@ func (h *Handler) Prepare() { id, err := h.GetInt64FromPath(":id") if err != nil { log.Errorf("Failed to get job ID, error: %v", err) - //Avoid job service from resending... + // Avoid job service from resending... h.Abort("200") return } @@ -78,7 +78,7 @@ func (h *Handler) HandleScan() { } } -//HandleReplication handles the webhook of replication job +// HandleReplication handles the webhook of replication job func (h *Handler) HandleReplication() { log.Debugf("received replication job status update event: job-%d, status-%s", h.id, h.status) if err := dao.UpdateRepJobStatus(h.id, h.status); err != nil { diff --git a/src/ui/service/notifications/registry/handler.go b/src/ui/service/notifications/registry/handler.go index ca7a0c736..06778ecd1 100644 --- a/src/ui/service/notifications/registry/handler.go +++ b/src/ui/service/notifications/registry/handler.go @@ -158,7 +158,7 @@ func filterEvents(notification *models.Notification) ([]*models.Event, error) { continue } - //pull and push manifest by docker-client or vic + // pull and push manifest by docker-client or vic if (strings.HasPrefix(event.Request.UserAgent, "docker") || strings.HasPrefix(event.Request.UserAgent, vicPrefix)) && (event.Action == "pull" || event.Action == "push") { events = append(events, &event) @@ -166,7 +166,7 @@ func filterEvents(notification *models.Notification) ([]*models.Event, error) { continue } - //push manifest by docker-client or job-service + // push manifest by docker-client or job-service if strings.ToLower(strings.TrimSpace(event.Request.UserAgent)) == "harbor-registry-client" && event.Action == "push" { events = append(events, &event) log.Debugf("add event to collect: %s", event.ID) diff --git a/src/ui/service/token/authutils.go b/src/ui/service/token/authutils.go index b324c7766..18cb156da 100644 --- a/src/ui/service/token/authutils.go +++ b/src/ui/service/token/authutils.go @@ -79,7 +79,7 @@ func GetResourceActions(scopes []string) []*token.ResourceActions { return res } -//filterAccess iterate a list of resource actions and try to use the filter that matches the resource type to filter the actions. +// filterAccess iterate a list of resource actions and try to use the filter that matches the resource type to filter the actions. func filterAccess(access []*token.ResourceActions, ctx security.Context, pm promgr.ProjectManager, filters map[string]accessFilter) error { var err error @@ -136,7 +136,7 @@ func permToActions(p string) []string { return res } -//make token core +// make token core func makeTokenCore(issuer, subject, audience string, expiration int, access []*token.ResourceActions, signingKey libtrust.PrivateKey) (t *token.Token, expiresIn int, issuedAt *time.Time, err error) { diff --git a/src/ui/service/token/creator.go b/src/ui/service/token/creator.go index fe6ea395f..da102eff7 100644 --- a/src/ui/service/token/creator.go +++ b/src/ui/service/token/creator.go @@ -40,7 +40,7 @@ const ( Registry = "harbor-registry" ) -//InitCreators initialize the token creators for different services +// InitCreators initialize the token creators for different services func InitCreators() { creatorMap = make(map[string]Creator) registryFilterMap = map[string]accessFilter{ @@ -108,7 +108,7 @@ func (e endpointParser) parse(s string) (*image, error) { return parseImg(repo[1]) } -//build Image accepts a string like library/ubuntu:14.04 and build a image struct +// build Image accepts a string like library/ubuntu:14.04 and build a image struct func parseImg(s string) (*image, error) { repo := strings.SplitN(s, "/", 2) if len(repo) < 2 { @@ -135,25 +135,25 @@ type registryFilter struct { func (reg registryFilter) filter(ctx security.Context, pm promgr.ProjectManager, a *token.ResourceActions) error { - //Do not filter if the request is to access registry catalog + // Do not filter if the request is to access registry catalog if a.Name != "catalog" { return fmt.Errorf("Unable to handle, type: %s, name: %s", a.Type, a.Name) } if !ctx.IsSysAdmin() { - //Set the actions to empty is the user is not admin + // Set the actions to empty is the user is not admin a.Actions = []string{} } return nil } -//repositoryFilter filters the access based on Harbor's permission model +// repositoryFilter filters the access based on Harbor's permission model type repositoryFilter struct { parser imageParser } func (rep repositoryFilter) filter(ctx security.Context, pm promgr.ProjectManager, a *token.ResourceActions) error { - //clear action list to assign to new acess element after perm check. + // clear action list to assign to new acess element after perm check. img, err := rep.parser.parse(a.Name) if err != nil { return err diff --git a/src/ui/service/token/token_test.go b/src/ui/service/token/token_test.go index 812c37f5b..154b9a314 100644 --- a/src/ui/service/token/token_test.go +++ b/src/ui/service/token/token_test.go @@ -133,7 +133,7 @@ type harborClaims struct { func TestMakeToken(t *testing.T) { pk, crt := getKeyAndCertPath() - //overwrite the config values for testing. + // overwrite the config values for testing. privateKey = pk ra := []*token.ResourceActions{{ Type: "repository", @@ -147,7 +147,7 @@ func TestMakeToken(t *testing.T) { t.Errorf("Error while making token: %v", err) } tokenString := tokenJSON.Token - //t.Logf("privatekey: %s, crt: %s", tokenString, crt) + // t.Logf("privatekey: %s, crt: %s", tokenString, crt) pubKey, err := getPublicKey(crt) if err != nil { t.Errorf("Error while getting public key from cert: %s", crt) @@ -268,7 +268,7 @@ func (f *fakeSecurityContext) GetProjectRoles(interface{}) []int { } func TestFilterAccess(t *testing.T) { - //TODO put initial data in DB to verify repository filter. + // TODO put initial data in DB to verify repository filter. var err error s := []string{"registry:catalog:*"} a1 := GetResourceActions(s) diff --git a/src/ui/utils/response_handlers.go b/src/ui/utils/response_handlers.go index 5a10e3dce..6f7101d9c 100644 --- a/src/ui/utils/response_handlers.go +++ b/src/ui/utils/response_handlers.go @@ -24,17 +24,17 @@ import ( "github.com/goharbor/harbor/src/common/utils/log" ) -//ResponseHandler provides utility to handle http response. +// ResponseHandler provides utility to handle http response. type ResponseHandler interface { Handle(*http.Response) error } -//StatusRespHandler handles the response to check if the status is expected, if not returns an error. +// StatusRespHandler handles the response to check if the status is expected, if not returns an error. type StatusRespHandler struct { status int } -//Handle ... +// Handle ... func (s StatusRespHandler) Handle(resp *http.Response) error { defer resp.Body.Close() if resp.StatusCode != s.status { @@ -54,12 +54,12 @@ func NewStatusRespHandler(sc int) ResponseHandler { } } -//JobLogRespHandler handles the response from jobservice to show the log of a job +// JobLogRespHandler handles the response from jobservice to show the log of a job type JobLogRespHandler struct { theAPI *api.BaseAPI } -//Handle will consume the response of job service and put the content of the job log in the response of the API. +// Handle will consume the response of job service and put the content of the job log in the response of the API. func (h JobLogRespHandler) Handle(resp *http.Response) error { defer resp.Body.Close() if resp.StatusCode == http.StatusOK { @@ -82,7 +82,7 @@ func (h JobLogRespHandler) Handle(resp *http.Response) error { return nil } -//NewJobLogRespHandler ... +// NewJobLogRespHandler ... func NewJobLogRespHandler(apiHandler *api.BaseAPI) ResponseHandler { return &JobLogRespHandler{ theAPI: apiHandler,