eoapi-cdk 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.devcontainer/devcontainer.json +4 -0
- package/.github/workflows/build.yaml +73 -0
- package/.github/workflows/conventional-pr.yaml +26 -0
- package/.github/workflows/distribute.yaml +45 -0
- package/.github/workflows/docs.yaml +26 -0
- package/.github/workflows/test.yaml +13 -0
- package/.github/workflows/tox.yaml +24 -0
- package/.jsii +5058 -0
- package/.nvmrc +1 -0
- package/CHANGELOG.md +195 -0
- package/README.md +50 -0
- package/diagrams/bastion_diagram.excalidraw +1416 -0
- package/diagrams/bastion_diagram.png +0 -0
- package/diagrams/ingestor_diagram.excalidraw +2274 -0
- package/diagrams/ingestor_diagram.png +0 -0
- package/lib/bastion-host/index.d.ts +117 -0
- package/lib/bastion-host/index.js +162 -0
- package/lib/bootstrapper/index.d.ts +57 -0
- package/lib/bootstrapper/index.js +73 -0
- package/lib/bootstrapper/runtime/Dockerfile +18 -0
- package/lib/bootstrapper/runtime/handler.py +235 -0
- package/lib/database/index.d.ts +60 -0
- package/lib/database/index.js +84 -0
- package/lib/database/instance-memory.json +525 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +19 -0
- package/lib/ingestor-api/index.d.ts +54 -0
- package/lib/ingestor-api/index.js +147 -0
- package/lib/ingestor-api/runtime/dev_requirements.txt +2 -0
- package/lib/ingestor-api/runtime/requirements.txt +12 -0
- package/lib/ingestor-api/runtime/src/__init__.py +0 -0
- package/lib/ingestor-api/runtime/src/collection.py +36 -0
- package/lib/ingestor-api/runtime/src/config.py +46 -0
- package/lib/ingestor-api/runtime/src/dependencies.py +94 -0
- package/lib/ingestor-api/runtime/src/handler.py +9 -0
- package/lib/ingestor-api/runtime/src/ingestor.py +82 -0
- package/lib/ingestor-api/runtime/src/loader.py +21 -0
- package/lib/ingestor-api/runtime/src/main.py +125 -0
- package/lib/ingestor-api/runtime/src/schemas.py +148 -0
- package/lib/ingestor-api/runtime/src/services.py +44 -0
- package/lib/ingestor-api/runtime/src/utils.py +52 -0
- package/lib/ingestor-api/runtime/src/validators.py +72 -0
- package/lib/ingestor-api/runtime/tests/__init__.py +0 -0
- package/lib/ingestor-api/runtime/tests/conftest.py +271 -0
- package/lib/ingestor-api/runtime/tests/test_collection.py +35 -0
- package/lib/ingestor-api/runtime/tests/test_collection_endpoint.py +41 -0
- package/lib/ingestor-api/runtime/tests/test_ingestor.py +60 -0
- package/lib/ingestor-api/runtime/tests/test_registration.py +198 -0
- package/lib/ingestor-api/runtime/tests/test_utils.py +35 -0
- package/lib/stac-api/index.d.ts +50 -0
- package/lib/stac-api/index.js +60 -0
- package/lib/stac-api/runtime/requirements.txt +8 -0
- package/lib/stac-api/runtime/src/__init__.py +0 -0
- package/lib/stac-api/runtime/src/app.py +58 -0
- package/lib/stac-api/runtime/src/config.py +96 -0
- package/lib/stac-api/runtime/src/handler.py +9 -0
- package/lib/titiler-pgstac-api/index.d.ts +33 -0
- package/lib/titiler-pgstac-api/index.js +67 -0
- package/lib/titiler-pgstac-api/runtime/Dockerfile +20 -0
- package/lib/titiler-pgstac-api/runtime/dev_requirements.txt +1 -0
- package/lib/titiler-pgstac-api/runtime/requirements.txt +3 -0
- package/lib/titiler-pgstac-api/runtime/src/__init__.py +3 -0
- package/lib/titiler-pgstac-api/runtime/src/handler.py +23 -0
- package/lib/titiler-pgstac-api/runtime/src/utils.py +26 -0
- package/package.json +81 -0
- package/tox.ini +52 -0
- package/tsconfig.tsbuildinfo +18116 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Custom resource lambda handler to bootstrap Postgres db.
|
|
3
|
+
Source: https://github.com/developmentseed/eoAPI/blob/master/deployment/handlers/db_handler.py
|
|
4
|
+
"""
|
|
5
|
+
import json
|
|
6
|
+
|
|
7
|
+
import boto3
|
|
8
|
+
import psycopg
|
|
9
|
+
import httpx
|
|
10
|
+
from psycopg import sql
|
|
11
|
+
from psycopg.conninfo import make_conninfo
|
|
12
|
+
from pypgstac.db import PgstacDB
|
|
13
|
+
from pypgstac.migrate import Migrate
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def send(
|
|
17
|
+
event,
|
|
18
|
+
context,
|
|
19
|
+
responseStatus,
|
|
20
|
+
responseData,
|
|
21
|
+
physicalResourceId=None,
|
|
22
|
+
noEcho=False,
|
|
23
|
+
):
|
|
24
|
+
"""
|
|
25
|
+
Copyright 2016 Amazon Web Services, Inc. or its affiliates. All Rights Reserved.
|
|
26
|
+
This file is licensed to you under the AWS Customer Agreement (the "License").
|
|
27
|
+
You may not use this file except in compliance with the License.
|
|
28
|
+
A copy of the License is located at http://aws.amazon.com/agreement/ .
|
|
29
|
+
This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied.
|
|
30
|
+
See the License for the specific language governing permissions and limitations under the License.
|
|
31
|
+
|
|
32
|
+
Send response from AWS Lambda.
|
|
33
|
+
|
|
34
|
+
Note: The cfnresponse module is available only when you use the ZipFile property to write your source code.
|
|
35
|
+
It isn't available for source code that's stored in Amazon S3 buckets.
|
|
36
|
+
For code in buckets, you must write your own functions to send responses.
|
|
37
|
+
"""
|
|
38
|
+
responseUrl = event["ResponseURL"]
|
|
39
|
+
|
|
40
|
+
print(responseUrl)
|
|
41
|
+
|
|
42
|
+
responseBody = {}
|
|
43
|
+
responseBody["Status"] = responseStatus
|
|
44
|
+
responseBody["Reason"] = (
|
|
45
|
+
"See the details in CloudWatch Log Stream: " + context.log_stream_name
|
|
46
|
+
)
|
|
47
|
+
responseBody["PhysicalResourceId"] = physicalResourceId or context.log_stream_name
|
|
48
|
+
responseBody["StackId"] = event["StackId"]
|
|
49
|
+
responseBody["RequestId"] = event["RequestId"]
|
|
50
|
+
responseBody["LogicalResourceId"] = event["LogicalResourceId"]
|
|
51
|
+
responseBody["NoEcho"] = noEcho
|
|
52
|
+
responseBody["Data"] = responseData
|
|
53
|
+
|
|
54
|
+
json_responseBody = json.dumps(responseBody)
|
|
55
|
+
|
|
56
|
+
print("Response body:\n" + json_responseBody)
|
|
57
|
+
|
|
58
|
+
headers = {"content-type": "", "content-length": str(len(json_responseBody))}
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
response = httpx.put(responseUrl, data=json_responseBody, headers=headers)
|
|
62
|
+
print("Status code: " + response.reason)
|
|
63
|
+
except Exception as e:
|
|
64
|
+
print("send(..) failed executing httpx.put(..): " + str(e))
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def get_secret(secret_name):
|
|
68
|
+
"""Get Secrets from secret manager."""
|
|
69
|
+
print(f"Fetching {secret_name}")
|
|
70
|
+
client = boto3.client(service_name="secretsmanager")
|
|
71
|
+
response = client.get_secret_value(SecretId=secret_name)
|
|
72
|
+
return json.loads(response["SecretString"])
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def create_db(cursor, db_name: str) -> None:
|
|
76
|
+
"""Create DB."""
|
|
77
|
+
cursor.execute(
|
|
78
|
+
sql.SQL("SELECT 1 FROM pg_catalog.pg_database " "WHERE datname = %s"), [db_name]
|
|
79
|
+
)
|
|
80
|
+
if cursor.fetchone():
|
|
81
|
+
print(f"database {db_name} exists, not creating DB")
|
|
82
|
+
else:
|
|
83
|
+
print(f"database {db_name} not found, creating...")
|
|
84
|
+
cursor.execute(
|
|
85
|
+
sql.SQL("CREATE DATABASE {db_name}").format(db_name=sql.Identifier(db_name))
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def create_user(cursor, username: str, password: str) -> None:
|
|
90
|
+
"""Create User."""
|
|
91
|
+
cursor.execute(
|
|
92
|
+
sql.SQL(
|
|
93
|
+
"DO $$ "
|
|
94
|
+
"BEGIN "
|
|
95
|
+
" IF NOT EXISTS ( "
|
|
96
|
+
" SELECT 1 FROM pg_roles "
|
|
97
|
+
" WHERE rolname = {user}) "
|
|
98
|
+
" THEN "
|
|
99
|
+
" CREATE USER {username} "
|
|
100
|
+
" WITH PASSWORD {password}; "
|
|
101
|
+
" ELSE "
|
|
102
|
+
" ALTER USER {username} "
|
|
103
|
+
" WITH PASSWORD {password}; "
|
|
104
|
+
" END IF; "
|
|
105
|
+
"END "
|
|
106
|
+
"$$; "
|
|
107
|
+
).format(username=sql.Identifier(username), password=password, user=username)
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def create_permissions(cursor, db_name: str, username: str) -> None:
|
|
112
|
+
"""Add permissions."""
|
|
113
|
+
cursor.execute(
|
|
114
|
+
sql.SQL(
|
|
115
|
+
"GRANT CONNECT ON DATABASE {db_name} TO {username};"
|
|
116
|
+
"GRANT CREATE ON DATABASE {db_name} TO {username};" # Allow schema creation
|
|
117
|
+
"GRANT USAGE ON SCHEMA public TO {username};"
|
|
118
|
+
"ALTER DEFAULT PRIVILEGES IN SCHEMA public "
|
|
119
|
+
"GRANT ALL PRIVILEGES ON TABLES TO {username};"
|
|
120
|
+
"ALTER DEFAULT PRIVILEGES IN SCHEMA public "
|
|
121
|
+
"GRANT ALL PRIVILEGES ON SEQUENCES TO {username};"
|
|
122
|
+
"GRANT pgstac_read TO {username};"
|
|
123
|
+
"GRANT pgstac_ingest TO {username};"
|
|
124
|
+
"GRANT pgstac_admin TO {username};"
|
|
125
|
+
).format(
|
|
126
|
+
db_name=sql.Identifier(db_name),
|
|
127
|
+
username=sql.Identifier(username),
|
|
128
|
+
)
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def register_extensions(cursor) -> None:
|
|
133
|
+
"""Add PostGIS extension."""
|
|
134
|
+
cursor.execute(sql.SQL("CREATE EXTENSION IF NOT EXISTS postgis;"))
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def handler(event, context):
|
|
138
|
+
"""Lambda Handler."""
|
|
139
|
+
print(f"Handling {event}")
|
|
140
|
+
|
|
141
|
+
if event["RequestType"] not in ["Create", "Update"]:
|
|
142
|
+
return send(event, context, "SUCCESS", {"msg": "No action to be taken"})
|
|
143
|
+
|
|
144
|
+
try:
|
|
145
|
+
params = event["ResourceProperties"]
|
|
146
|
+
connection_params = get_secret(params["conn_secret_arn"])
|
|
147
|
+
user_params = get_secret(params["new_user_secret_arn"])
|
|
148
|
+
|
|
149
|
+
print("Connecting to admin DB...")
|
|
150
|
+
admin_db_conninfo = make_conninfo(
|
|
151
|
+
dbname=connection_params.get("dbname", "postgres"),
|
|
152
|
+
user=connection_params["username"],
|
|
153
|
+
password=connection_params["password"],
|
|
154
|
+
host=connection_params["host"],
|
|
155
|
+
port=connection_params["port"],
|
|
156
|
+
)
|
|
157
|
+
with psycopg.connect(admin_db_conninfo, autocommit=True) as conn:
|
|
158
|
+
with conn.cursor() as cur:
|
|
159
|
+
print("Creating database...")
|
|
160
|
+
create_db(
|
|
161
|
+
cursor=cur,
|
|
162
|
+
db_name=user_params["dbname"],
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
print("Creating user...")
|
|
166
|
+
create_user(
|
|
167
|
+
cursor=cur,
|
|
168
|
+
username=user_params["username"],
|
|
169
|
+
password=user_params["password"],
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# Install extensions on the user DB with
|
|
173
|
+
# superuser permissions, since they will
|
|
174
|
+
# otherwise fail to install when run as
|
|
175
|
+
# the non-superuser within the pgstac
|
|
176
|
+
# migrations.
|
|
177
|
+
print("Connecting to STAC DB...")
|
|
178
|
+
stac_db_conninfo = make_conninfo(
|
|
179
|
+
dbname=user_params["dbname"],
|
|
180
|
+
user=connection_params["username"],
|
|
181
|
+
password=connection_params["password"],
|
|
182
|
+
host=connection_params["host"],
|
|
183
|
+
port=connection_params["port"],
|
|
184
|
+
)
|
|
185
|
+
with psycopg.connect(stac_db_conninfo, autocommit=True) as conn:
|
|
186
|
+
with conn.cursor() as cur:
|
|
187
|
+
print("Registering PostGIS ...")
|
|
188
|
+
register_extensions(cursor=cur)
|
|
189
|
+
|
|
190
|
+
stac_db_admin_dsn = (
|
|
191
|
+
"postgresql://{user}:{password}@{host}:{port}/{dbname}".format(
|
|
192
|
+
dbname=user_params.get("dbname", "postgres"),
|
|
193
|
+
user=connection_params["username"],
|
|
194
|
+
password=connection_params["password"],
|
|
195
|
+
host=connection_params["host"],
|
|
196
|
+
port=connection_params["port"],
|
|
197
|
+
)
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
pgdb = PgstacDB(dsn=stac_db_admin_dsn, debug=True)
|
|
201
|
+
print(f"Current {pgdb.version=}")
|
|
202
|
+
|
|
203
|
+
# As admin, run migrations
|
|
204
|
+
print("Running migrations...")
|
|
205
|
+
Migrate(pgdb).run_migration(params["pgstac_version"])
|
|
206
|
+
|
|
207
|
+
# Assign appropriate permissions to user (requires pgSTAC migrations to have run)
|
|
208
|
+
with psycopg.connect(admin_db_conninfo, autocommit=True) as conn:
|
|
209
|
+
with conn.cursor() as cur:
|
|
210
|
+
print("Setting permissions...")
|
|
211
|
+
create_permissions(
|
|
212
|
+
cursor=cur,
|
|
213
|
+
db_name=user_params["dbname"],
|
|
214
|
+
username=user_params["username"],
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
print("Adding mosaic index...")
|
|
218
|
+
with psycopg.connect(
|
|
219
|
+
stac_db_admin_dsn,
|
|
220
|
+
autocommit=True,
|
|
221
|
+
options="-c search_path=pgstac,public -c application_name=pgstac",
|
|
222
|
+
) as conn:
|
|
223
|
+
conn.execute(
|
|
224
|
+
sql.SQL(
|
|
225
|
+
"CREATE INDEX IF NOT EXISTS searches_mosaic ON searches ((true)) WHERE metadata->>'type'='mosaic';"
|
|
226
|
+
)
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
except Exception as e:
|
|
230
|
+
print(f"Unable to bootstrap database with exception={e}")
|
|
231
|
+
send(event, context, "FAILED", {"message": str(e)})
|
|
232
|
+
raise e
|
|
233
|
+
|
|
234
|
+
print("Complete.")
|
|
235
|
+
return send(event, context, "SUCCESS", {})
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { aws_rds as rds, aws_secretsmanager as secretsmanager } from "aws-cdk-lib";
|
|
2
|
+
import { Construct } from "constructs";
|
|
3
|
+
import { BootstrapPgStacProps } from "../bootstrapper";
|
|
4
|
+
/**
|
|
5
|
+
* An RDS instance with pgSTAC installed. This is a wrapper around the
|
|
6
|
+
* `rds.DatabaseInstance` higher-level construct making use
|
|
7
|
+
* of the BootstrapPgStac construct.
|
|
8
|
+
*/
|
|
9
|
+
export declare class PgStacDatabase extends Construct {
|
|
10
|
+
db: rds.DatabaseInstance;
|
|
11
|
+
pgstacSecret: secretsmanager.ISecret;
|
|
12
|
+
constructor(scope: Construct, id: string, props: PgStacDatabaseProps);
|
|
13
|
+
getParameters(instanceType: string, parameters: PgStacDatabaseProps["parameters"]): DatabaseParameters;
|
|
14
|
+
}
|
|
15
|
+
export interface PgStacDatabaseProps extends rds.DatabaseInstanceProps {
|
|
16
|
+
readonly pgstacDbName?: BootstrapPgStacProps["pgstacDbName"];
|
|
17
|
+
readonly pgstacVersion?: BootstrapPgStacProps["pgstacVersion"];
|
|
18
|
+
readonly pgstacUsername?: BootstrapPgStacProps["pgstacUsername"];
|
|
19
|
+
readonly secretsPrefix?: BootstrapPgStacProps["secretsPrefix"];
|
|
20
|
+
}
|
|
21
|
+
export interface DatabaseParameters {
|
|
22
|
+
/**
|
|
23
|
+
* @default - LEAST({DBInstanceClassMemory/9531392}, 5000)
|
|
24
|
+
*/
|
|
25
|
+
readonly maxConnections: string;
|
|
26
|
+
/**
|
|
27
|
+
* Note: This value is measured in 8KB blocks.
|
|
28
|
+
*
|
|
29
|
+
* @default '{DBInstanceClassMemory/32768}' 25% of instance memory, ie `{(DBInstanceClassMemory/(1024*8)) * 0.25}`
|
|
30
|
+
*/
|
|
31
|
+
readonly sharedBuffers: string;
|
|
32
|
+
/**
|
|
33
|
+
* @default - 75% of instance memory
|
|
34
|
+
*/
|
|
35
|
+
readonly effectiveCacheSize: string;
|
|
36
|
+
/**
|
|
37
|
+
* @default - shared buffers divided by max connections
|
|
38
|
+
*/
|
|
39
|
+
readonly workMem: string;
|
|
40
|
+
/**
|
|
41
|
+
* @default - 25% of shared buffers
|
|
42
|
+
*/
|
|
43
|
+
readonly maintenanceWorkMem: string;
|
|
44
|
+
/**
|
|
45
|
+
* @default 1024
|
|
46
|
+
*/
|
|
47
|
+
readonly maxLocksPerTransaction: string;
|
|
48
|
+
/**
|
|
49
|
+
* @default 131172 (128 * 1024)
|
|
50
|
+
*/
|
|
51
|
+
readonly tempBuffers: string;
|
|
52
|
+
/**
|
|
53
|
+
* @default 1
|
|
54
|
+
*/
|
|
55
|
+
readonly seqPageCost: string;
|
|
56
|
+
/**
|
|
57
|
+
* @default 1.1
|
|
58
|
+
*/
|
|
59
|
+
readonly randomPageCost: string;
|
|
60
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.PgStacDatabase = void 0;
|
|
5
|
+
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
|
6
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
7
|
+
const constructs_1 = require("constructs");
|
|
8
|
+
const bootstrapper_1 = require("../bootstrapper");
|
|
9
|
+
const instanceSizes = require("./instance-memory.json");
|
|
10
|
+
/**
|
|
11
|
+
* An RDS instance with pgSTAC installed. This is a wrapper around the
|
|
12
|
+
* `rds.DatabaseInstance` higher-level construct making use
|
|
13
|
+
* of the BootstrapPgStac construct.
|
|
14
|
+
*/
|
|
15
|
+
class PgStacDatabase extends constructs_1.Construct {
|
|
16
|
+
constructor(scope, id, props) {
|
|
17
|
+
super(scope, id);
|
|
18
|
+
const defaultParameters = this.getParameters(props.instanceType?.toString() || "m5.large", props.parameters);
|
|
19
|
+
const parameterGroup = new aws_cdk_lib_1.aws_rds.ParameterGroup(this, "parameterGroup", {
|
|
20
|
+
engine: props.engine,
|
|
21
|
+
parameters: {
|
|
22
|
+
shared_buffers: defaultParameters.sharedBuffers,
|
|
23
|
+
effective_cache_size: defaultParameters.effectiveCacheSize,
|
|
24
|
+
work_mem: defaultParameters.workMem,
|
|
25
|
+
maintenance_work_mem: defaultParameters.maintenanceWorkMem,
|
|
26
|
+
max_locks_per_transaction: defaultParameters.maxLocksPerTransaction,
|
|
27
|
+
temp_buffers: defaultParameters.tempBuffers,
|
|
28
|
+
seq_page_cost: defaultParameters.seqPageCost,
|
|
29
|
+
random_page_cost: defaultParameters.randomPageCost,
|
|
30
|
+
...props.parameters,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
this.db = new aws_cdk_lib_1.aws_rds.DatabaseInstance(this, "db", {
|
|
34
|
+
instanceIdentifier: aws_cdk_lib_1.Stack.of(this).stackName,
|
|
35
|
+
parameterGroup,
|
|
36
|
+
...props,
|
|
37
|
+
});
|
|
38
|
+
const bootstrap = new bootstrapper_1.BootstrapPgStac(this, "bootstrap-pgstac-instance", {
|
|
39
|
+
vpc: props.vpc,
|
|
40
|
+
database: this.db,
|
|
41
|
+
dbSecret: this.db.secret,
|
|
42
|
+
pgstacDbName: props.pgstacDbName,
|
|
43
|
+
pgstacVersion: props.pgstacVersion,
|
|
44
|
+
pgstacUsername: props.pgstacUsername,
|
|
45
|
+
secretsPrefix: props.secretsPrefix,
|
|
46
|
+
});
|
|
47
|
+
this.pgstacSecret = bootstrap.secret;
|
|
48
|
+
}
|
|
49
|
+
getParameters(instanceType, parameters) {
|
|
50
|
+
// https://github.com/aws/aws-cli/issues/1279#issuecomment-909318236
|
|
51
|
+
const memory_in_kb = instanceSizes[instanceType] * 1024;
|
|
52
|
+
// It's only necessary to consider passed in parameters for any value that used to
|
|
53
|
+
// derive subsequent values. Values that don't have dependencies will be overriden
|
|
54
|
+
// when we unpack the passed-in user parameters
|
|
55
|
+
const maxConnections = parameters?.maxConnections
|
|
56
|
+
? Number.parseInt(parameters.maxConnections)
|
|
57
|
+
: // https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Limits.html#RDS_Limits.MaxConnections
|
|
58
|
+
Math.min(Math.round((memory_in_kb * 1024) / 9531392), 5000);
|
|
59
|
+
const sharedBuffers = parameters?.sharedBufers
|
|
60
|
+
? Number.parseInt(parameters.sharedBufers)
|
|
61
|
+
: Math.round(0.25 * memory_in_kb);
|
|
62
|
+
const effectiveCacheSize = Math.round(0.75 * memory_in_kb);
|
|
63
|
+
const workMem = Math.floor(sharedBuffers / maxConnections);
|
|
64
|
+
const maintenanceWorkMem = Math.round(0.25 * sharedBuffers);
|
|
65
|
+
const tempBuffers = 128 * 1024;
|
|
66
|
+
const seqPageCost = 1;
|
|
67
|
+
const randomPageCost = 1.1;
|
|
68
|
+
return {
|
|
69
|
+
maxConnections: `${maxConnections}`,
|
|
70
|
+
sharedBuffers: `${sharedBuffers / 8}`,
|
|
71
|
+
effectiveCacheSize: `${effectiveCacheSize}`,
|
|
72
|
+
workMem: `${workMem}`,
|
|
73
|
+
maintenanceWorkMem: `${maintenanceWorkMem}`,
|
|
74
|
+
maxLocksPerTransaction: "1024",
|
|
75
|
+
tempBuffers: `${tempBuffers}`,
|
|
76
|
+
seqPageCost: `${seqPageCost}`,
|
|
77
|
+
randomPageCost: `${randomPageCost}`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.PgStacDatabase = PgStacDatabase;
|
|
82
|
+
_a = JSII_RTTI_SYMBOL_1;
|
|
83
|
+
PgStacDatabase[_a] = { fqn: "eoapi-cdk.PgStacDatabase", version: "5.0.0" };
|
|
84
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDZDQUlxQjtBQUNyQiwyQ0FBdUM7QUFDdkMsa0RBQXdFO0FBRXhFLE1BQU0sYUFBYSxHQUEyQixPQUFPLENBQUMsd0JBQXdCLENBQUMsQ0FBQztBQUVoRjs7OztHQUlHO0FBQ0gsTUFBYSxjQUFlLFNBQVEsc0JBQVM7SUFJM0MsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUEwQjtRQUNsRSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRWpCLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FDMUMsS0FBSyxDQUFDLFlBQVksRUFBRSxRQUFRLEVBQUUsSUFBSSxVQUFVLEVBQzVDLEtBQUssQ0FBQyxVQUFVLENBQ2pCLENBQUM7UUFDRixNQUFNLGNBQWMsR0FBRyxJQUFJLHFCQUFHLENBQUMsY0FBYyxDQUFDLElBQUksRUFBRSxnQkFBZ0IsRUFBRTtZQUNwRSxNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU07WUFDcEIsVUFBVSxFQUFFO2dCQUNWLGNBQWMsRUFBRSxpQkFBaUIsQ0FBQyxhQUFhO2dCQUMvQyxvQkFBb0IsRUFBRSxpQkFBaUIsQ0FBQyxrQkFBa0I7Z0JBQzFELFFBQVEsRUFBRSxpQkFBaUIsQ0FBQyxPQUFPO2dCQUNuQyxvQkFBb0IsRUFBRSxpQkFBaUIsQ0FBQyxrQkFBa0I7Z0JBQzFELHlCQUF5QixFQUFFLGlCQUFpQixDQUFDLHNCQUFzQjtnQkFDbkUsWUFBWSxFQUFFLGlCQUFpQixDQUFDLFdBQVc7Z0JBQzNDLGFBQWEsRUFBRSxpQkFBaUIsQ0FBQyxXQUFXO2dCQUM1QyxnQkFBZ0IsRUFBRSxpQkFBaUIsQ0FBQyxjQUFjO2dCQUNsRCxHQUFHLEtBQUssQ0FBQyxVQUFVO2FBQ3BCO1NBQ0YsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLEVBQUUsR0FBRyxJQUFJLHFCQUFHLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxFQUFFLElBQUksRUFBRTtZQUM3QyxrQkFBa0IsRUFBRSxtQkFBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxTQUFTO1lBQzVDLGNBQWM7WUFDZCxHQUFHLEtBQUs7U0FDVCxDQUFDLENBQUM7UUFFSCxNQUFNLFNBQVMsR0FBRyxJQUFJLDhCQUFlLENBQUMsSUFBSSxFQUFFLDJCQUEyQixFQUFFO1lBQ3ZFLEdBQUcsRUFBRSxLQUFLLENBQUMsR0FBRztZQUNkLFFBQVEsRUFBRSxJQUFJLENBQUMsRUFBRTtZQUNqQixRQUFRLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFPO1lBQ3pCLFlBQVksRUFBRSxLQUFLLENBQUMsWUFBWTtZQUNoQyxhQUFhLEVBQUUsS0FBSyxDQUFDLGFBQWE7WUFDbEMsY0FBYyxFQUFFLEtBQUssQ0FBQyxjQUFjO1lBQ3BDLGFBQWEsRUFBRSxLQUFLLENBQUMsYUFBYTtTQUNuQyxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsWUFBWSxHQUFHLFNBQVMsQ0FBQyxNQUFNLENBQUM7SUFDdkMsQ0FBQztJQUVNLGFBQWEsQ0FDbEIsWUFBb0IsRUFDcEIsVUFBNkM7UUFFN0Msb0VBQW9FO1FBQ3BFLE1BQU0sWUFBWSxHQUFHLGFBQWEsQ0FBQyxZQUFZLENBQUMsR0FBRyxJQUFJLENBQUM7UUFFeEQsa0ZBQWtGO1FBQ2xGLGtGQUFrRjtRQUNsRiwrQ0FBK0M7UUFDL0MsTUFBTSxjQUFjLEdBQUcsVUFBVSxFQUFFLGNBQWM7WUFDL0MsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLGNBQWMsQ0FBQztZQUM1QyxDQUFDLENBQUMsb0dBQW9HO2dCQUNwRyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLEdBQUcsT0FBTyxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDaEUsTUFBTSxhQUFhLEdBQUcsVUFBVSxFQUFFLFlBQVk7WUFDNUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLFlBQVksQ0FBQztZQUMxQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEdBQUcsWUFBWSxDQUFDLENBQUM7UUFFcEMsTUFBTSxrQkFBa0IsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksR0FBRyxZQUFZLENBQUMsQ0FBQztRQUMzRCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLGFBQWEsR0FBRyxjQUFjLENBQUMsQ0FBQztRQUMzRCxNQUFNLGtCQUFrQixHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxHQUFHLGFBQWEsQ0FBQyxDQUFDO1FBRTVELE1BQU0sV0FBVyxHQUFHLEdBQUcsR0FBRyxJQUFJLENBQUM7UUFDL0IsTUFBTSxXQUFXLEdBQUcsQ0FBQyxDQUFDO1FBQ3RCLE1BQU0sY0FBYyxHQUFHLEdBQUcsQ0FBQztRQUUzQixPQUFPO1lBQ0wsY0FBYyxFQUFFLEdBQUcsY0FBYyxFQUFFO1lBQ25DLGFBQWEsRUFBRSxHQUFHLGFBQWEsR0FBRyxDQUFDLEVBQUU7WUFDckMsa0JBQWtCLEVBQUUsR0FBRyxrQkFBa0IsRUFBRTtZQUMzQyxPQUFPLEVBQUUsR0FBRyxPQUFPLEVBQUU7WUFDckIsa0JBQWtCLEVBQUUsR0FBRyxrQkFBa0IsRUFBRTtZQUMzQyxzQkFBc0IsRUFBRSxNQUFNO1lBQzlCLFdBQVcsRUFBRSxHQUFHLFdBQVcsRUFBRTtZQUM3QixXQUFXLEVBQUUsR0FBRyxXQUFXLEVBQUU7WUFDN0IsY0FBYyxFQUFFLEdBQUcsY0FBYyxFQUFFO1NBQ3BDLENBQUM7SUFDSixDQUFDOztBQWxGSCx3Q0FtRkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBTdGFjayxcbiAgYXdzX3JkcyBhcyByZHMsXG4gIGF3c19zZWNyZXRzbWFuYWdlciBhcyBzZWNyZXRzbWFuYWdlcixcbn0gZnJvbSBcImF3cy1jZGstbGliXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tIFwiY29uc3RydWN0c1wiO1xuaW1wb3J0IHsgQm9vdHN0cmFwUGdTdGFjLCBCb290c3RyYXBQZ1N0YWNQcm9wcyB9IGZyb20gXCIuLi9ib290c3RyYXBwZXJcIjtcblxuY29uc3QgaW5zdGFuY2VTaXplczogUmVjb3JkPHN0cmluZywgbnVtYmVyPiA9IHJlcXVpcmUoXCIuL2luc3RhbmNlLW1lbW9yeS5qc29uXCIpO1xuXG4vKipcbiAqIEFuIFJEUyBpbnN0YW5jZSB3aXRoIHBnU1RBQyBpbnN0YWxsZWQuIFRoaXMgaXMgYSB3cmFwcGVyIGFyb3VuZCB0aGVcbiAqIGByZHMuRGF0YWJhc2VJbnN0YW5jZWAgaGlnaGVyLWxldmVsIGNvbnN0cnVjdCBtYWtpbmcgdXNlXG4gKiBvZiB0aGUgQm9vdHN0cmFwUGdTdGFjIGNvbnN0cnVjdC5cbiAqL1xuZXhwb3J0IGNsYXNzIFBnU3RhY0RhdGFiYXNlIGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgZGI6IHJkcy5EYXRhYmFzZUluc3RhbmNlO1xuICBwZ3N0YWNTZWNyZXQ6IHNlY3JldHNtYW5hZ2VyLklTZWNyZXQ7XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IFBnU3RhY0RhdGFiYXNlUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgY29uc3QgZGVmYXVsdFBhcmFtZXRlcnMgPSB0aGlzLmdldFBhcmFtZXRlcnMoXG4gICAgICBwcm9wcy5pbnN0YW5jZVR5cGU/LnRvU3RyaW5nKCkgfHwgXCJtNS5sYXJnZVwiLFxuICAgICAgcHJvcHMucGFyYW1ldGVyc1xuICAgICk7XG4gICAgY29uc3QgcGFyYW1ldGVyR3JvdXAgPSBuZXcgcmRzLlBhcmFtZXRlckdyb3VwKHRoaXMsIFwicGFyYW1ldGVyR3JvdXBcIiwge1xuICAgICAgZW5naW5lOiBwcm9wcy5lbmdpbmUsXG4gICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgIHNoYXJlZF9idWZmZXJzOiBkZWZhdWx0UGFyYW1ldGVycy5zaGFyZWRCdWZmZXJzLFxuICAgICAgICBlZmZlY3RpdmVfY2FjaGVfc2l6ZTogZGVmYXVsdFBhcmFtZXRlcnMuZWZmZWN0aXZlQ2FjaGVTaXplLFxuICAgICAgICB3b3JrX21lbTogZGVmYXVsdFBhcmFtZXRlcnMud29ya01lbSxcbiAgICAgICAgbWFpbnRlbmFuY2Vfd29ya19tZW06IGRlZmF1bHRQYXJhbWV0ZXJzLm1haW50ZW5hbmNlV29ya01lbSxcbiAgICAgICAgbWF4X2xvY2tzX3Blcl90cmFuc2FjdGlvbjogZGVmYXVsdFBhcmFtZXRlcnMubWF4TG9ja3NQZXJUcmFuc2FjdGlvbixcbiAgICAgICAgdGVtcF9idWZmZXJzOiBkZWZhdWx0UGFyYW1ldGVycy50ZW1wQnVmZmVycyxcbiAgICAgICAgc2VxX3BhZ2VfY29zdDogZGVmYXVsdFBhcmFtZXRlcnMuc2VxUGFnZUNvc3QsXG4gICAgICAgIHJhbmRvbV9wYWdlX2Nvc3Q6IGRlZmF1bHRQYXJhbWV0ZXJzLnJhbmRvbVBhZ2VDb3N0LFxuICAgICAgICAuLi5wcm9wcy5wYXJhbWV0ZXJzLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIHRoaXMuZGIgPSBuZXcgcmRzLkRhdGFiYXNlSW5zdGFuY2UodGhpcywgXCJkYlwiLCB7XG4gICAgICBpbnN0YW5jZUlkZW50aWZpZXI6IFN0YWNrLm9mKHRoaXMpLnN0YWNrTmFtZSxcbiAgICAgIHBhcmFtZXRlckdyb3VwLFxuICAgICAgLi4ucHJvcHMsXG4gICAgfSk7XG5cbiAgICBjb25zdCBib290c3RyYXAgPSBuZXcgQm9vdHN0cmFwUGdTdGFjKHRoaXMsIFwiYm9vdHN0cmFwLXBnc3RhYy1pbnN0YW5jZVwiLCB7XG4gICAgICB2cGM6IHByb3BzLnZwYyxcbiAgICAgIGRhdGFiYXNlOiB0aGlzLmRiLFxuICAgICAgZGJTZWNyZXQ6IHRoaXMuZGIuc2VjcmV0ISxcbiAgICAgIHBnc3RhY0RiTmFtZTogcHJvcHMucGdzdGFjRGJOYW1lLFxuICAgICAgcGdzdGFjVmVyc2lvbjogcHJvcHMucGdzdGFjVmVyc2lvbixcbiAgICAgIHBnc3RhY1VzZXJuYW1lOiBwcm9wcy5wZ3N0YWNVc2VybmFtZSxcbiAgICAgIHNlY3JldHNQcmVmaXg6IHByb3BzLnNlY3JldHNQcmVmaXgsXG4gICAgfSk7XG5cbiAgICB0aGlzLnBnc3RhY1NlY3JldCA9IGJvb3RzdHJhcC5zZWNyZXQ7XG4gIH1cblxuICBwdWJsaWMgZ2V0UGFyYW1ldGVycyhcbiAgICBpbnN0YW5jZVR5cGU6IHN0cmluZyxcbiAgICBwYXJhbWV0ZXJzOiBQZ1N0YWNEYXRhYmFzZVByb3BzW1wicGFyYW1ldGVyc1wiXVxuICApOiBEYXRhYmFzZVBhcmFtZXRlcnMge1xuICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9hd3MvYXdzLWNsaS9pc3N1ZXMvMTI3OSNpc3N1ZWNvbW1lbnQtOTA5MzE4MjM2XG4gICAgY29uc3QgbWVtb3J5X2luX2tiID0gaW5zdGFuY2VTaXplc1tpbnN0YW5jZVR5cGVdICogMTAyNDtcblxuICAgIC8vIEl0J3Mgb25seSBuZWNlc3NhcnkgdG8gY29uc2lkZXIgcGFzc2VkIGluIHBhcmFtZXRlcnMgZm9yIGFueSB2YWx1ZSB0aGF0IHVzZWQgdG9cbiAgICAvLyBkZXJpdmUgc3Vic2VxdWVudCB2YWx1ZXMuIFZhbHVlcyB0aGF0IGRvbid0IGhhdmUgZGVwZW5kZW5jaWVzIHdpbGwgYmUgb3ZlcnJpZGVuXG4gICAgLy8gd2hlbiB3ZSB1bnBhY2sgdGhlIHBhc3NlZC1pbiB1c2VyIHBhcmFtZXRlcnNcbiAgICBjb25zdCBtYXhDb25uZWN0aW9ucyA9IHBhcmFtZXRlcnM/Lm1heENvbm5lY3Rpb25zXG4gICAgICA/IE51bWJlci5wYXJzZUludChwYXJhbWV0ZXJzLm1heENvbm5lY3Rpb25zKVxuICAgICAgOiAvLyBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uUkRTL2xhdGVzdC9Vc2VyR3VpZGUvQ0hBUF9MaW1pdHMuaHRtbCNSRFNfTGltaXRzLk1heENvbm5lY3Rpb25zXG4gICAgICAgIE1hdGgubWluKE1hdGgucm91bmQoKG1lbW9yeV9pbl9rYiAqIDEwMjQpIC8gOTUzMTM5MiksIDUwMDApO1xuICAgIGNvbnN0IHNoYXJlZEJ1ZmZlcnMgPSBwYXJhbWV0ZXJzPy5zaGFyZWRCdWZlcnNcbiAgICAgID8gTnVtYmVyLnBhcnNlSW50KHBhcmFtZXRlcnMuc2hhcmVkQnVmZXJzKVxuICAgICAgOiBNYXRoLnJvdW5kKDAuMjUgKiBtZW1vcnlfaW5fa2IpO1xuXG4gICAgY29uc3QgZWZmZWN0aXZlQ2FjaGVTaXplID0gTWF0aC5yb3VuZCgwLjc1ICogbWVtb3J5X2luX2tiKTtcbiAgICBjb25zdCB3b3JrTWVtID0gTWF0aC5mbG9vcihzaGFyZWRCdWZmZXJzIC8gbWF4Q29ubmVjdGlvbnMpO1xuICAgIGNvbnN0IG1haW50ZW5hbmNlV29ya01lbSA9IE1hdGgucm91bmQoMC4yNSAqIHNoYXJlZEJ1ZmZlcnMpO1xuXG4gICAgY29uc3QgdGVtcEJ1ZmZlcnMgPSAxMjggKiAxMDI0O1xuICAgIGNvbnN0IHNlcVBhZ2VDb3N0ID0gMTtcbiAgICBjb25zdCByYW5kb21QYWdlQ29zdCA9IDEuMTtcblxuICAgIHJldHVybiB7XG4gICAgICBtYXhDb25uZWN0aW9uczogYCR7bWF4Q29ubmVjdGlvbnN9YCxcbiAgICAgIHNoYXJlZEJ1ZmZlcnM6IGAke3NoYXJlZEJ1ZmZlcnMgLyA4fWAsIC8vIFJlcHJlc2VudGVkIGluIDhrYiBibG9ja3NcbiAgICAgIGVmZmVjdGl2ZUNhY2hlU2l6ZTogYCR7ZWZmZWN0aXZlQ2FjaGVTaXplfWAsXG4gICAgICB3b3JrTWVtOiBgJHt3b3JrTWVtfWAsXG4gICAgICBtYWludGVuYW5jZVdvcmtNZW06IGAke21haW50ZW5hbmNlV29ya01lbX1gLFxuICAgICAgbWF4TG9ja3NQZXJUcmFuc2FjdGlvbjogXCIxMDI0XCIsXG4gICAgICB0ZW1wQnVmZmVyczogYCR7dGVtcEJ1ZmZlcnN9YCxcbiAgICAgIHNlcVBhZ2VDb3N0OiBgJHtzZXFQYWdlQ29zdH1gLFxuICAgICAgcmFuZG9tUGFnZUNvc3Q6IGAke3JhbmRvbVBhZ2VDb3N0fWAsXG4gICAgfTtcbiAgfVxufVxuXG5leHBvcnQgaW50ZXJmYWNlIFBnU3RhY0RhdGFiYXNlUHJvcHMgZXh0ZW5kcyByZHMuRGF0YWJhc2VJbnN0YW5jZVByb3BzIHtcbiAgcmVhZG9ubHkgcGdzdGFjRGJOYW1lPzogQm9vdHN0cmFwUGdTdGFjUHJvcHNbXCJwZ3N0YWNEYk5hbWVcIl07XG4gIHJlYWRvbmx5IHBnc3RhY1ZlcnNpb24/OiBCb290c3RyYXBQZ1N0YWNQcm9wc1tcInBnc3RhY1ZlcnNpb25cIl07XG4gIHJlYWRvbmx5IHBnc3RhY1VzZXJuYW1lPzogQm9vdHN0cmFwUGdTdGFjUHJvcHNbXCJwZ3N0YWNVc2VybmFtZVwiXTtcbiAgcmVhZG9ubHkgc2VjcmV0c1ByZWZpeD86IEJvb3RzdHJhcFBnU3RhY1Byb3BzW1wic2VjcmV0c1ByZWZpeFwiXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBEYXRhYmFzZVBhcmFtZXRlcnMge1xuICAvKipcbiAgICogQGRlZmF1bHQgLSBMRUFTVCh7REJJbnN0YW5jZUNsYXNzTWVtb3J5Lzk1MzEzOTJ9LCA1MDAwKVxuICAgKi9cbiAgcmVhZG9ubHkgbWF4Q29ubmVjdGlvbnM6IHN0cmluZztcblxuICAvKipcbiAgICogTm90ZTogVGhpcyB2YWx1ZSBpcyBtZWFzdXJlZCBpbiA4S0IgYmxvY2tzLlxuICAgKlxuICAgKiBAZGVmYXVsdCAne0RCSW5zdGFuY2VDbGFzc01lbW9yeS8zMjc2OH0nIDI1JSBvZiBpbnN0YW5jZSBtZW1vcnksIGllIGB7KERCSW5zdGFuY2VDbGFzc01lbW9yeS8oMTAyNCo4KSkgKiAwLjI1fWBcbiAgICovXG4gIHJlYWRvbmx5IHNoYXJlZEJ1ZmZlcnM6IHN0cmluZztcblxuICAvKipcbiAgICogQGRlZmF1bHQgLSA3NSUgb2YgaW5zdGFuY2UgbWVtb3J5XG4gICAqL1xuICByZWFkb25seSBlZmZlY3RpdmVDYWNoZVNpemU6IHN0cmluZztcblxuICAvKipcbiAgICogQGRlZmF1bHQgLSBzaGFyZWQgYnVmZmVycyBkaXZpZGVkIGJ5IG1heCBjb25uZWN0aW9uc1xuICAgKi9cbiAgcmVhZG9ubHkgd29ya01lbTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBAZGVmYXVsdCAtIDI1JSBvZiBzaGFyZWQgYnVmZmVyc1xuICAgKi9cbiAgcmVhZG9ubHkgbWFpbnRlbmFuY2VXb3JrTWVtOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEBkZWZhdWx0IDEwMjRcbiAgICovXG4gIHJlYWRvbmx5IG1heExvY2tzUGVyVHJhbnNhY3Rpb246IHN0cmluZztcblxuICAvKipcbiAgICogQGRlZmF1bHQgMTMxMTcyICgxMjggKiAxMDI0KVxuICAgKi9cbiAgcmVhZG9ubHkgdGVtcEJ1ZmZlcnM6IHN0cmluZztcblxuICAvKipcbiAgICogQGRlZmF1bHQgMVxuICAgKi9cbiAgcmVhZG9ubHkgc2VxUGFnZUNvc3Q6IHN0cmluZztcblxuICAvKipcbiAgICogQGRlZmF1bHQgMS4xXG4gICAqL1xuICByZWFkb25seSByYW5kb21QYWdlQ29zdDogc3RyaW5nO1xufVxuIl19
|