| 
									
										
										
										
											2024-01-23 00:09:08 +08:00
										 |  |  | package api | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2024-03-25 20:30:47 +08:00
										 |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2024-01-23 00:09:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/api/response" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/api/routing" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/infra/log" | 
					
						
							| 
									
										
										
										
											2024-03-25 23:43:28 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/tracing" | 
					
						
							| 
									
										
										
										
											2024-01-23 00:09:08 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/middleware" | 
					
						
							| 
									
										
										
										
											2024-02-26 21:52:16 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/cloudmigration" | 
					
						
							| 
									
										
										
										
											2024-01-23 00:09:08 +08:00
										 |  |  | 	contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/web" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-25 20:30:47 +08:00
										 |  |  | type CloudMigrationAPI struct { | 
					
						
							| 
									
										
										
										
											2024-02-26 21:52:16 +08:00
										 |  |  | 	cloudMigrationsService cloudmigration.Service | 
					
						
							| 
									
										
										
										
											2024-01-23 00:09:08 +08:00
										 |  |  | 	routeRegister          routing.RouteRegister | 
					
						
							|  |  |  | 	log                    log.Logger | 
					
						
							| 
									
										
										
										
											2024-03-25 23:43:28 +08:00
										 |  |  | 	tracer                 tracing.Tracer | 
					
						
							| 
									
										
										
										
											2024-01-23 00:09:08 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func RegisterApi( | 
					
						
							|  |  |  | 	rr routing.RouteRegister, | 
					
						
							| 
									
										
										
										
											2024-02-26 21:52:16 +08:00
										 |  |  | 	cms cloudmigration.Service, | 
					
						
							| 
									
										
										
										
											2024-03-25 23:43:28 +08:00
										 |  |  | 	tracer tracing.Tracer, | 
					
						
							| 
									
										
										
										
											2024-03-25 20:30:47 +08:00
										 |  |  | ) *CloudMigrationAPI { | 
					
						
							|  |  |  | 	api := &CloudMigrationAPI{ | 
					
						
							| 
									
										
										
										
											2024-01-23 00:09:08 +08:00
										 |  |  | 		log:                    log.New("cloudmigrations.api"), | 
					
						
							|  |  |  | 		routeRegister:          rr, | 
					
						
							|  |  |  | 		cloudMigrationsService: cms, | 
					
						
							| 
									
										
										
										
											2024-03-25 23:43:28 +08:00
										 |  |  | 		tracer:                 tracer, | 
					
						
							| 
									
										
										
										
											2024-01-23 00:09:08 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	api.registerEndpoints() | 
					
						
							|  |  |  | 	return api | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RegisterAPIEndpoints Registers Endpoints on Grafana Router
 | 
					
						
							| 
									
										
										
										
											2024-03-25 20:30:47 +08:00
										 |  |  | func (cma *CloudMigrationAPI) registerEndpoints() { | 
					
						
							|  |  |  | 	cma.routeRegister.Group("/api/cloudmigration", func(cloudMigrationRoute routing.RouteRegister) { | 
					
						
							|  |  |  | 		// migration
 | 
					
						
							|  |  |  | 		cloudMigrationRoute.Get("/migration", routing.Wrap(cma.GetMigrationList)) | 
					
						
							|  |  |  | 		cloudMigrationRoute.Post("/migration", routing.Wrap(cma.CreateMigration)) | 
					
						
							|  |  |  | 		cloudMigrationRoute.Get("/migration/:id", routing.Wrap(cma.GetMigration)) | 
					
						
							|  |  |  | 		cloudMigrationRoute.Delete("migration/:id", routing.Wrap(cma.DeleteMigration)) | 
					
						
							|  |  |  | 		cloudMigrationRoute.Post("/migration/:id/run", routing.Wrap(cma.RunMigration)) | 
					
						
							|  |  |  | 		cloudMigrationRoute.Get("/migration/:id/run", routing.Wrap(cma.GetMigrationRunList)) | 
					
						
							|  |  |  | 		cloudMigrationRoute.Get("/migration/:id/run/:runID", routing.Wrap(cma.GetMigrationRun)) | 
					
						
							| 
									
										
										
										
											2024-03-25 23:43:28 +08:00
										 |  |  | 		cloudMigrationRoute.Post("/token", routing.Wrap(cma.CreateToken)) | 
					
						
							| 
									
										
										
										
											2024-01-23 00:09:08 +08:00
										 |  |  | 	}, middleware.ReqGrafanaAdmin) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-02 19:57:42 +08:00
										 |  |  | // swagger:route POST /cloudmigration/token migrations createCloudMigrationToken
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Create gcom access token.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Responses:
 | 
					
						
							|  |  |  | // 200: cloudMigrationCreateTokenResponse
 | 
					
						
							|  |  |  | // 401: unauthorisedError
 | 
					
						
							|  |  |  | // 403: forbiddenError
 | 
					
						
							|  |  |  | // 500: internalServerError
 | 
					
						
							| 
									
										
										
										
											2024-03-25 20:30:47 +08:00
										 |  |  | func (cma *CloudMigrationAPI) CreateToken(c *contextmodel.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2024-03-25 23:43:28 +08:00
										 |  |  | 	ctx, span := cma.tracer.Start(c.Req.Context(), "MigrationAPI.CreateAccessToken") | 
					
						
							|  |  |  | 	defer span.End() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	logger := cma.log.FromContext(ctx) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	resp, err := cma.cloudMigrationsService.CreateToken(ctx) | 
					
						
							| 
									
										
										
										
											2024-03-25 20:30:47 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2024-03-25 23:43:28 +08:00
										 |  |  | 		logger.Error("creating gcom access token", "err", err.Error()) | 
					
						
							|  |  |  | 		return response.Error(http.StatusInternalServerError, "creating gcom access token", err) | 
					
						
							| 
									
										
										
										
											2024-03-25 20:30:47 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-03-25 23:43:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return response.JSON(http.StatusOK, cloudmigration.CreateAccessTokenResponseDTO(resp)) | 
					
						
							| 
									
										
										
										
											2024-03-25 20:30:47 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-02 19:57:42 +08:00
										 |  |  | // swagger:route GET /cloudmigration/migration migrations getMigrationList
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Get a list of all cloud migrations.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Responses:
 | 
					
						
							|  |  |  | // 200: cloudMigrationListResponse
 | 
					
						
							|  |  |  | // 401: unauthorisedError
 | 
					
						
							|  |  |  | // 403: forbiddenError
 | 
					
						
							|  |  |  | // 500: internalServerError
 | 
					
						
							| 
									
										
										
										
											2024-03-25 20:30:47 +08:00
										 |  |  | func (cma *CloudMigrationAPI) GetMigrationList(c *contextmodel.ReqContext) response.Response { | 
					
						
							|  |  |  | 	cloudMigrations, err := cma.cloudMigrationsService.GetMigrationList(c.Req.Context()) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return response.Error(http.StatusInternalServerError, "migration list error", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-04-02 19:57:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-25 20:30:47 +08:00
										 |  |  | 	return response.JSON(http.StatusOK, cloudMigrations) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-02 19:57:42 +08:00
										 |  |  | // swagger:route GET /cloudmigration/migration/{id} migrations getCloudMigration
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Get a cloud migration.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // It returns migrations that has been created.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Responses:
 | 
					
						
							|  |  |  | // 200: cloudMigrationResponse
 | 
					
						
							|  |  |  | // 401: unauthorisedError
 | 
					
						
							|  |  |  | // 403: forbiddenError
 | 
					
						
							|  |  |  | // 500: internalServerError
 | 
					
						
							| 
									
										
										
										
											2024-03-25 20:30:47 +08:00
										 |  |  | func (cma *CloudMigrationAPI) GetMigration(c *contextmodel.ReqContext) response.Response { | 
					
						
							|  |  |  | 	id, err := strconv.ParseInt(web.Params(c.Req)[":id"], 10, 64) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return response.Error(http.StatusBadRequest, "id is invalid", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	cloudMigration, err := cma.cloudMigrationsService.GetMigration(c.Req.Context(), id) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return response.Error(http.StatusNotFound, "migration not found", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return response.JSON(http.StatusOK, cloudMigration) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-02 19:57:42 +08:00
										 |  |  | // swagger:parameters getCloudMigration
 | 
					
						
							|  |  |  | type GetCloudMigrationRequest struct { | 
					
						
							|  |  |  | 	// ID of an migration
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// in: path
 | 
					
						
							|  |  |  | 	ID int64 `json:"id"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // swagger:route POST /cloudmigration/migration migrations createMigration
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Create a migration.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Responses:
 | 
					
						
							|  |  |  | // 200: cloudMigrationResponse
 | 
					
						
							|  |  |  | // 401: unauthorisedError
 | 
					
						
							|  |  |  | // 403: forbiddenError
 | 
					
						
							|  |  |  | // 500: internalServerError
 | 
					
						
							| 
									
										
										
										
											2024-03-25 20:30:47 +08:00
										 |  |  | func (cma *CloudMigrationAPI) CreateMigration(c *contextmodel.ReqContext) response.Response { | 
					
						
							|  |  |  | 	cmd := cloudmigration.CloudMigrationRequest{} | 
					
						
							|  |  |  | 	if err := web.Bind(c.Req, &cmd); err != nil { | 
					
						
							| 
									
										
										
										
											2024-01-23 00:09:08 +08:00
										 |  |  | 		return response.Error(http.StatusBadRequest, "bad request data", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-03-25 20:30:47 +08:00
										 |  |  | 	cloudMigration, err := cma.cloudMigrationsService.CreateMigration(c.Req.Context(), cmd) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return response.Error(http.StatusInternalServerError, "migration creation error", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return response.JSON(http.StatusOK, cloudMigration) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-02 19:57:42 +08:00
										 |  |  | // swagger:route GET /cloudmigration/migration/{id}/run migrations runCloudMigration
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Trigger the run of a migration to the Grafana Cloud.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // It returns migrations that has been created.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Responses:
 | 
					
						
							|  |  |  | // 200: cloudMigrationRunResponse
 | 
					
						
							|  |  |  | // 401: unauthorisedError
 | 
					
						
							|  |  |  | // 403: forbiddenError
 | 
					
						
							|  |  |  | // 500: internalServerError
 | 
					
						
							| 
									
										
										
										
											2024-03-25 20:30:47 +08:00
										 |  |  | func (cma *CloudMigrationAPI) RunMigration(c *contextmodel.ReqContext) response.Response { | 
					
						
							|  |  |  | 	cloudMigrationRun, err := cma.cloudMigrationsService.RunMigration(c.Req.Context(), web.Params(c.Req)[":id"]) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return response.Error(http.StatusInternalServerError, "migration run error", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return response.JSON(http.StatusOK, cloudMigrationRun) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-01-23 00:09:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-02 19:57:42 +08:00
										 |  |  | // swagger:parameters runCloudMigration
 | 
					
						
							|  |  |  | type RunCloudMigrationRequest struct { | 
					
						
							|  |  |  | 	// ID of an migration
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// in: path
 | 
					
						
							|  |  |  | 	ID int64 `json:"id"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // swagger:route GET /cloudmigration/migration/{id}/run/{runID} migrations getCloudMigrationRun
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Get the result of a single migration run.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Responses:
 | 
					
						
							|  |  |  | // 200: cloudMigrationRunResponse
 | 
					
						
							|  |  |  | // 401: unauthorisedError
 | 
					
						
							|  |  |  | // 403: forbiddenError
 | 
					
						
							|  |  |  | // 500: internalServerError
 | 
					
						
							| 
									
										
										
										
											2024-03-25 20:30:47 +08:00
										 |  |  | func (cma *CloudMigrationAPI) GetMigrationRun(c *contextmodel.ReqContext) response.Response { | 
					
						
							|  |  |  | 	migrationStatus, err := cma.cloudMigrationsService.GetMigrationStatus(c.Req.Context(), web.Params(c.Req)[":id"], web.Params(c.Req)[":runID"]) | 
					
						
							| 
									
										
										
										
											2024-01-23 00:09:08 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2024-03-25 20:30:47 +08:00
										 |  |  | 		return response.Error(http.StatusInternalServerError, "migration status error", err) | 
					
						
							| 
									
										
										
										
											2024-01-23 00:09:08 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-03-25 20:30:47 +08:00
										 |  |  | 	return response.JSON(http.StatusOK, migrationStatus) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-01-23 00:09:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-02 19:57:42 +08:00
										 |  |  | // swagger:parameters getCloudMigrationRun
 | 
					
						
							|  |  |  | type GetMigrationRunParams struct { | 
					
						
							|  |  |  | 	// ID of an migration
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// in: path
 | 
					
						
							|  |  |  | 	ID int64 `json:"id"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Run ID of a migration run
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// in: path
 | 
					
						
							|  |  |  | 	RunID int64 `json:"runID"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // swagger:route GET /cloudmigration/migration/{id}/run migrations getCloudMigrationRunList
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Get a list of migration runs for a migration.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Responses:
 | 
					
						
							|  |  |  | // 200: cloudMigrationRunListResponse
 | 
					
						
							|  |  |  | // 401: unauthorisedError
 | 
					
						
							|  |  |  | // 403: forbiddenError
 | 
					
						
							|  |  |  | // 500: internalServerError
 | 
					
						
							| 
									
										
										
										
											2024-03-25 20:30:47 +08:00
										 |  |  | func (cma *CloudMigrationAPI) GetMigrationRunList(c *contextmodel.ReqContext) response.Response { | 
					
						
							|  |  |  | 	migrationStatus, err := cma.cloudMigrationsService.GetMigrationStatusList(c.Req.Context(), web.Params(c.Req)[":id"]) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return response.Error(http.StatusInternalServerError, "migration status error", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-04-02 19:57:42 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	runList := cloudmigration.CloudMigrationRunList{Runs: migrationStatus} | 
					
						
							|  |  |  | 	return response.JSON(http.StatusOK, runList) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // swagger:parameters getCloudMigrationRunList
 | 
					
						
							|  |  |  | type GetCloudMigrationRunList struct { | 
					
						
							|  |  |  | 	// ID of an migration
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// in: path
 | 
					
						
							|  |  |  | 	ID int64 `json:"id"` | 
					
						
							| 
									
										
										
										
											2024-03-25 20:30:47 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-02 19:57:42 +08:00
										 |  |  | // swagger:route DELETE /cloudmigration/migration/{id} migrations deleteCloudMigration
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Delete a migration.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Responses:
 | 
					
						
							|  |  |  | // 200
 | 
					
						
							|  |  |  | // 401: unauthorisedError
 | 
					
						
							|  |  |  | // 403: forbiddenError
 | 
					
						
							|  |  |  | // 500: internalServerError
 | 
					
						
							| 
									
										
										
										
											2024-03-25 20:30:47 +08:00
										 |  |  | func (cma *CloudMigrationAPI) DeleteMigration(c *contextmodel.ReqContext) response.Response { | 
					
						
							|  |  |  | 	err := cma.cloudMigrationsService.DeleteMigration(c.Req.Context(), web.Params(c.Req)[":id"]) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return response.Error(http.StatusInternalServerError, "migration delete error", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return response.Empty(http.StatusOK) | 
					
						
							| 
									
										
										
										
											2024-01-23 00:09:08 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2024-04-02 19:57:42 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // swagger:parameters deleteCloudMigration
 | 
					
						
							|  |  |  | type DeleteMigrationRequest struct { | 
					
						
							|  |  |  | 	// ID of an migration
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// in: path
 | 
					
						
							|  |  |  | 	ID int64 `json:"id"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // swagger:response cloudMigrationRunResponse
 | 
					
						
							|  |  |  | type CloudMigrationRunResponse struct { | 
					
						
							|  |  |  | 	// in: body
 | 
					
						
							|  |  |  | 	Body cloudmigration.CloudMigrationRun | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // swagger:response cloudMigrationListResponse
 | 
					
						
							|  |  |  | type CloudMigrationListResponse struct { | 
					
						
							|  |  |  | 	// in: body
 | 
					
						
							|  |  |  | 	Body cloudmigration.CloudMigrationListResponse | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // swagger:response cloudMigrationResponse
 | 
					
						
							|  |  |  | type CloudMigrationResponse struct { | 
					
						
							|  |  |  | 	// in: body
 | 
					
						
							|  |  |  | 	Body cloudmigration.CloudMigrationResponse | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // swagger:response cloudMigrationRunListResponse
 | 
					
						
							|  |  |  | type CloudMigrationRunListResponse struct { | 
					
						
							|  |  |  | 	// in: body
 | 
					
						
							|  |  |  | 	Body cloudmigration.CloudMigrationRunList | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // swagger:response cloudMigrationCreateTokenResponse
 | 
					
						
							|  |  |  | type CloudMigrationCreateTokenResponse struct { | 
					
						
							|  |  |  | 	// in: body
 | 
					
						
							|  |  |  | 	Body cloudmigration.CreateAccessTokenResponseDTO | 
					
						
							|  |  |  | } |