From 18db8efa0c4f9d829da34f7a7fcde5c7ba8d81bd Mon Sep 17 00:00:00 2001 From: Craig Labenz Date: Fri, 12 Mar 2021 12:39:03 -0800 Subject: [PATCH] feat: adds synthed bundle protos --- .../firestore_admin_v1/types/__init__.py | 40 ++-- google/cloud/firestore_bundle/__init__.py | 31 +++ google/cloud/firestore_bundle/py.typed | 2 + .../firestore_bundle/services/__init__.py | 16 ++ .../cloud/firestore_bundle/types/__init__.py | 32 +++ google/cloud/firestore_bundle/types/bundle.py | 185 ++++++++++++++++++ google/cloud/firestore_v1/types/__init__.py | 116 +++++------ synth.metadata | 130 ++---------- synth.py | 29 +++ tests/unit/gapic/bundle/__init__.py | 16 ++ 10 files changed, 400 insertions(+), 197 deletions(-) create mode 100644 google/cloud/firestore_bundle/__init__.py create mode 100644 google/cloud/firestore_bundle/py.typed create mode 100644 google/cloud/firestore_bundle/services/__init__.py create mode 100644 google/cloud/firestore_bundle/types/__init__.py create mode 100644 google/cloud/firestore_bundle/types/bundle.py create mode 100644 tests/unit/gapic/bundle/__init__.py diff --git a/google/cloud/firestore_admin_v1/types/__init__.py b/google/cloud/firestore_admin_v1/types/__init__.py index f6838c624..c9de31fe5 100644 --- a/google/cloud/firestore_admin_v1/types/__init__.py +++ b/google/cloud/firestore_admin_v1/types/__init__.py @@ -15,52 +15,52 @@ # limitations under the License. # +from .index import Index from .field import Field from .firestore_admin import ( CreateIndexRequest, + ListIndexesRequest, + ListIndexesResponse, + GetIndexRequest, DeleteIndexRequest, - ExportDocumentsRequest, + UpdateFieldRequest, GetFieldRequest, - GetIndexRequest, - ImportDocumentsRequest, ListFieldsRequest, ListFieldsResponse, - ListIndexesRequest, - ListIndexesResponse, - UpdateFieldRequest, + ExportDocumentsRequest, + ImportDocumentsRequest, ) -from .index import Index from .location import LocationMetadata from .operation import ( - ExportDocumentsMetadata, - ExportDocumentsResponse, + IndexOperationMetadata, FieldOperationMetadata, + ExportDocumentsMetadata, ImportDocumentsMetadata, - IndexOperationMetadata, + ExportDocumentsResponse, Progress, OperationState, ) __all__ = ( + "Index", "Field", "CreateIndexRequest", + "ListIndexesRequest", + "ListIndexesResponse", + "GetIndexRequest", "DeleteIndexRequest", - "ExportDocumentsRequest", + "UpdateFieldRequest", "GetFieldRequest", - "GetIndexRequest", - "ImportDocumentsRequest", "ListFieldsRequest", "ListFieldsResponse", - "ListIndexesRequest", - "ListIndexesResponse", - "UpdateFieldRequest", - "Index", + "ExportDocumentsRequest", + "ImportDocumentsRequest", "LocationMetadata", - "ExportDocumentsMetadata", - "ExportDocumentsResponse", + "IndexOperationMetadata", "FieldOperationMetadata", + "ExportDocumentsMetadata", "ImportDocumentsMetadata", - "IndexOperationMetadata", + "ExportDocumentsResponse", "Progress", "OperationState", ) diff --git a/google/cloud/firestore_bundle/__init__.py b/google/cloud/firestore_bundle/__init__.py new file mode 100644 index 000000000..75cf63e02 --- /dev/null +++ b/google/cloud/firestore_bundle/__init__.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- + +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. +# + +from .types.bundle import BundleElement +from .types.bundle import BundleMetadata +from .types.bundle import BundledDocumentMetadata +from .types.bundle import BundledQuery +from .types.bundle import NamedQuery + + +__all__ = ( + "BundleElement", + "BundleMetadata", + "BundledDocumentMetadata", + "NamedQuery", + "BundledQuery", +) diff --git a/google/cloud/firestore_bundle/py.typed b/google/cloud/firestore_bundle/py.typed new file mode 100644 index 000000000..e2987f296 --- /dev/null +++ b/google/cloud/firestore_bundle/py.typed @@ -0,0 +1,2 @@ +# Marker file for PEP 561. +# The google-cloud-bundle package uses inline types. diff --git a/google/cloud/firestore_bundle/services/__init__.py b/google/cloud/firestore_bundle/services/__init__.py new file mode 100644 index 000000000..42ffdf2bc --- /dev/null +++ b/google/cloud/firestore_bundle/services/__init__.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. +# diff --git a/google/cloud/firestore_bundle/types/__init__.py b/google/cloud/firestore_bundle/types/__init__.py new file mode 100644 index 000000000..c5aae3259 --- /dev/null +++ b/google/cloud/firestore_bundle/types/__init__.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- + +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. +# + +from .bundle import ( + BundledQuery, + NamedQuery, + BundledDocumentMetadata, + BundleMetadata, + BundleElement, +) + +__all__ = ( + "BundledQuery", + "NamedQuery", + "BundledDocumentMetadata", + "BundleMetadata", + "BundleElement", +) diff --git a/google/cloud/firestore_bundle/types/bundle.py b/google/cloud/firestore_bundle/types/bundle.py new file mode 100644 index 000000000..3d78bfe00 --- /dev/null +++ b/google/cloud/firestore_bundle/types/bundle.py @@ -0,0 +1,185 @@ +# -*- coding: utf-8 -*- + +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. +# + +import proto # type: ignore + + +from google.cloud.firestore_v1.types import document as gfv_document +from google.cloud.firestore_v1.types import query +from google.protobuf import timestamp_pb2 as timestamp # type: ignore + + +__protobuf__ = proto.module( + package="google.firestore.bundle", + manifest={ + "BundledQuery", + "NamedQuery", + "BundledDocumentMetadata", + "BundleMetadata", + "BundleElement", + }, +) + + +class BundledQuery(proto.Message): + r"""Encodes a query saved in the bundle. + + Attributes: + parent (str): + The parent resource name. + structured_query (google.firestore.v1.query_pb2.StructuredQuery): + A structured query. + limit_type (google.cloud.bundle.types.BundledQuery.LimitType): + + """ + + class LimitType(proto.Enum): + r"""If the query is a limit query, should the limit be applied to + the beginning or the end of results. + """ + FIRST = 0 + LAST = 1 + + parent = proto.Field(proto.STRING, number=1) + + structured_query = proto.Field( + proto.MESSAGE, number=2, oneof="query_type", message=query.StructuredQuery, + ) + + limit_type = proto.Field(proto.ENUM, number=3, enum=LimitType,) + + +class NamedQuery(proto.Message): + r"""A Query associated with a name, created as part of the bundle + file, and can be read by client SDKs once the bundle containing + them is loaded. + + Attributes: + name (str): + Name of the query, such that client can use + the name to load this query from bundle, and + resume from when the query results are + materialized into this bundle. + bundled_query (google.cloud.bundle.types.BundledQuery): + The query saved in the bundle. + read_time (google.protobuf.timestamp_pb2.Timestamp): + The read time of the query, when it is used + to build the bundle. This is useful to resume + the query from the bundle, once it is loaded by + client SDKs. + """ + + name = proto.Field(proto.STRING, number=1) + + bundled_query = proto.Field(proto.MESSAGE, number=2, message="BundledQuery",) + + read_time = proto.Field(proto.MESSAGE, number=3, message=timestamp.Timestamp,) + + +class BundledDocumentMetadata(proto.Message): + r"""Metadata describing a Firestore document saved in the bundle. + + Attributes: + name (str): + The document key of a bundled document. + read_time (google.protobuf.timestamp_pb2.Timestamp): + The snapshot version of the document data + bundled. + exists (bool): + Whether the document exists. + queries (Sequence[str]): + The names of the queries in this bundle that + this document matches to. + """ + + name = proto.Field(proto.STRING, number=1) + + read_time = proto.Field(proto.MESSAGE, number=2, message=timestamp.Timestamp,) + + exists = proto.Field(proto.BOOL, number=3) + + queries = proto.RepeatedField(proto.STRING, number=4) + + +class BundleMetadata(proto.Message): + r"""Metadata describing the bundle file/stream. + + Attributes: + id (str): + The ID of the bundle. + create_time (google.protobuf.timestamp_pb2.Timestamp): + Time at which the documents snapshot is taken + for this bundle. + version (int): + The schema version of the bundle. + total_documents (int): + The number of documents in the bundle. + total_bytes (int): + The size of the bundle in bytes, excluding this + ``BundleMetadata``. + """ + + id = proto.Field(proto.STRING, number=1) + + create_time = proto.Field(proto.MESSAGE, number=2, message=timestamp.Timestamp,) + + version = proto.Field(proto.UINT32, number=3) + + total_documents = proto.Field(proto.UINT32, number=4) + + total_bytes = proto.Field(proto.UINT64, number=5) + + +class BundleElement(proto.Message): + r"""A Firestore bundle is a length-prefixed stream of JSON + representations of ``BundleElement``. Only one ``BundleMetadata`` is + expected, and it should be the first element. The named queries + follow after ``metadata``. Every ``document_metadata`` is + immediately followed by a ``document``. + + Attributes: + metadata (google.cloud.bundle.types.BundleMetadata): + + named_query (google.cloud.bundle.types.NamedQuery): + + document_metadata (google.cloud.bundle.types.BundledDocumentMetadata): + + document (google.firestore.v1.document_pb2.Document): + + """ + + metadata = proto.Field( + proto.MESSAGE, number=1, oneof="element_type", message="BundleMetadata", + ) + + named_query = proto.Field( + proto.MESSAGE, number=2, oneof="element_type", message="NamedQuery", + ) + + document_metadata = proto.Field( + proto.MESSAGE, + number=3, + oneof="element_type", + message="BundledDocumentMetadata", + ) + + document = proto.Field( + proto.MESSAGE, number=4, oneof="element_type", message=gfv_document.Document, + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/google/cloud/firestore_v1/types/__init__.py b/google/cloud/firestore_v1/types/__init__.py index a353384a9..00070044a 100644 --- a/google/cloud/firestore_v1/types/__init__.py +++ b/google/cloud/firestore_v1/types/__init__.py @@ -21,96 +21,96 @@ TransactionOptions, ) from .document import ( - ArrayValue, Document, - MapValue, Value, + ArrayValue, + MapValue, +) +from .query import ( + StructuredQuery, + Cursor, +) +from .write import ( + Write, + DocumentTransform, + WriteResult, + DocumentChange, + DocumentDelete, + DocumentRemove, + ExistenceFilter, ) from .firestore import ( + GetDocumentRequest, + ListDocumentsRequest, + ListDocumentsResponse, + CreateDocumentRequest, + UpdateDocumentRequest, + DeleteDocumentRequest, BatchGetDocumentsRequest, BatchGetDocumentsResponse, - BatchWriteRequest, - BatchWriteResponse, BeginTransactionRequest, BeginTransactionResponse, CommitRequest, CommitResponse, - CreateDocumentRequest, - DeleteDocumentRequest, - GetDocumentRequest, - ListCollectionIdsRequest, - ListCollectionIdsResponse, - ListDocumentsRequest, - ListDocumentsResponse, - ListenRequest, - ListenResponse, - PartitionQueryRequest, - PartitionQueryResponse, RollbackRequest, RunQueryRequest, RunQueryResponse, - Target, - TargetChange, - UpdateDocumentRequest, + PartitionQueryRequest, + PartitionQueryResponse, WriteRequest, WriteResponse, -) -from .query import ( - Cursor, - StructuredQuery, -) -from .write import ( - DocumentChange, - DocumentDelete, - DocumentRemove, - DocumentTransform, - ExistenceFilter, - Write, - WriteResult, + ListenRequest, + ListenResponse, + Target, + TargetChange, + ListCollectionIdsRequest, + ListCollectionIdsResponse, + BatchWriteRequest, + BatchWriteResponse, ) __all__ = ( "DocumentMask", "Precondition", "TransactionOptions", - "ArrayValue", "Document", - "MapValue", "Value", + "ArrayValue", + "MapValue", + "StructuredQuery", + "Cursor", + "Write", + "DocumentTransform", + "WriteResult", + "DocumentChange", + "DocumentDelete", + "DocumentRemove", + "ExistenceFilter", + "GetDocumentRequest", + "ListDocumentsRequest", + "ListDocumentsResponse", + "CreateDocumentRequest", + "UpdateDocumentRequest", + "DeleteDocumentRequest", "BatchGetDocumentsRequest", "BatchGetDocumentsResponse", - "BatchWriteRequest", - "BatchWriteResponse", "BeginTransactionRequest", "BeginTransactionResponse", "CommitRequest", "CommitResponse", - "CreateDocumentRequest", - "DeleteDocumentRequest", - "GetDocumentRequest", - "ListCollectionIdsRequest", - "ListCollectionIdsResponse", - "ListDocumentsRequest", - "ListDocumentsResponse", - "ListenRequest", - "ListenResponse", - "PartitionQueryRequest", - "PartitionQueryResponse", "RollbackRequest", "RunQueryRequest", "RunQueryResponse", - "Target", - "TargetChange", - "UpdateDocumentRequest", + "PartitionQueryRequest", + "PartitionQueryResponse", "WriteRequest", "WriteResponse", - "Cursor", - "StructuredQuery", - "DocumentChange", - "DocumentDelete", - "DocumentRemove", - "DocumentTransform", - "ExistenceFilter", - "Write", - "WriteResult", + "ListenRequest", + "ListenResponse", + "Target", + "TargetChange", + "ListCollectionIdsRequest", + "ListCollectionIdsResponse", + "BatchWriteRequest", + "BatchWriteResponse", ) diff --git a/synth.metadata b/synth.metadata index 974df0da6..4284d0e6c 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,22 +4,14 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/python-firestore.git", - "sha": "afeaa77884c9a79cb87aac566767faaa71a866bc" - } - }, - { - "git": { - "name": "googleapis", - "remote": "https://github.com/googleapis/googleapis.git", - "sha": "28a591963253d52ce3a25a918cafbdd9928de8cf", - "internalRef": "361662015" + "sha": "db9b355e6d86ac024a7af80443c69d43674e9399" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "0780323da96d5a53925fe0547757181fe76e8f1e" + "sha": "ac8f20f12e7a4c0b0ae1c6fa415f684a25ea82b7" } } ], @@ -41,115 +33,15 @@ "language": "python", "generator": "bazel" } + }, + { + "client": { + "source": "googleapis", + "apiName": "firestore-bundle", + "apiVersion": "v1", + "language": "python", + "generator": "bazel" + } } - ], - "generatedFiles": [ - ".coveragerc", - ".flake8", - ".github/CONTRIBUTING.md", - ".github/ISSUE_TEMPLATE/bug_report.md", - ".github/ISSUE_TEMPLATE/feature_request.md", - ".github/ISSUE_TEMPLATE/support_request.md", - ".github/PULL_REQUEST_TEMPLATE.md", - ".github/header-checker-lint.yml", - ".github/release-please.yml", - ".github/snippet-bot.yml", - ".gitignore", - ".kokoro/build.sh", - ".kokoro/continuous/common.cfg", - ".kokoro/continuous/continuous.cfg", - ".kokoro/docker/docs/Dockerfile", - ".kokoro/docker/docs/fetch_gpg_keys.sh", - ".kokoro/docs/common.cfg", - ".kokoro/docs/docs-presubmit.cfg", - ".kokoro/docs/docs.cfg", - ".kokoro/populate-secrets.sh", - ".kokoro/presubmit/common.cfg", - ".kokoro/presubmit/presubmit.cfg", - ".kokoro/publish-docs.sh", - ".kokoro/release.sh", - ".kokoro/release/common.cfg", - ".kokoro/release/release.cfg", - ".kokoro/samples/lint/common.cfg", - ".kokoro/samples/lint/continuous.cfg", - ".kokoro/samples/lint/periodic.cfg", - ".kokoro/samples/lint/presubmit.cfg", - ".kokoro/samples/python3.6/common.cfg", - ".kokoro/samples/python3.6/continuous.cfg", - ".kokoro/samples/python3.6/periodic.cfg", - ".kokoro/samples/python3.6/presubmit.cfg", - ".kokoro/samples/python3.7/common.cfg", - ".kokoro/samples/python3.7/continuous.cfg", - ".kokoro/samples/python3.7/periodic.cfg", - ".kokoro/samples/python3.7/presubmit.cfg", - ".kokoro/samples/python3.8/common.cfg", - ".kokoro/samples/python3.8/continuous.cfg", - ".kokoro/samples/python3.8/periodic.cfg", - ".kokoro/samples/python3.8/presubmit.cfg", - ".kokoro/test-samples.sh", - ".kokoro/trampoline.sh", - ".kokoro/trampoline_v2.sh", - ".pre-commit-config.yaml", - ".trampolinerc", - "CODE_OF_CONDUCT.md", - "CONTRIBUTING.rst", - "LICENSE", - "MANIFEST.in", - "docs/_static/custom.css", - "docs/_templates/layout.html", - "docs/conf.py", - "docs/multiprocessing.rst", - "google/cloud/firestore_admin_v1/__init__.py", - "google/cloud/firestore_admin_v1/py.typed", - "google/cloud/firestore_admin_v1/services/__init__.py", - "google/cloud/firestore_admin_v1/services/firestore_admin/__init__.py", - "google/cloud/firestore_admin_v1/services/firestore_admin/async_client.py", - "google/cloud/firestore_admin_v1/services/firestore_admin/client.py", - "google/cloud/firestore_admin_v1/services/firestore_admin/pagers.py", - "google/cloud/firestore_admin_v1/services/firestore_admin/transports/__init__.py", - "google/cloud/firestore_admin_v1/services/firestore_admin/transports/base.py", - "google/cloud/firestore_admin_v1/services/firestore_admin/transports/grpc.py", - "google/cloud/firestore_admin_v1/services/firestore_admin/transports/grpc_asyncio.py", - "google/cloud/firestore_admin_v1/types/__init__.py", - "google/cloud/firestore_admin_v1/types/field.py", - "google/cloud/firestore_admin_v1/types/firestore_admin.py", - "google/cloud/firestore_admin_v1/types/index.py", - "google/cloud/firestore_admin_v1/types/location.py", - "google/cloud/firestore_admin_v1/types/operation.py", - "google/cloud/firestore_v1/py.typed", - "google/cloud/firestore_v1/services/__init__.py", - "google/cloud/firestore_v1/services/firestore/__init__.py", - "google/cloud/firestore_v1/services/firestore/async_client.py", - "google/cloud/firestore_v1/services/firestore/client.py", - "google/cloud/firestore_v1/services/firestore/pagers.py", - "google/cloud/firestore_v1/services/firestore/transports/__init__.py", - "google/cloud/firestore_v1/services/firestore/transports/base.py", - "google/cloud/firestore_v1/services/firestore/transports/grpc.py", - "google/cloud/firestore_v1/services/firestore/transports/grpc_asyncio.py", - "google/cloud/firestore_v1/types/__init__.py", - "google/cloud/firestore_v1/types/common.py", - "google/cloud/firestore_v1/types/document.py", - "google/cloud/firestore_v1/types/firestore.py", - "google/cloud/firestore_v1/types/query.py", - "google/cloud/firestore_v1/types/write.py", - "noxfile.py", - "renovate.json", - "samples/AUTHORING_GUIDE.md", - "samples/CONTRIBUTING.md", - "scripts/decrypt-secrets.sh", - "scripts/fixup_firestore_admin_v1_keywords.py", - "scripts/fixup_firestore_v1_keywords.py", - "scripts/readme-gen/readme_gen.py", - "scripts/readme-gen/templates/README.tmpl.rst", - "scripts/readme-gen/templates/auth.tmpl.rst", - "scripts/readme-gen/templates/auth_api_key.tmpl.rst", - "scripts/readme-gen/templates/install_deps.tmpl.rst", - "scripts/readme-gen/templates/install_portaudio.tmpl.rst", - "setup.cfg", - "testing/.gitignore", - "tests/unit/gapic/firestore_admin_v1/__init__.py", - "tests/unit/gapic/firestore_admin_v1/test_firestore_admin.py", - "tests/unit/gapic/firestore_v1/__init__.py", - "tests/unit/gapic/firestore_v1/test_firestore.py" ] } \ No newline at end of file diff --git a/synth.py b/synth.py index 872c2709f..e5626d223 100644 --- a/synth.py +++ b/synth.py @@ -66,6 +66,23 @@ s.move(library / "scripts") +# ---------------------------------------------------------------------------- +# Generate firestore bundle GAPIC layer +# ---------------------------------------------------------------------------- +for version in ["v1"]: + library = gapic.py_library( + service="firestore-bundle", + version=version, + proto_path='google/firestore/bundle', + bazel_target=f"//google/firestore/bundle:firestore-bundle-py", + ) + s.move( + library / f"google/cloud/bundle", + f"google/cloud/firestore_bundle", + ) + s.move(library / f"tests", f"tests") + + # ---------------------------------------------------------------------------- # Add templated files # ---------------------------------------------------------------------------- @@ -204,6 +221,18 @@ def lint_setup_py(session): """, ) +s.replace( + "google/cloud/firestore_bundle/types/bundle.py", + "from google.firestore.v1 import document_pb2 as gfv_document # type: ignore\n", + "from google.cloud.firestore_v1.types import document as gfv_document\n", +) + +s.replace( + "google/cloud/firestore_bundle/types/bundle.py", + "from google.firestore.v1 import query_pb2 as query # type: ignore\n", + "from google.cloud.firestore_v1.types import query\n", +) + s.replace( ".coveragerc", """\ diff --git a/tests/unit/gapic/bundle/__init__.py b/tests/unit/gapic/bundle/__init__.py new file mode 100644 index 000000000..42ffdf2bc --- /dev/null +++ b/tests/unit/gapic/bundle/__init__.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. +#