-
Notifications
You must be signed in to change notification settings - Fork 93
Add interface for NoSQL storage #214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 157 commits
Commits
Show all changes
163 commits
Select commit
Hold shift + click to select a range
0363899
[system] Add basic interface for allocating NoSQL storage
mcopik dd3384c
[aws] Implement allocation of DynamoDB tables
mcopik 847534f
[system] Allocate NoSQL tables for the selected benchmark
mcopik 6a62633
[system] Remove debug printouts
mcopik 1c30372
[aws] Add first version of DynamoDB wrapper
mcopik ed22ea3
[azure] First implementation of wrapper for CosmosDB
mcopik b21cd34
[aws] Update AWS wrapper with query interface
mcopik e85c348
[gcp] Add wrapper for google cloud datastore
mcopik f28b496
[system] Add packages needed to support storage API
mcopik a1cd286
[aws] Formatting AWS nosql wrapper
mcopik 9b3a284
[system] Split system packages into benchmark modules
mcopik 3f3b440
[aws] Support sorting keys in DynamoDB
mcopik 8ca8e24
[system] Fix incorrect variable name
mcopik 1fdf04f
[system] Adapt cache implementation of NoSQL to support different lay…
mcopik 2cd1bc4
[azure] Implement CosmosDB management
mcopik f90971f
[azure] Add management of CosmosDB accoutns
mcopik 020fcd6
[azure] Install locally CosmosDB library to allocate containers
mcopik 6959cd6
[azure] Add missing handler file
mcopik f089017
[azure] Allocate clients to databases and containers when they alread…
mcopik d6e14de
[system] Improved logging
mcopik 0c7906a
[azure] Export NoSQL database information
mcopik 8314f41
[system] Initialize storage before deploying function
mcopik b975d78
[azure] Help mypy recognize that variable is never None
mcopik b9ae6ca
[azure] Linting nosql wrapper
mcopik 53bb33e
[azure] Export the proper database name as env
mcopik 8d211a2
[azure] Export tables as envs
mcopik 43680a1
[azure] Fix error of allocating the same container many times
mcopik cf6fc22
[azure] Avoid creating duplicated HTTP triggers
mcopik f49714c
[aws] Remove Decimals from DynamoDB results
mcopik 36dd13f
[aws] Append environment variables to send Table data
mcopik 4312ebc
[aws] Linting
mcopik ec62b9c
[azure] Prevent overwriting existing variables
mcopik ab62ec9
[azure Add sleep to avoid problems with stale values of envs
mcopik e36cf80
[gcp] Add Google Cloud manage image with gcloud
mcopik 69fe546
[system] [aws] Move table management to each implementation to adjust…
mcopik 50f8ac6
[azure] Remove mapping of tables
mcopik b836597
[system] Fix bug in cache processing - now storage is updated before …
mcopik 853d083
[gcp] Add gcloud CLI handling
mcopik 89560ca
[system] Linting
mcopik e8288a0
[gcp] Extend Docker images
mcopik 4a944a0
[gcp] Update wrapper with database init
mcopik e511885
[gcp] Update docs with permissions
mcopik ce9076b
[aws] Ensure we update envs
mcopik 8204715
[gcp] Add management of datastore instances
mcopik 8e66ca3
[gcp] Correctly mount read-only files in CLI
mcopik 994f107
[gcp] Update function envs to support NoSQL storage
mcopik 22333a5
[benchmarks] Add initial config for 130.crud-api benchmark
mcopik 820c5b4
[benchmarks] Update module configuration
mcopik 85de381
[azure] [gcp] Fix nosql import
mcopik 7f23fe2
[azure] Move storage connection string from request to config
mcopik 2af6082
[system] Update benchmark input config
mcopik 92c7ce6
[gcp] Add missing dependency
mcopik ed00c14
[experiments] Reorder input processing and function generation
mcopik 12b475d
[whisk] Skip nosql
mcopik 06ece22
[gcp] Fix mypy issues
mcopik 7118b58
[benchmarks] Add test implementation of the CRUD benchmark
mcopik 6c78152
[benchmarks] Work in progress on the CRUD benchmark
mcopik 3d58e42
[storage] Adapt interface to multiple tiers of storage
mcopik 045f077
[local] Adapt local to the new storage config
mcopik 1c48a10
[system] First attempt to break the circular dependency between Syste…
mcopik b8b04f1
[local] Adapt new resource style
mcopik c9e2635
[system] Expand storage configuration
mcopik e9c954b
[system] remove dbg output
mcopik f4bd76f
[minio] Support data volume and explicit version
mcopik afa5d7e
[minio] Fix bug in setting volume path
mcopik a0c88ad
[scylla] Add ScyllaDB as a local NoSQL backend
mcopik 898328f
[scylla] Add stop for the container
mcopik 18f4692
[aws] Restructurize storage allocation
mcopik 67fa42b
[benchmarks] Updated version of 130.crud-api
mcopik da0e009
[system] Add initialization of NoSQL results
mcopik f953768
[aws] Implement initialization of DynamoDB
mcopik e5d72b8
[system] Fix cache issue - we now prepare benchmark data before code …
mcopik dc60969
[benchmarks] Update input API
mcopik ef54402
[system] Additional logging
mcopik ff9314c
[benchmarks] Update input API
mcopik c6463e2
[benchmarks] Fix incorrect IDs and division by zero
mcopik 9916028
[bechmarks] Implement final sizes for 130.crud-api
mcopik 9dc5d03
[aws] Implement the update method for DynamoDB
mcopik 078bdbc
[aws] Fix waiting condition when creating DynamoDB table
mcopik 3d7d1dc
[gcp] Implement new resource class
mcopik 51fafd4
[gcp] Implement upload function for Datastore
mcopik 0843b00
[gcp] Add wrapper for update function
mcopik 1a7325f
[gcp] Fix incorrect update implementation
mcopik 23ed66b
[gcp] Fix linting issues
mcopik d277923
[azure] Move resources to a different file
mcopik ff1a696
[azure] Linting
mcopik 1077605
[azure] Implement the missing function for CosmosDB
mcopik 6758863
[azure] Add the new abstraction of system resources
mcopik b9dfc92
[azure] Replace insert with upsert
mcopik 383a62b
[azure] Add NoSQL update
mcopik ecc2816
[azure] Fix allocation of database client
mcopik 0e1e1fc
[local] Add base methods for local storage config
mcopik 945b0fd
[local] Make storage paths consistent
mcopik be85773
[local] Drop unused storage config in output
mcopik 7bb8d87
[local] Ignore Docker volumes in git
mcopik a5977b7
[system] Allow for multiple input files with storage definition
mcopik c168c0f
[local] Better error description
mcopik 2caa564
[system] Remove debug printout
mcopik 2e6f75a
[local] Make storage implementation cacheable and more generic by off…
mcopik 92d610b
[local] Final standardization of volume names
mcopik 3ac12e7
[storage] Remove unnecessary storage classes
mcopik a76c7d9
[system] Fix type hint
mcopik 0a678b5
[local] Support ScyllaDB serialization
mcopik cc9c103
[local] Linting
mcopik cf66c2c
[system] Support removing functions that are no longer available
mcopik 8db684c
[aws] Linting
mcopik 223f368
[storage] Implement allocation of ScyllaDB tables
mcopik 124cf79
[storage] Fix correct deployment name in output
mcopik ecc5cbf
[storage] Linting
mcopik dae8ec1
[local] Export NoSQL settings
mcopik 1796ca8
[storage] Add default implementation of envs for NoSQL
mcopik e504674
[local] Add ScyllaDB wrapper
mcopik 0642eaa
[local] Implement function update for local container
mcopik b293f7a
[storage] Linting
mcopik 38b3b1b
[local] Add necessary files and dependencies for the ScyllaDB
mcopik 8c62560
[aws][azure][gcp] Manually cherry-pick changes to handling of environ…
mcopik 390aa81
Merge branch 'master' into feature/nosql_storage
mcopik fae0be8
[aws] Fix bug in incorrect initialization order
mcopik 8180b59
[gcp] Remove dead code
mcopik 52f80a1
[local] Updating local deployment to recent developments
mcopik a3012a7
[local] [whisk] Unify storage and resource handling
mcopik d198e83
[whisk] Remove default minio import since now it is not mandatory
mcopik e6a8ad6
[whisk] Add wrappers and dependencies for NoSQL
mcopik da3f08a
[whisk] Update action on changes to storage configuration
mcopik f6ae47d
[local] [whisk] Correct cache locations and naming in shared implemen…
mcopik f934c89
Merge branch 'master' into feature/nosql_storage
mcopik 745a275
[dev] Post-merge linting
mcopik 45e1e88
Merge branch 'master' into feature/nosql_storage
mcopik b0f56c6
[dev] Linting
mcopik 62865c4
[gcp] Add customized waiting for GCP deployment
mcopik 77efd85
[system] Remove unnecessary skipping of storage update
mcopik 5b31152
[gcp] Decrease length of function name
mcopik 5e3917d
[system] Add 130.crud-api to regression
mcopik 9c12dfc
[system] Make sure that NoSQL and storage is initialized before we cr…
mcopik a87945c
[system] Update resource removal
mcopik f441e2f
[system] Better output for incorrect CLI option
mcopik 69e83aa
[aws] Properly support ARM containers
mcopik 9fc01e3
[system] Separate regression into different deployment types
mcopik 0c7d25c
[benchmarks] Rename nosql_func to something more descriptive
mcopik 9ebe877
[system] Change order of initializing data and caching
mcopik 6d8229f
[system] Address review comments - docs, naming
mcopik 130c3d6
[aws] Add waiters to make sure DynamoDB table is ready before using
mcopik 5a6b01e
[system] Linting for regression
mcopik 4616b99
[docs] Update jq instructions since argfile is deprecated
mcopik 2ce6dbc
[system] Fix regression initialization for Openwhisk
mcopik 084e018
[aws][system] Add versioning to build images
mcopik 519842c
[system] Remove unnecessary output
mcopik 6887ae2
[system] Make sure to remove builder images
mcopik 7f2bb49
[system] Bump version to the upcoming release
mcopik b47f427
[azure] Make regression work again
mcopik 1a9ea66
[azure] Improve catching non-existing resource error
mcopik bd8d6fb
[azure] Move envs update before code publish
mcopik e20215c
[azure] Linting
mcopik b110cd5
[gcp] Remove leftover package installation for GCP
mcopik d0f98c5
[system] Make installation of modules dependent on language version
mcopik 73ec8e1
[system] Linting
mcopik dcf7fc1
[docs] Update documentation of the new benchmark
mcopik 14a3977
[system] Correctly stop all storage containers
mcopik b377e4a
[system] Remove unnecessary JSON fields of the storage configuration
mcopik cacbd66
[docs] Update documentation of storage options
mcopik cf95c57
Update platforms.md
mcopik 58ca223
[system] Update storage.md
mcopik 664d03e
[dev] Linting
mcopik File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Submodule benchmarks-data
updated
6 files
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| { | ||
| "timeout": 10, | ||
| "memory": 128, | ||
| "languages": ["python", "nodejs"] | ||
| "languages": ["python", "nodejs"], | ||
| "modules": [] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| { | ||
| "timeout": 30, | ||
| "memory": 128, | ||
| "languages": ["python", "nodejs"] | ||
| "languages": ["python", "nodejs"], | ||
| "modules": ["storage"] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| { | ||
| "timeout": 30, | ||
| "memory": 128, | ||
| "languages": [ | ||
| "python", | ||
| "nodejs" | ||
| ], | ||
| "modules": [ | ||
| "nosql" | ||
| ] | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| import uuid | ||
|
|
||
|
|
||
| def allocate_nosql() -> dict: | ||
| return {"shopping_cart": {"primary_key": "cart_id", "secondary_key": "product_id"}} | ||
|
|
||
|
|
||
| def generate_input( | ||
| data_dir, size, benchmarks_bucket, input_buckets, output_buckets, upload_func, nosql_upload | ||
| ): | ||
|
|
||
| input_config = {} | ||
|
|
||
| cart_id = str(uuid.uuid4().hex) | ||
| write_cart_id = str(uuid.uuid4().hex) | ||
|
|
||
| # Set initial data | ||
|
|
||
| nosql_upload( | ||
| "130.crud-api", | ||
| "shopping_cart", | ||
| {"name": "Gothic Game", "price": 42, "quantity": 2}, | ||
| ("cart_id", cart_id), | ||
| ("product_id", "game-gothic"), | ||
| ) | ||
| nosql_upload( | ||
| "130.crud-api", | ||
| "shopping_cart", | ||
| {"name": "Gothic 2", "price": 142, "quantity": 3}, | ||
| ("cart_id", cart_id), | ||
| ("product_id", "game-gothic-2"), | ||
| ) | ||
| nosql_upload( | ||
| "130.crud-api", | ||
| "shopping_cart", | ||
| {"name": "SeBS Benchmark", "price": 1000, "quantity": 1}, | ||
| ("cart_id", cart_id), | ||
| ("product_id", "sebs-benchmark"), | ||
| ) | ||
| nosql_upload( | ||
| "130.crud-api", | ||
| "shopping_cart", | ||
| {"name": "Mint Linux", "price": 0, "quantity": 5}, | ||
| ("cart_id", cart_id), | ||
| ("product_id", "mint-linux"), | ||
| ) | ||
|
|
||
| requests = [] | ||
|
|
||
| if size == "test": | ||
| # retrieve a single entry | ||
| requests.append( | ||
| { | ||
| "route": "GET /cart/{id}", | ||
| "path": {"id": "game-gothic"}, | ||
| "body": { | ||
| "cart": cart_id, | ||
| }, | ||
| } | ||
| ) | ||
| elif size == "small": | ||
| requests.append( | ||
| { | ||
| "route": "GET /cart", | ||
| "body": { | ||
| "cart": cart_id, | ||
| }, | ||
| } | ||
| ) | ||
| elif size == "large": | ||
| # add many new entries | ||
| for i in range(5): | ||
| requests.append( | ||
| { | ||
| "route": "PUT /cart", | ||
| "body": { | ||
| "cart": write_cart_id, | ||
| "product_id": f"new-id-{i}", | ||
| "name": f"Test Item {i}", | ||
| "price": 100 * i, | ||
| "quantity": i, | ||
| }, | ||
| } | ||
| ) | ||
| requests.append( | ||
| { | ||
| "route": "GET /cart", | ||
| "body": { | ||
| "cart": write_cart_id, | ||
| }, | ||
| } | ||
| ) | ||
|
|
||
| input_config["requests"] = requests | ||
|
|
||
| return input_config |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| from . import nosql | ||
|
|
||
| nosql_client = nosql.nosql.get_instance() | ||
|
|
||
| nosql_table_name = "shopping_cart" | ||
|
|
||
|
|
||
| def add_product(cart_id: str, product_id: str, product_name: str, price: float, quantity: int): | ||
|
|
||
| nosql_client.insert( | ||
| nosql_table_name, | ||
| ("cart_id", cart_id), | ||
| ("product_id", product_id), | ||
| {"price": price, "quantity": quantity, "name": product_name}, | ||
| ) | ||
|
|
||
|
|
||
| def get_products(cart_id: str, product_id: str): | ||
| return nosql_client.get(nosql_table_name, ("cart_id", cart_id), ("product_id", product_id)) | ||
|
|
||
|
|
||
| def query_products(cart_id: str): | ||
|
|
||
| res = nosql_client.query( | ||
| nosql_table_name, | ||
| ("cart_id", cart_id), | ||
| "product_id", | ||
| ) | ||
|
|
||
| products = [] | ||
| price_sum = 0 | ||
| quantity_sum = 0 | ||
| for product in res: | ||
|
|
||
| products.append(product["name"]) | ||
| price_sum += product["price"] | ||
| quantity_sum += product["quantity"] | ||
|
|
||
| avg_price = price_sum / quantity_sum if quantity_sum > 0 else 0.0 | ||
|
|
||
| return {"products": products, "total_cost": price_sum, "avg_price": avg_price} | ||
|
|
||
|
|
||
| def handler(event): | ||
|
|
||
| results = [] | ||
|
|
||
| for request in event["requests"]: | ||
|
|
||
| route = request["route"] | ||
| body = request["body"] | ||
|
|
||
| if route == "PUT /cart": | ||
| add_product( | ||
| body["cart"], body["product_id"], body["name"], body["price"], body["quantity"] | ||
| ) | ||
| res = {} | ||
| elif route == "GET /cart/{id}": | ||
| res = get_products(body["cart"], request["path"]["id"]) | ||
| elif route == "GET /cart": | ||
| res = query_products(body["cart"]) | ||
| else: | ||
| raise RuntimeError(f"Unknown request route: {route}") | ||
|
|
||
| results.append(res) | ||
|
|
||
| return {"result": results} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| { | ||
| "timeout": 60, | ||
| "memory": 256, | ||
| "languages": ["python", "nodejs"] | ||
| "languages": ["python", "nodejs"], | ||
| "modules": ["storage"] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| { | ||
| "timeout": 60, | ||
| "memory": 512, | ||
| "languages": ["python"] | ||
| "languages": ["python"], | ||
| "modules": ["storage"] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| { | ||
| "timeout": 60, | ||
| "memory": 256, | ||
| "languages": ["python", "nodejs"] | ||
| "languages": ["python", "nodejs"], | ||
| "modules": ["storage"] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| { | ||
| "timeout": 60, | ||
| "memory": 512, | ||
| "languages": ["python"] | ||
| "languages": ["python"], | ||
| "modules": ["storage"] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| { | ||
| "timeout": 120, | ||
| "memory": 512, | ||
| "languages": ["python"] | ||
| "languages": ["python"], | ||
| "modules": [] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| { | ||
| "timeout": 120, | ||
| "memory": 512, | ||
| "languages": ["python"] | ||
| "languages": ["python"], | ||
| "modules": [] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| { | ||
| "timeout": 120, | ||
| "memory": 512, | ||
| "languages": ["python"] | ||
| "languages": ["python"], | ||
| "modules": [] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| { | ||
| "timeout": 60, | ||
| "memory": 2048, | ||
| "languages": ["python"] | ||
| "languages": ["python"], | ||
| "modules": ["storage"] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.