diff --git a/scaleway-async/scaleway_async/file/v1alpha1/__init__.py b/scaleway-async/scaleway_async/file/v1alpha1/__init__.py index 05c3dbdf6..78ec2e68e 100644 --- a/scaleway-async/scaleway_async/file/v1alpha1/__init__.py +++ b/scaleway-async/scaleway_async/file/v1alpha1/__init__.py @@ -5,12 +5,15 @@ from .content import FILE_SYSTEM_TRANSIENT_STATUSES from .types import ListFileSystemsRequestOrderBy from .types import Attachment +from .types import FileSystemType from .types import FileSystem from .types import CreateFileSystemRequest from .types import DeleteFileSystemRequest from .types import GetFileSystemRequest from .types import ListAttachmentsRequest from .types import ListAttachmentsResponse +from .types import ListFileSystemTypesRequest +from .types import ListFileSystemTypesResponse from .types import ListFileSystemsRequest from .types import ListFileSystemsResponse from .types import UpdateFileSystemRequest @@ -22,12 +25,15 @@ "FILE_SYSTEM_TRANSIENT_STATUSES", "ListFileSystemsRequestOrderBy", "Attachment", + "FileSystemType", "FileSystem", "CreateFileSystemRequest", "DeleteFileSystemRequest", "GetFileSystemRequest", "ListAttachmentsRequest", "ListAttachmentsResponse", + "ListFileSystemTypesRequest", + "ListFileSystemTypesResponse", "ListFileSystemsRequest", "ListFileSystemsResponse", "UpdateFileSystemRequest", diff --git a/scaleway-async/scaleway_async/file/v1alpha1/api.py b/scaleway-async/scaleway_async/file/v1alpha1/api.py index 1123230ef..7a3681b2a 100644 --- a/scaleway-async/scaleway_async/file/v1alpha1/api.py +++ b/scaleway-async/scaleway_async/file/v1alpha1/api.py @@ -20,7 +20,9 @@ Attachment, CreateFileSystemRequest, FileSystem, + FileSystemType, ListAttachmentsResponse, + ListFileSystemTypesResponse, ListFileSystemsResponse, UpdateFileSystemRequest, ) @@ -30,6 +32,7 @@ from .marshalling import ( unmarshal_FileSystem, unmarshal_ListAttachmentsResponse, + unmarshal_ListFileSystemTypesResponse, unmarshal_ListFileSystemsResponse, marshal_CreateFileSystemRequest, marshal_UpdateFileSystemRequest, @@ -41,6 +44,73 @@ class FileV1Alpha1API(API): This API allows you to manage your File Storage resources. """ + async def list_file_system_types( + self, + *, + region: Optional[ScwRegion] = None, + page: Optional[int] = None, + page_size: Optional[int] = None, + ) -> ListFileSystemTypesResponse: + """ + List filesystems types. + :param region: Region to target. If none is passed will use default region from the config. + :param page: Page number (starts at 1). + :param page_size: Number of entries per page (default: 50, max: 100). + :return: :class:`ListFileSystemTypesResponse ` + + Usage: + :: + + result = await api.list_file_system_types() + """ + + param_region = validate_path_param( + "region", region or self.client.default_region + ) + + res = self._request( + "GET", + f"/file/v1alpha1/regions/{param_region}/filesystem-types", + params={ + "page": page, + "page_size": page_size or self.client.default_page_size, + }, + ) + + self._throw_on_error(res) + return unmarshal_ListFileSystemTypesResponse(res.json()) + + async def list_file_system_types_all( + self, + *, + region: Optional[ScwRegion] = None, + page: Optional[int] = None, + page_size: Optional[int] = None, + ) -> list[FileSystemType]: + """ + List filesystems types. + :param region: Region to target. If none is passed will use default region from the config. + :param page: Page number (starts at 1). + :param page_size: Number of entries per page (default: 50, max: 100). + :return: :class:`list[FileSystemType] ` + + Usage: + :: + + result = await api.list_file_system_types_all() + """ + + return await fetch_all_pages_async( + type=ListFileSystemTypesResponse, + key="filesystem_types", + fetcher=self.list_file_system_types, + args={ + "region": region, + "page": page, + "page_size": page_size, + }, + ) + async def get_file_system( self, *, @@ -124,6 +194,7 @@ async def list_file_systems( page: Optional[int] = None, page_size: Optional[int] = None, name: Optional[str] = None, + filesystem_type: Optional[str] = None, tags: Optional[list[str]] = None, filesystem_ids: Optional[list[str]] = None, ) -> ListFileSystemsResponse: @@ -137,6 +208,7 @@ async def list_file_systems( :param page: Page number (starting at 1). :param page_size: Number of entries per page (default: 20, max: 100). :param name: Filter the returned filesystems by their names. + :param filesystem_type: Type of the filesystem. :param tags: Filter by tags. Only filesystems with one or more matching tags will be returned. :param filesystem_ids: Filter by filesystem IDs. Only filesystems with one or more matching IDs will be returned. :return: :class:`ListFileSystemsResponse ` @@ -156,6 +228,7 @@ async def list_file_systems( f"/file/v1alpha1/regions/{param_region}/filesystems", params={ "filesystem_ids": filesystem_ids, + "filesystem_type": filesystem_type, "name": name, "order_by": order_by, "organization_id": organization_id @@ -180,6 +253,7 @@ async def list_file_systems_all( page: Optional[int] = None, page_size: Optional[int] = None, name: Optional[str] = None, + filesystem_type: Optional[str] = None, tags: Optional[list[str]] = None, filesystem_ids: Optional[list[str]] = None, ) -> list[FileSystem]: @@ -193,6 +267,7 @@ async def list_file_systems_all( :param page: Page number (starting at 1). :param page_size: Number of entries per page (default: 20, max: 100). :param name: Filter the returned filesystems by their names. + :param filesystem_type: Type of the filesystem. :param tags: Filter by tags. Only filesystems with one or more matching tags will be returned. :param filesystem_ids: Filter by filesystem IDs. Only filesystems with one or more matching IDs will be returned. :return: :class:`list[FileSystem] ` @@ -215,6 +290,7 @@ async def list_file_systems_all( "page": page, "page_size": page_size, "name": name, + "filesystem_type": filesystem_type, "tags": tags, "filesystem_ids": filesystem_ids, }, @@ -322,6 +398,7 @@ async def create_file_system( size: int, region: Optional[ScwRegion] = None, project_id: Optional[str] = None, + type_: Optional[str] = None, tags: Optional[list[str]] = None, ) -> FileSystem: """ @@ -331,6 +408,7 @@ async def create_file_system( :param size: Must be compliant with the minimum (100 GB) and maximum (10 TB) allowed size. :param region: Region to target. If none is passed will use default region from the config. :param project_id: UUID of the project the filesystem belongs to. + :param type_: Type of the filesystem. :param tags: List of tags assigned to the filesystem. :return: :class:`FileSystem ` @@ -356,6 +434,7 @@ async def create_file_system( size=size, region=region, project_id=project_id, + type_=type_, tags=tags, ), self.client, diff --git a/scaleway-async/scaleway_async/file/v1alpha1/marshalling.py b/scaleway-async/scaleway_async/file/v1alpha1/marshalling.py index b82b7ebd5..580850a01 100644 --- a/scaleway-async/scaleway_async/file/v1alpha1/marshalling.py +++ b/scaleway-async/scaleway_async/file/v1alpha1/marshalling.py @@ -5,12 +5,17 @@ from dateutil import parser from scaleway_core.profile import ProfileDefaults +from scaleway_core.bridge import ( + unmarshal_Money, +) from .types import ( AttachmentResourceType, FileSystemStatus, FileSystem, Attachment, ListAttachmentsResponse, + FileSystemType, + ListFileSystemTypesResponse, ListFileSystemsResponse, CreateFileSystemRequest, UpdateFileSystemRequest, @@ -79,6 +84,12 @@ def unmarshal_FileSystem(data: Any) -> FileSystem: else: args["region"] = None + field = data.get("filesystem_type_id", None) + if field is not None: + args["filesystem_type_id"] = field + else: + args["filesystem_type_id"] = None + field = data.get("created_at", None) if field is not None: args["created_at"] = parser.isoparse(field) if isinstance(field, str) else field @@ -160,6 +171,60 @@ def unmarshal_ListAttachmentsResponse(data: Any) -> ListAttachmentsResponse: return ListAttachmentsResponse(**args) +def unmarshal_FileSystemType(data: Any) -> FileSystemType: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'FileSystemType' failed as data isn't a dictionary." + ) + + args: dict[str, Any] = {} + + field = data.get("name", None) + if field is not None: + args["name"] = field + else: + args["name"] = None + + field = data.get("filesystem_price_gb_per_hour", None) + if field is not None: + args["filesystem_price_gb_per_hour"] = unmarshal_Money(field) + else: + args["filesystem_price_gb_per_hour"] = None + + field = data.get("snapshot_price_gb_per_hour", None) + if field is not None: + args["snapshot_price_gb_per_hour"] = unmarshal_Money(field) + else: + args["snapshot_price_gb_per_hour"] = None + + return FileSystemType(**args) + + +def unmarshal_ListFileSystemTypesResponse(data: Any) -> ListFileSystemTypesResponse: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'ListFileSystemTypesResponse' failed as data isn't a dictionary." + ) + + args: dict[str, Any] = {} + + field = data.get("filesystem_types", None) + if field is not None: + args["filesystem_types"] = ( + [unmarshal_FileSystemType(v) for v in field] if field is not None else None + ) + else: + args["filesystem_types"] = [] + + field = data.get("total_count", None) + if field is not None: + args["total_count"] = field + else: + args["total_count"] = 0 + + return ListFileSystemTypesResponse(**args) + + def unmarshal_ListFileSystemsResponse(data: Any) -> ListFileSystemsResponse: if not isinstance(data, dict): raise TypeError( @@ -202,6 +267,9 @@ def marshal_CreateFileSystemRequest( else: output["project_id"] = defaults.default_project_id + if request.type_ is not None: + output["type"] = request.type_ + if request.tags is not None: output["tags"] = request.tags diff --git a/scaleway-async/scaleway_async/file/v1alpha1/types.py b/scaleway-async/scaleway_async/file/v1alpha1/types.py index 41b2e1bc9..4cd3bd7a7 100644 --- a/scaleway-async/scaleway_async/file/v1alpha1/types.py +++ b/scaleway-async/scaleway_async/file/v1alpha1/types.py @@ -8,6 +8,7 @@ from typing import Optional from scaleway_core.bridge import ( + Money, Region as ScwRegion, Zone as ScwZone, ) @@ -77,6 +78,24 @@ class Attachment: """ +@dataclass +class FileSystemType: + name: str + """ + Filesystem type name. + """ + + filesystem_price_gb_per_hour: Optional[Money] = None + """ + Price of the filesystem billed in GB/hour. + """ + + snapshot_price_gb_per_hour: Optional[Money] = None + """ + Price of the snapshot billed in GB/hour. + """ + + @dataclass class FileSystem: """ @@ -128,6 +147,11 @@ class FileSystem: Region where the filesystem is located. """ + filesystem_type_id: str + """ + UUID of the filesystem type. + """ + created_at: Optional[datetime] = None """ Creation date of the filesystem. @@ -165,6 +189,11 @@ class CreateFileSystemRequest: UUID of the project the filesystem belongs to. """ + type_: Optional[str] = None + """ + Type of the filesystem. + """ + tags: Optional[list[str]] = field(default_factory=list) """ List of tags assigned to the filesystem. @@ -266,6 +295,41 @@ class ListAttachmentsResponse: """ +@dataclass +class ListFileSystemTypesRequest: + """ + Request to list filesystem types with pagination options. + """ + + region: Optional[ScwRegion] = None + """ + Region to target. If none is passed will use default region from the config. + """ + + page: Optional[int] = 0 + """ + Page number (starts at 1). + """ + + page_size: Optional[int] = 0 + """ + Number of entries per page (default: 50, max: 100). + """ + + +@dataclass +class ListFileSystemTypesResponse: + filesystem_types: list[FileSystemType] + """ + Returns paginated list of filesystem-types. + """ + + total_count: int + """ + Total number of file system types. + """ + + @dataclass class ListFileSystemsRequest: """ @@ -309,6 +373,11 @@ class ListFileSystemsRequest: Filter the returned filesystems by their names. """ + filesystem_type: Optional[str] = None + """ + Type of the filesystem. + """ + tags: Optional[list[str]] = field(default_factory=list) """ Filter by tags. Only filesystems with one or more matching tags will be returned. diff --git a/scaleway/scaleway/file/v1alpha1/__init__.py b/scaleway/scaleway/file/v1alpha1/__init__.py index 05c3dbdf6..78ec2e68e 100644 --- a/scaleway/scaleway/file/v1alpha1/__init__.py +++ b/scaleway/scaleway/file/v1alpha1/__init__.py @@ -5,12 +5,15 @@ from .content import FILE_SYSTEM_TRANSIENT_STATUSES from .types import ListFileSystemsRequestOrderBy from .types import Attachment +from .types import FileSystemType from .types import FileSystem from .types import CreateFileSystemRequest from .types import DeleteFileSystemRequest from .types import GetFileSystemRequest from .types import ListAttachmentsRequest from .types import ListAttachmentsResponse +from .types import ListFileSystemTypesRequest +from .types import ListFileSystemTypesResponse from .types import ListFileSystemsRequest from .types import ListFileSystemsResponse from .types import UpdateFileSystemRequest @@ -22,12 +25,15 @@ "FILE_SYSTEM_TRANSIENT_STATUSES", "ListFileSystemsRequestOrderBy", "Attachment", + "FileSystemType", "FileSystem", "CreateFileSystemRequest", "DeleteFileSystemRequest", "GetFileSystemRequest", "ListAttachmentsRequest", "ListAttachmentsResponse", + "ListFileSystemTypesRequest", + "ListFileSystemTypesResponse", "ListFileSystemsRequest", "ListFileSystemsResponse", "UpdateFileSystemRequest", diff --git a/scaleway/scaleway/file/v1alpha1/api.py b/scaleway/scaleway/file/v1alpha1/api.py index f81d63b01..621636e0c 100644 --- a/scaleway/scaleway/file/v1alpha1/api.py +++ b/scaleway/scaleway/file/v1alpha1/api.py @@ -20,7 +20,9 @@ Attachment, CreateFileSystemRequest, FileSystem, + FileSystemType, ListAttachmentsResponse, + ListFileSystemTypesResponse, ListFileSystemsResponse, UpdateFileSystemRequest, ) @@ -30,6 +32,7 @@ from .marshalling import ( unmarshal_FileSystem, unmarshal_ListAttachmentsResponse, + unmarshal_ListFileSystemTypesResponse, unmarshal_ListFileSystemsResponse, marshal_CreateFileSystemRequest, marshal_UpdateFileSystemRequest, @@ -41,6 +44,73 @@ class FileV1Alpha1API(API): This API allows you to manage your File Storage resources. """ + def list_file_system_types( + self, + *, + region: Optional[ScwRegion] = None, + page: Optional[int] = None, + page_size: Optional[int] = None, + ) -> ListFileSystemTypesResponse: + """ + List filesystems types. + :param region: Region to target. If none is passed will use default region from the config. + :param page: Page number (starts at 1). + :param page_size: Number of entries per page (default: 50, max: 100). + :return: :class:`ListFileSystemTypesResponse ` + + Usage: + :: + + result = api.list_file_system_types() + """ + + param_region = validate_path_param( + "region", region or self.client.default_region + ) + + res = self._request( + "GET", + f"/file/v1alpha1/regions/{param_region}/filesystem-types", + params={ + "page": page, + "page_size": page_size or self.client.default_page_size, + }, + ) + + self._throw_on_error(res) + return unmarshal_ListFileSystemTypesResponse(res.json()) + + def list_file_system_types_all( + self, + *, + region: Optional[ScwRegion] = None, + page: Optional[int] = None, + page_size: Optional[int] = None, + ) -> list[FileSystemType]: + """ + List filesystems types. + :param region: Region to target. If none is passed will use default region from the config. + :param page: Page number (starts at 1). + :param page_size: Number of entries per page (default: 50, max: 100). + :return: :class:`list[FileSystemType] ` + + Usage: + :: + + result = api.list_file_system_types_all() + """ + + return fetch_all_pages( + type=ListFileSystemTypesResponse, + key="filesystem_types", + fetcher=self.list_file_system_types, + args={ + "region": region, + "page": page, + "page_size": page_size, + }, + ) + def get_file_system( self, *, @@ -122,6 +192,7 @@ def list_file_systems( page: Optional[int] = None, page_size: Optional[int] = None, name: Optional[str] = None, + filesystem_type: Optional[str] = None, tags: Optional[list[str]] = None, filesystem_ids: Optional[list[str]] = None, ) -> ListFileSystemsResponse: @@ -135,6 +206,7 @@ def list_file_systems( :param page: Page number (starting at 1). :param page_size: Number of entries per page (default: 20, max: 100). :param name: Filter the returned filesystems by their names. + :param filesystem_type: Type of the filesystem. :param tags: Filter by tags. Only filesystems with one or more matching tags will be returned. :param filesystem_ids: Filter by filesystem IDs. Only filesystems with one or more matching IDs will be returned. :return: :class:`ListFileSystemsResponse ` @@ -154,6 +226,7 @@ def list_file_systems( f"/file/v1alpha1/regions/{param_region}/filesystems", params={ "filesystem_ids": filesystem_ids, + "filesystem_type": filesystem_type, "name": name, "order_by": order_by, "organization_id": organization_id @@ -178,6 +251,7 @@ def list_file_systems_all( page: Optional[int] = None, page_size: Optional[int] = None, name: Optional[str] = None, + filesystem_type: Optional[str] = None, tags: Optional[list[str]] = None, filesystem_ids: Optional[list[str]] = None, ) -> list[FileSystem]: @@ -191,6 +265,7 @@ def list_file_systems_all( :param page: Page number (starting at 1). :param page_size: Number of entries per page (default: 20, max: 100). :param name: Filter the returned filesystems by their names. + :param filesystem_type: Type of the filesystem. :param tags: Filter by tags. Only filesystems with one or more matching tags will be returned. :param filesystem_ids: Filter by filesystem IDs. Only filesystems with one or more matching IDs will be returned. :return: :class:`list[FileSystem] ` @@ -213,6 +288,7 @@ def list_file_systems_all( "page": page, "page_size": page_size, "name": name, + "filesystem_type": filesystem_type, "tags": tags, "filesystem_ids": filesystem_ids, }, @@ -320,6 +396,7 @@ def create_file_system( size: int, region: Optional[ScwRegion] = None, project_id: Optional[str] = None, + type_: Optional[str] = None, tags: Optional[list[str]] = None, ) -> FileSystem: """ @@ -329,6 +406,7 @@ def create_file_system( :param size: Must be compliant with the minimum (100 GB) and maximum (10 TB) allowed size. :param region: Region to target. If none is passed will use default region from the config. :param project_id: UUID of the project the filesystem belongs to. + :param type_: Type of the filesystem. :param tags: List of tags assigned to the filesystem. :return: :class:`FileSystem ` @@ -354,6 +432,7 @@ def create_file_system( size=size, region=region, project_id=project_id, + type_=type_, tags=tags, ), self.client, diff --git a/scaleway/scaleway/file/v1alpha1/marshalling.py b/scaleway/scaleway/file/v1alpha1/marshalling.py index b82b7ebd5..580850a01 100644 --- a/scaleway/scaleway/file/v1alpha1/marshalling.py +++ b/scaleway/scaleway/file/v1alpha1/marshalling.py @@ -5,12 +5,17 @@ from dateutil import parser from scaleway_core.profile import ProfileDefaults +from scaleway_core.bridge import ( + unmarshal_Money, +) from .types import ( AttachmentResourceType, FileSystemStatus, FileSystem, Attachment, ListAttachmentsResponse, + FileSystemType, + ListFileSystemTypesResponse, ListFileSystemsResponse, CreateFileSystemRequest, UpdateFileSystemRequest, @@ -79,6 +84,12 @@ def unmarshal_FileSystem(data: Any) -> FileSystem: else: args["region"] = None + field = data.get("filesystem_type_id", None) + if field is not None: + args["filesystem_type_id"] = field + else: + args["filesystem_type_id"] = None + field = data.get("created_at", None) if field is not None: args["created_at"] = parser.isoparse(field) if isinstance(field, str) else field @@ -160,6 +171,60 @@ def unmarshal_ListAttachmentsResponse(data: Any) -> ListAttachmentsResponse: return ListAttachmentsResponse(**args) +def unmarshal_FileSystemType(data: Any) -> FileSystemType: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'FileSystemType' failed as data isn't a dictionary." + ) + + args: dict[str, Any] = {} + + field = data.get("name", None) + if field is not None: + args["name"] = field + else: + args["name"] = None + + field = data.get("filesystem_price_gb_per_hour", None) + if field is not None: + args["filesystem_price_gb_per_hour"] = unmarshal_Money(field) + else: + args["filesystem_price_gb_per_hour"] = None + + field = data.get("snapshot_price_gb_per_hour", None) + if field is not None: + args["snapshot_price_gb_per_hour"] = unmarshal_Money(field) + else: + args["snapshot_price_gb_per_hour"] = None + + return FileSystemType(**args) + + +def unmarshal_ListFileSystemTypesResponse(data: Any) -> ListFileSystemTypesResponse: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'ListFileSystemTypesResponse' failed as data isn't a dictionary." + ) + + args: dict[str, Any] = {} + + field = data.get("filesystem_types", None) + if field is not None: + args["filesystem_types"] = ( + [unmarshal_FileSystemType(v) for v in field] if field is not None else None + ) + else: + args["filesystem_types"] = [] + + field = data.get("total_count", None) + if field is not None: + args["total_count"] = field + else: + args["total_count"] = 0 + + return ListFileSystemTypesResponse(**args) + + def unmarshal_ListFileSystemsResponse(data: Any) -> ListFileSystemsResponse: if not isinstance(data, dict): raise TypeError( @@ -202,6 +267,9 @@ def marshal_CreateFileSystemRequest( else: output["project_id"] = defaults.default_project_id + if request.type_ is not None: + output["type"] = request.type_ + if request.tags is not None: output["tags"] = request.tags diff --git a/scaleway/scaleway/file/v1alpha1/types.py b/scaleway/scaleway/file/v1alpha1/types.py index 41b2e1bc9..4cd3bd7a7 100644 --- a/scaleway/scaleway/file/v1alpha1/types.py +++ b/scaleway/scaleway/file/v1alpha1/types.py @@ -8,6 +8,7 @@ from typing import Optional from scaleway_core.bridge import ( + Money, Region as ScwRegion, Zone as ScwZone, ) @@ -77,6 +78,24 @@ class Attachment: """ +@dataclass +class FileSystemType: + name: str + """ + Filesystem type name. + """ + + filesystem_price_gb_per_hour: Optional[Money] = None + """ + Price of the filesystem billed in GB/hour. + """ + + snapshot_price_gb_per_hour: Optional[Money] = None + """ + Price of the snapshot billed in GB/hour. + """ + + @dataclass class FileSystem: """ @@ -128,6 +147,11 @@ class FileSystem: Region where the filesystem is located. """ + filesystem_type_id: str + """ + UUID of the filesystem type. + """ + created_at: Optional[datetime] = None """ Creation date of the filesystem. @@ -165,6 +189,11 @@ class CreateFileSystemRequest: UUID of the project the filesystem belongs to. """ + type_: Optional[str] = None + """ + Type of the filesystem. + """ + tags: Optional[list[str]] = field(default_factory=list) """ List of tags assigned to the filesystem. @@ -266,6 +295,41 @@ class ListAttachmentsResponse: """ +@dataclass +class ListFileSystemTypesRequest: + """ + Request to list filesystem types with pagination options. + """ + + region: Optional[ScwRegion] = None + """ + Region to target. If none is passed will use default region from the config. + """ + + page: Optional[int] = 0 + """ + Page number (starts at 1). + """ + + page_size: Optional[int] = 0 + """ + Number of entries per page (default: 50, max: 100). + """ + + +@dataclass +class ListFileSystemTypesResponse: + filesystem_types: list[FileSystemType] + """ + Returns paginated list of filesystem-types. + """ + + total_count: int + """ + Total number of file system types. + """ + + @dataclass class ListFileSystemsRequest: """ @@ -309,6 +373,11 @@ class ListFileSystemsRequest: Filter the returned filesystems by their names. """ + filesystem_type: Optional[str] = None + """ + Type of the filesystem. + """ + tags: Optional[list[str]] = field(default_factory=list) """ Filter by tags. Only filesystems with one or more matching tags will be returned.