From 21c70ea228d5e10b802b490c31574c82d2f667fc Mon Sep 17 00:00:00 2001
From: Nick Ludwig <51385718+nickludwig@users.noreply.github.com>
Date: Thu, 14 Apr 2022 10:27:36 -0700
Subject: [PATCH 01/39] note about POST support for end_session_endpoint
AAD supports HTTP POST requests on the `end_session_endpoint`. However, this isn't mentioned in the OIDC doc. I'm proposing an extremely minor change to fix this.
-------
cc: @nickludwig
---
articles/active-directory/develop/v2-protocols-oidc.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/articles/active-directory/develop/v2-protocols-oidc.md b/articles/active-directory/develop/v2-protocols-oidc.md
index 195f099a461ea..734d813cd3ecb 100644
--- a/articles/active-directory/develop/v2-protocols-oidc.md
+++ b/articles/active-directory/develop/v2-protocols-oidc.md
@@ -284,7 +284,7 @@ Review the [UserInfo documentation](userinfo.md#calling-the-api) to look over ho
When you want to sign out the user from your app, it isn't sufficient to clear your app's cookies or otherwise end the user's session. You must also redirect the user to the Microsoft identity platform to sign out. If you don't do this, the user reauthenticates to your app without entering their credentials again, because they will have a valid single sign-in session with the Microsoft identity platform.
-You can redirect the user to the `end_session_endpoint` listed in the OpenID Connect metadata document:
+You can redirect the user to the `end_session_endpoint` (which supports both HTTP GET and POST requests) listed in the OpenID Connect metadata document:
```HTTP
GET https://login.microsoftonline.com/common/oauth2/v2.0/logout?
From afd266c57e1cede66f22f605db81dde9aa6f344f Mon Sep 17 00:00:00 2001
From: "Kalyan Kadiyala @ Microsoft"
<52089565+kalyankadiyala-Microsoft@users.noreply.github.com>
Date: Mon, 18 Apr 2022 11:26:27 -0700
Subject: [PATCH 02/39] Fixed a typo where DATASOURCE should be spelled as
DATA_SOURCE
---
.../spark/synapse-spark-sql-pool-import-export.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md b/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
index 8676627fb5596..6a6d656bbc21d 100644
--- a/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
+++ b/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
@@ -144,8 +144,8 @@ Following table describes the essential configuration options that must be set f
|Usage Scenario| Options to configure |
|--------------|----------------------------------|
-| Write using Azure AD based authentication |
- Azure Synapse Dedicated SQL End Point
- `Constants.SERVER`
- By default, the Connector will infer the Synapse Dedicated SQL End Point associated with the database name (from the three part table name argument to `synapsesql` method).
- Alternatively, users can provide the `Constants.SERVER` option.
- Azure Data Lake Storage (Gen 2) End Point - Staging Folders
- For Internal Table Type:
- Configure either `Constants.TEMP_FOLDER` or `Constants.DATASOURCE` option.
- If user chose to provide `Constants.DATASOURCE` option, staging folder will be derived by using the `location` value on the DataSource.
- If both are provided, then the `Constants.TEMP_FOLDER` option value will be used.
- In the absence of a staging folder option, the Connector will derive one based on the runtime configuration - `spark.sqlanalyticsconnector.stagingdir.prefix`.
- For External Table Type:
- `Constants.DATASOURCE` is a required configuration option.
- The storage path defined on the Data Source's `location` parameter will be used as the base path to establish final absolute path.
- The base path is then appended with the value set on the `synapsesql` method's `location` argument, example `/`.
- If the `location` argument to `synapsesql` method isn't provided, then the connector will derive the location value as `/dbName/schemaName/tableName`.
|
-| Write using Basic Authentication | - Azure Synapse Dedicated SQL End Point
- `Constants.SERVER` - Synapse Dedicated SQL Pool End Point (Server FQDN)
- `Constants.USER` - SQL User Name.
- `Constants.PASSWORD` - SQL User Password.
- `Constants.STAGING_STORAGE_ACCOUNT_KEY` associated with Storage Account that hosts `Constants.TEMP_FOLDERS` (internal table types only) or `Constants.DATASOURCE`.
- Azure Data Lake Storage (Gen 2) End Point - Staging Folders
- SQL basic authentication credentials don't apply to access storage end points. Hence it's required that the workspace user identity is given relevant access permissions (reference the section - [Azure Data Lake Storage Gen2](#azure-data-lake-storage-gen2).
|
+| Write using Azure AD based authentication | - Azure Synapse Dedicated SQL End Point
- `Constants.SERVER`
- By default, the Connector will infer the Synapse Dedicated SQL End Point associated with the database name (from the three part table name argument to `synapsesql` method).
- Alternatively, users can provide the `Constants.SERVER` option.
- Azure Data Lake Storage (Gen 2) End Point - Staging Folders
- For Internal Table Type:
- Configure either `Constants.TEMP_FOLDER` or `Constants.DATA_SOURCE` option.
- If user chose to provide `Constants.DATA_SOURCE` option, staging folder will be derived by using the `location` value from the DataSource.
- If both are provided, then the `Constants.TEMP_FOLDER` option value will be used.
- In the absence of a staging folder option, the Connector will derive one based on the runtime configuration - `spark.sqlanalyticsconnector.stagingdir.prefix`.
- For External Table Type:
- `Constants.DATA_SOURCE` is a required configuration option.
- The storage path defined on the Data Source's `location` parameter will be used as the base path to establish final absolute path.
- The base path is then appended with the value set on the `synapsesql` method's `location` argument, example `/`.
- If the `location` argument to `synapsesql` method isn't provided, then the connector will derive the location value as `/dbName/schemaName/tableName`.
|
+| Write using Basic Authentication | - Azure Synapse Dedicated SQL End Point
- `Constants.SERVER` - Synapse Dedicated SQL Pool End Point (Server FQDN)
- `Constants.USER` - SQL User Name.
- `Constants.PASSWORD` - SQL User Password.
- `Constants.STAGING_STORAGE_ACCOUNT_KEY` associated with Storage Account that hosts `Constants.TEMP_FOLDERS` (internal table types only) or `Constants.DATA_SOURCE`.
- Azure Data Lake Storage (Gen 2) End Point - Staging Folders
- SQL basic authentication credentials don't apply to access storage end points. Hence it's required that the workspace user identity is given relevant access permissions (reference the section - [Azure Data Lake Storage Gen2](#azure-data-lake-storage-gen2).
|
|Read using Azure AD based authentication|- Credentials are auto-mapped, and user isn't required to provide specific configuration options.
- Three-part table name argument on `synapsesql` method is required to read from respective table in Azure Synapse Dedicated SQL Pool.
|
|Read using basic authentication|- Azure Synapse Dedicated SQL End Point
- `Constants.SERVER` - Synapse Dedicated SQL Pool End Point (Server FQDN)
- `Constants.USER` - SQL User Name.
- `Constants.PASSWORD` - SQL User Password.
- Azure Data Lake Storage (Gen 2) End Point - Staging Folders
- `Constants.DATA_SOURCE` - Location setting from data source is used to stage extracted data from Azure Synapse Dedicated SQL End Point.
|
From 8b301afd994a20c214f630920dc667ff741212ab Mon Sep 17 00:00:00 2001
From: Simon Kurtz <84809797+simonkurtz-MSFT@users.noreply.github.com>
Date: Thu, 21 Apr 2022 12:49:42 -0400
Subject: [PATCH 03/39] Update api-management-advanced-policies.md
I would like to add a `retry` example involving a `send-request` as this is a use case I just encountered with my customer to get additional information before the call to the backend can proceed. I see this use case as one that many customers may have and could benefit from having this example.
-------
cc: @dlepow
---
.../api-management-advanced-policies.md | 23 +++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/articles/api-management/api-management-advanced-policies.md b/articles/api-management/api-management-advanced-policies.md
index ba55d5aaeaf39..9542eb18036f5 100644
--- a/articles/api-management/api-management-advanced-policies.md
+++ b/articles/api-management/api-management-advanced-policies.md
@@ -536,6 +536,29 @@ In the following example, request forwarding is retried up to ten times using an
```
+### Example
+
+In the following example, sending a request to a URL other than the defined backend is retried up to three times if a) the connections is dropped/timed out, or b) the requests results in a server-side error. Since `first-fast-retry` is set to true, the first retry is executed immediately upon the initial request failure. Note that `send-request` must set `ignore-error` to true in order for `response-variable-name` to be null in the event of an error.
+
+```xml
+
+= 500)"
+ count="3"
+ interval="1"
+ first-fast-retry="true">
+
+ https://api.contoso.com/products/5
+ GET
+
+
+
+```
+
### Elements
| Element | Description | Required |
From 0f59a27e9b917cf2cb8ba89821302b6bee411671 Mon Sep 17 00:00:00 2001
From: Simon Kurtz <84809797+simonkurtz-MSFT@users.noreply.github.com>
Date: Sat, 23 Apr 2022 07:26:28 -0400
Subject: [PATCH 04/39] Update
articles/api-management/api-management-advanced-policies.md
Co-authored-by: Dan Lepow
---
articles/api-management/api-management-advanced-policies.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/articles/api-management/api-management-advanced-policies.md b/articles/api-management/api-management-advanced-policies.md
index 9542eb18036f5..63f4995efbf27 100644
--- a/articles/api-management/api-management-advanced-policies.md
+++ b/articles/api-management/api-management-advanced-policies.md
@@ -538,7 +538,7 @@ In the following example, request forwarding is retried up to ten times using an
### Example
-In the following example, sending a request to a URL other than the defined backend is retried up to three times if a) the connections is dropped/timed out, or b) the requests results in a server-side error. Since `first-fast-retry` is set to true, the first retry is executed immediately upon the initial request failure. Note that `send-request` must set `ignore-error` to true in order for `response-variable-name` to be null in the event of an error.
+In the following example, sending a request to a URL other than the defined backend is retried up to three times if the connection is dropped/timed out, or the request results in a server-side error. Since `first-fast-retry` is set to true, the first retry is executed immediately upon the initial request failure. Note that `send-request` must set `ignore-error` to true in order for `response-variable-name` to be null in the event of an error.
```xml
From 2a661a1c7c6841cca95ec5bfdbd7ba2b654bdd90 Mon Sep 17 00:00:00 2001
From: "Kalyan Kadiyala @ Microsoft"
<52089565+kalyankadiyala-Microsoft@users.noreply.github.com>
Date: Mon, 25 Apr 2022 12:18:17 -0700
Subject: [PATCH 05/39] Re-arrange sections in the order - Read followed by
Write
---
.../synapse-spark-sql-pool-import-export.md | 186 +++++++++---------
1 file changed, 93 insertions(+), 93 deletions(-)
diff --git a/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md b/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
index 6a6d656bbc21d..362a30bda2302 100644
--- a/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
+++ b/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
@@ -17,6 +17,10 @@ The Azure Synapse Dedicated SQL Pool Connector for Apache Spark in Azure Synapse
At a high-level, the connector provides the following capabilities:
+* Read from Azure Synapse Dedicated SQL Pool:
+ * Read large data sets from Synapse Dedicated SQL Pool Tables (Internal and External) and Views.
+ * Comprehensive predicate push down support, where filters on DataFrame get mapped to corresponding SQL predicate push down.
+ * Support for column pruning.
* Write to Azure Synapse Dedicated SQL Pool:
* Ingest large volume data to Internal and External table types.
* Supports following DataFrame save mode preferences:
@@ -29,21 +33,17 @@ At a high-level, the connector provides the following capabilities:
* Enhancements to optimize end-to-end write throughput performance.
* Introduces an optional call-back handle (a Scala function argument) that clients can use to receive post-write metrics.
* Few examples include - number of records, duration to complete certain action, and failure reason.
-* Read from Azure Synapse Dedicated SQL Pool:
- * Read large data sets from Synapse Dedicated SQL Pool Tables (Internal and External) and Views.
- * Comprehensive predicate push down support, where filters on DataFrame get mapped to corresponding SQL predicate push down.
- * Support for column pruning.
## Orchestration Approach
-### Write
-
-![Write-Orchestration](./media/synapse-spark-sql-pool-import-export/synapse-dedicated-sql-pool-spark-connector-write-orchestration.png)
-
### Read
![Read-Orchestration](./media/synapse-spark-sql-pool-import-export/synapse-dedicated-sql-pool-spark-connector-read-orchestration.png)
+### Write
+
+![Write-Orchestration](./media/synapse-spark-sql-pool-import-export/synapse-dedicated-sql-pool-spark-connector-write-orchestration.png)
+
## Pre-requisites
This section details necessary pre-requisite steps include Azure Resource setup and Configurations including authentication and authorization requirements for using the Azure Synapse Dedicated SQL Pool Connector for Apache Spark.
@@ -108,6 +108,13 @@ There are two ways to grant access permissions to Azure Data Lake Storage Gen2 -
To enable successful interaction with Azure Synapse Dedicated SQL Pool, following authorization is necessary unless you're a user also configured as an `Active Directory Admin` on the Dedicated SQL End Point:
+* Read Scenario
+ * Grant the user `db_exporter` using the system stored procedure `sp_addrolemember`.
+
+ ```sql
+ EXEC sp_addrolemember 'db_exporter', [@.com];
+ ```
+
* Write Scenario
* Connector uses the COPY command to write data from staging to the internal table's managed location.
* Configure required permissions described [here](../../synapse-analytics/sql-data-warehouse/quickstart-bulk-load-copy-tsql.md#set-up-the-required-permissions).
@@ -125,13 +132,6 @@ To enable successful interaction with Azure Synapse Dedicated SQL Pool, followin
GRANT INSERT ON TO [@.com]
```
-* Read Scenario
- * Grant the user `db_exporter` using the system stored procedure `sp_addrolemember`.
-
- ```sql
- EXEC sp_addrolemember 'db_exporter', [@.com];
- ```
-
## Connector API Documentation
Azure Synapse Dedicated SQL Pool Connector for Apache Spark - [API Documentation](https://synapsesql.blob.core.windows.net/docs/latest/scala/index.html).
@@ -144,15 +144,86 @@ Following table describes the essential configuration options that must be set f
|Usage Scenario| Options to configure |
|--------------|----------------------------------|
-| Write using Azure AD based authentication | - Azure Synapse Dedicated SQL End Point
- `Constants.SERVER`
- By default, the Connector will infer the Synapse Dedicated SQL End Point associated with the database name (from the three part table name argument to `synapsesql` method).
- Alternatively, users can provide the `Constants.SERVER` option.
- Azure Data Lake Storage (Gen 2) End Point - Staging Folders
- For Internal Table Type:
- Configure either `Constants.TEMP_FOLDER` or `Constants.DATA_SOURCE` option.
- If user chose to provide `Constants.DATA_SOURCE` option, staging folder will be derived by using the `location` value from the DataSource.
- If both are provided, then the `Constants.TEMP_FOLDER` option value will be used.
- In the absence of a staging folder option, the Connector will derive one based on the runtime configuration - `spark.sqlanalyticsconnector.stagingdir.prefix`.
- For External Table Type:
- `Constants.DATA_SOURCE` is a required configuration option.
- The storage path defined on the Data Source's `location` parameter will be used as the base path to establish final absolute path.
- The base path is then appended with the value set on the `synapsesql` method's `location` argument, example `/`.
- If the `location` argument to `synapsesql` method isn't provided, then the connector will derive the location value as `/dbName/schemaName/tableName`.
|
-| Write using Basic Authentication | - Azure Synapse Dedicated SQL End Point
- `Constants.SERVER` - Synapse Dedicated SQL Pool End Point (Server FQDN)
- `Constants.USER` - SQL User Name.
- `Constants.PASSWORD` - SQL User Password.
- `Constants.STAGING_STORAGE_ACCOUNT_KEY` associated with Storage Account that hosts `Constants.TEMP_FOLDERS` (internal table types only) or `Constants.DATA_SOURCE`.
- Azure Data Lake Storage (Gen 2) End Point - Staging Folders
- SQL basic authentication credentials don't apply to access storage end points. Hence it's required that the workspace user identity is given relevant access permissions (reference the section - [Azure Data Lake Storage Gen2](#azure-data-lake-storage-gen2).
|
|Read using Azure AD based authentication|- Credentials are auto-mapped, and user isn't required to provide specific configuration options.
- Three-part table name argument on `synapsesql` method is required to read from respective table in Azure Synapse Dedicated SQL Pool.
|
|Read using basic authentication|- Azure Synapse Dedicated SQL End Point
- `Constants.SERVER` - Synapse Dedicated SQL Pool End Point (Server FQDN)
- `Constants.USER` - SQL User Name.
- `Constants.PASSWORD` - SQL User Password.
- Azure Data Lake Storage (Gen 2) End Point - Staging Folders
- `Constants.DATA_SOURCE` - Location setting from data source is used to stage extracted data from Azure Synapse Dedicated SQL End Point.
|
+| Write using Azure AD based authentication | - Azure Synapse Dedicated SQL End Point
- `Constants.SERVER`
- By default, the Connector will infer the Synapse Dedicated SQL End Point associated with the database name (from the three part table name argument to `synapsesql` method).
- Alternatively, users can provide the `Constants.SERVER` option.
- Azure Data Lake Storage (Gen 2) End Point - Staging Folders
- For Internal Table Type:
- Configure either `Constants.TEMP_FOLDER` or `Constants.DATA_SOURCE` option.
- If user chose to provide `Constants.DATA_SOURCE` option, staging folder will be derived by using the `location` value from the DataSource.
- If both are provided, then the `Constants.TEMP_FOLDER` option value will be used.
- In the absence of a staging folder option, the Connector will derive one based on the runtime configuration - `spark.sqlanalyticsconnector.stagingdir.prefix`.
- For External Table Type:
- `Constants.DATA_SOURCE` is a required configuration option.
- The storage path defined on the Data Source's `location` parameter will be used as the base path to establish final absolute path.
- The base path is then appended with the value set on the `synapsesql` method's `location` argument, example `/`.
- If the `location` argument to `synapsesql` method isn't provided, then the connector will derive the location value as `/dbName/schemaName/tableName`.
|
+| Write using Basic Authentication | - Azure Synapse Dedicated SQL End Point
- `Constants.SERVER` - Synapse Dedicated SQL Pool End Point (Server FQDN)
- `Constants.USER` - SQL User Name.
- `Constants.PASSWORD` - SQL User Password.
- `Constants.STAGING_STORAGE_ACCOUNT_KEY` associated with Storage Account that hosts `Constants.TEMP_FOLDERS` (internal table types only) or `Constants.DATA_SOURCE`.
- Azure Data Lake Storage (Gen 2) End Point - Staging Folders
- SQL basic authentication credentials don't apply to access storage end points. Hence it's required that the workspace user identity is given relevant access permissions (reference the section - [Azure Data Lake Storage Gen2](#azure-data-lake-storage-gen2).
|
## Code Templates
This section presents reference code templates to describe how to use and invoke the Azure Synapse Dedicated SQL Pool Connector for Apache Spark.
+### Read from Azure Synapse Dedicated SQL Pool
+
+#### Read Request - `synapsesql` Method Signature
+
+```Scala
+synapsesql(tableName:String) => org.apache.spark.sql.DataFrame
+```
+
+#### Read using Azure AD based authentication
+
+```Scala
+//Use case is to read data from an internal table in Synapse Dedicated SQL Pool DB
+//Azure Active Directory based authentication approach is preferred here.
+import org.apache.spark.sql.DataFrame
+import com.microsoft.spark.sqlanalytics.utils.Constants
+import org.apache.spark.sql.SqlAnalyticsConnector._
+
+//Read from existing internal table
+val dfToReadFromTable:DataFrame = spark.read.
+ //If `Constants.SERVER` is not provided, the `` from the three-part table name argument
+ //to `synapsesql` method is used to infer the Synapse Dedicated SQL End Point.
+ option(Constants.SERVER, ".sql.azuresynapse.net").
+ //Defaults to storage path defined in the runtime configurations (See section on Configuration Options above).
+ option(Constants.TEMP_FOLDER, "abfss://@.dfs.core.windows.net/").
+ //Three-part table name from where data will be read.
+ synapsesql("..").
+ //Column-pruning i.e., query select column values.
+ select("", "", "").
+ //Push-down filter criteria that gets translated to SQL Push-down Predicates.
+ filter(col("Title").startsWith("E")).
+ //Fetch a sample of 10 records
+ limit(10)
+
+//Show contents of the dataframe
+dfToReadFromTable.show()
+```
+
+#### Read using basic authentication
+
+```Scala
+//Use case is to read data from an internal table in Synapse Dedicated SQL Pool DB
+//Azure Active Directory based authentication approach is preferred here.
+import org.apache.spark.sql.DataFrame
+import com.microsoft.spark.sqlanalytics.utils.Constants
+import org.apache.spark.sql.SqlAnalyticsConnector._
+
+//Read from existing internal table
+val dfToReadFromTable:DataFrame = spark.read.
+ //If `Constants.SERVER` is not provided, the `` from the three-part table name argument
+ //to `synapsesql` method is used to infer the Synapse Dedicated SQL End Point.
+ option(Constants.SERVER, ".sql.azuresynapse.net").
+ //Set database user name
+ option(Constants.USER, "").
+ //Set user's password to the database
+ option(Constants.PASSWORD, "").
+ //Set name of the data source definition that is defined with database scoped credentials.
+ //Data extracted from the SQL query will be staged to the storage path defined on the data source's location setting.
+ option(Constants.DATA_SOURCE, "").
+ //Three-part table name from where data will be read.
+ synapsesql("..").
+ //Column-pruning i.e., query select column values.
+ select("", "", "").
+ //Push-down filter criteria that gets translated to SQL Push-down Predicates.
+ filter(col("Title").startsWith("E")).
+ //Fetch a sample of 10 records
+ limit(10)
+
+//Show contents of the dataframe
+dfToReadFromTable.show()
+```
+
### Write to Azure Synapse Dedicated SQL Pool
#### Write Request - `synapsesql` Method Signature
@@ -176,7 +247,7 @@ synapsesql(tableName:String,
callBackHandle=Option[(Map[String, Any], Option[Throwable])=>Unit]):Unit
```
-### Write using Azure AD based Authentication
+#### Write using Azure AD based Authentication
Following is a comprehensive code template that describes how to use the Connector for write scenarios:
@@ -362,77 +433,6 @@ Following is a sample JSON string with post-write metrics:
}
```
-### Read from Azure Synapse Dedicated SQL Pool
-
-#### Read Request - `synapsesql` Method Signature
-
-```Scala
-synapsesql(tableName:String) => org.apache.spark.sql.DataFrame
-```
-
-#### Read using Azure AD based authentication
-
-```Scala
-//Use case is to read data from an internal table in Synapse Dedicated SQL Pool DB
-//Azure Active Directory based authentication approach is preferred here.
-import org.apache.spark.sql.DataFrame
-import com.microsoft.spark.sqlanalytics.utils.Constants
-import org.apache.spark.sql.SqlAnalyticsConnector._
-
-//Read from existing internal table
-val dfToReadFromTable:DataFrame = spark.read.
- //If `Constants.SERVER` is not provided, the `` from the three-part table name argument
- //to `synapsesql` method is used to infer the Synapse Dedicated SQL End Point.
- option(Constants.SERVER, ".sql.azuresynapse.net").
- //Defaults to storage path defined in the runtime configurations (See section on Configuration Options above).
- option(Constants.TEMP_FOLDER, "abfss://@.dfs.core.windows.net/").
- //Three-part table name from where data will be read.
- synapsesql("..").
- //Column-pruning i.e., query select column values.
- select("", "", "").
- //Push-down filter criteria that gets translated to SQL Push-down Predicates.
- filter(col("Title").startsWith("E")).
- //Fetch a sample of 10 records
- limit(10)
-
-//Show contents of the dataframe
-dfToReadFromTable.show()
-```
-
-#### Read using basic authentication
-
-```Scala
-//Use case is to read data from an internal table in Synapse Dedicated SQL Pool DB
-//Azure Active Directory based authentication approach is preferred here.
-import org.apache.spark.sql.DataFrame
-import com.microsoft.spark.sqlanalytics.utils.Constants
-import org.apache.spark.sql.SqlAnalyticsConnector._
-
-//Read from existing internal table
-val dfToReadFromTable:DataFrame = spark.read.
- //If `Constants.SERVER` is not provided, the `` from the three-part table name argument
- //to `synapsesql` method is used to infer the Synapse Dedicated SQL End Point.
- option(Constants.SERVER, ".sql.azuresynapse.net").
- //Set database user name
- option(Constants.USER, "").
- //Set user's password to the database
- option(Constants.PASSWORD, "").
- //Set name of the data source definition that is defined with database scoped credentials.
- //Data extracted from the SQL query will be staged to the storage path defined on the data source's location setting.
- option(Constants.DATA_SOURCE, "").
- //Three-part table name from where data will be read.
- synapsesql("..").
- //Column-pruning i.e., query select column values.
- select("", "", "").
- //Push-down filter criteria that gets translated to SQL Push-down Predicates.
- filter(col("Title").startsWith("E")).
- //Fetch a sample of 10 records
- limit(10)
-
-//Show contents of the dataframe
-dfToReadFromTable.show()
-```
-
### More Code Samples
#### Using the Connector with Other language preferences
@@ -501,6 +501,10 @@ By default, a write response is printed to the cell output. On failure, the curr
## Things to Note
+* When reading from the Azure Synapse Dedicated SQL Pool tables:
+ * Consider applying necessary filters on the DataFrame to take advantage of the Connector's column-pruning feature.
+ * Read scenario doesn't support the `TOP(n-rows)` clause, when framing the `SELECT` query statements. The choice to limit data is to use the DataFrame's limit(.) clause.
+ * Refer the example - [Using materialized data across cells](#using-materialized-data-across-cells) section.
* When writing to the Azure Synapse Dedicated SQL Pool tables:
* For internal table types:
* Tables are created with ROUND_ROBIN data distribution.
@@ -510,10 +514,6 @@ By default, a write response is printed to the cell output. On failure, the curr
* Column types are inferred from the DataFrame that would read data from source.
* Better data distribution across executors can be achieved by tuning the `spark.sql.files.maxPartitionBytes` and the DataFrame's `repartition` parameter.
* When writing large data sets, it's important to factor in the impact of [DWU Performance Level](../../synapse-analytics/sql-data-warehouse/quickstart-scale-compute-portal.md) setting that limits [transaction size](../../synapse-analytics/sql-data-warehouse/sql-data-warehouse-develop-transactions.md#transaction-size).
-* When reading from the Azure Synapse Dedicated SQL Pool tables:
- * Consider applying necessary filters on the DataFrame to take advantage of the Connector's column-pruning feature.
- * Read scenario doesn't support the `TOP(n-rows)` clause, when framing the `SELECT` query statements. The choice to limit data is to use the DataFrame's limit(.) clause.
- * Refer the example - [Using materialized data across cells](#using-materialized-data-across-cells) section.
* Monitor [Azure Data Lake Storage Gen2](../../storage/blobs/data-lake-storage-best-practices.md) utilization trends to spot throttling behaviors that can [impact](../../storage/common/scalability-targets-standard-account.md) read and write performance.
## References
From 42dbefb86240955895fe179738b63bc78a16bbd6 Mon Sep 17 00:00:00 2001
From: "Kalyan Kadiyala @ Microsoft"
<52089565+kalyankadiyala-Microsoft@users.noreply.github.com>
Date: Mon, 25 Apr 2022 12:39:38 -0700
Subject: [PATCH 06/39] Note about running connector code using pipeline
execution mode.
---
.../spark/synapse-spark-sql-pool-import-export.md | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md b/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
index 362a30bda2302..e81f695e7812e 100644
--- a/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
+++ b/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
@@ -104,6 +104,11 @@ There are two ways to grant access permissions to Azure Data Lake Storage Gen2 -
* `Write` enables ability to write.
* It's important to configure ACLs such that the Connector can successfully write and read from the storage locations.
+>[!Note]
+> * If your use case involves use of Synapse Workspace pipelines to run notebooks, you must grant above mentioned access permissions to the workspace default managed identity. The name of the workspace default identity will be same as the workspace.
+>
+> * To use the Synapse workspace with secured storage accounts, a managed private end point must be [configured](../../storage/common/storage-network-security.md?tabs=azure-portal) from the notebook. The managed private end point must be approved from the ADLS Gen2 storage account's `Private endpoint connections` section in the `Networking` pane.
+
#### [Azure Synapse Dedicated SQL Pool](../../synapse-analytics/sql-data-warehouse/sql-data-warehouse-overview-what-is.md)
To enable successful interaction with Azure Synapse Dedicated SQL Pool, following authorization is necessary unless you're a user also configured as an `Active Directory Admin` on the Dedicated SQL End Point:
From 67c7d881a26b9ced0a38ee6fa55c36c0e8889139 Mon Sep 17 00:00:00 2001
From: "Kalyan Kadiyala @ Microsoft"
<52089565+kalyankadiyala-Microsoft@users.noreply.github.com>
Date: Mon, 25 Apr 2022 12:47:06 -0700
Subject: [PATCH 07/39] typo fix.
---
.../spark/synapse-spark-sql-pool-import-export.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md b/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
index e81f695e7812e..8f11c3a9da9ae 100644
--- a/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
+++ b/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
@@ -332,7 +332,7 @@ val writeOptionsWithBasicAuth:Map[String, String] = Map(Constants.SERVER -> "..",
From 63a279d49fbb77514d8694225c5490022b0464a0 Mon Sep 17 00:00:00 2001
From: "Kalyan Kadiyala @ Microsoft"
<52089565+kalyankadiyala-Microsoft@users.noreply.github.com>
Date: Mon, 25 Apr 2022 13:21:48 -0700
Subject: [PATCH 08/39] explicit clarity in the Note
---
.../spark/synapse-spark-sql-pool-import-export.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md b/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
index 8f11c3a9da9ae..f8c7a33ae6a38 100644
--- a/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
+++ b/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
@@ -105,7 +105,7 @@ There are two ways to grant access permissions to Azure Data Lake Storage Gen2 -
* It's important to configure ACLs such that the Connector can successfully write and read from the storage locations.
>[!Note]
-> * If your use case involves use of Synapse Workspace pipelines to run notebooks, you must grant above mentioned access permissions to the workspace default managed identity. The name of the workspace default identity will be same as the workspace.
+> * If your use case involves use of Synapse Workspace pipelines to run notebooks, you must also grant above mentioned access permissions to the workspace default managed identity. The name of the workspace default identity will be same as the workspace.
>
> * To use the Synapse workspace with secured storage accounts, a managed private end point must be [configured](../../storage/common/storage-network-security.md?tabs=azure-portal) from the notebook. The managed private end point must be approved from the ADLS Gen2 storage account's `Private endpoint connections` section in the `Networking` pane.
From bd5322cf81a80fc7eef3e1d2ec5467975e3d71c2 Mon Sep 17 00:00:00 2001
From: "Kalyan Kadiyala @ Microsoft"
<52089565+kalyankadiyala-Microsoft@users.noreply.github.com>
Date: Mon, 25 Apr 2022 13:25:52 -0700
Subject: [PATCH 09/39] re-phrased note about managed identity permissions.
---
.../spark/synapse-spark-sql-pool-import-export.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md b/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
index f8c7a33ae6a38..fcc84ef64ee16 100644
--- a/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
+++ b/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
@@ -105,7 +105,7 @@ There are two ways to grant access permissions to Azure Data Lake Storage Gen2 -
* It's important to configure ACLs such that the Connector can successfully write and read from the storage locations.
>[!Note]
-> * If your use case involves use of Synapse Workspace pipelines to run notebooks, you must also grant above mentioned access permissions to the workspace default managed identity. The name of the workspace default identity will be same as the workspace.
+> * If you'd like to run notebooks using Synapse Workspace pipelines you must also grant above listed access permissions to the Synapse Workspace default managed identity. The workspace's default managed identity name is same as the workspace.
>
> * To use the Synapse workspace with secured storage accounts, a managed private end point must be [configured](../../storage/common/storage-network-security.md?tabs=azure-portal) from the notebook. The managed private end point must be approved from the ADLS Gen2 storage account's `Private endpoint connections` section in the `Networking` pane.
From 32170d56663617ff4b123a0c16c1edb48563fd79 Mon Sep 17 00:00:00 2001
From: "Kalyan Kadiyala @ Microsoft"
<52089565+kalyankadiyala-Microsoft@users.noreply.github.com>
Date: Mon, 25 Apr 2022 13:41:26 -0700
Subject: [PATCH 10/39] rephrase for clarity in ADLS gen2 authorization - Note
section
---
.../spark/synapse-spark-sql-pool-import-export.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md b/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
index fcc84ef64ee16..f66fd8f640ca2 100644
--- a/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
+++ b/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
@@ -105,7 +105,7 @@ There are two ways to grant access permissions to Azure Data Lake Storage Gen2 -
* It's important to configure ACLs such that the Connector can successfully write and read from the storage locations.
>[!Note]
-> * If you'd like to run notebooks using Synapse Workspace pipelines you must also grant above listed access permissions to the Synapse Workspace default managed identity. The workspace's default managed identity name is same as the workspace.
+> * If you'd like to run notebooks using Synapse Workspace pipelines you must also grant above listed access permissions to the Synapse Workspace default managed identity. The workspace's default managed identity name is same as the name of the workspace.
>
> * To use the Synapse workspace with secured storage accounts, a managed private end point must be [configured](../../storage/common/storage-network-security.md?tabs=azure-portal) from the notebook. The managed private end point must be approved from the ADLS Gen2 storage account's `Private endpoint connections` section in the `Networking` pane.
From af6595b59cc85a7d67084874b2b13d9eeccd136b Mon Sep 17 00:00:00 2001
From: "Kalyan Kadiyala @ Microsoft"
<52089565+kalyankadiyala-Microsoft@users.noreply.github.com>
Date: Mon, 25 Apr 2022 17:53:12 -0700
Subject: [PATCH 11/39] Addressed review comments from @ktuckdd.
---
.../spark/synapse-spark-sql-pool-import-export.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md b/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
index f66fd8f640ca2..c53845d2aea71 100644
--- a/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
+++ b/articles/synapse-analytics/spark/synapse-spark-sql-pool-import-export.md
@@ -13,7 +13,7 @@ ms.reviewer: ktuckerdavis, aniket.adnaik
## Introduction
-The Azure Synapse Dedicated SQL Pool Connector for Apache Spark in Azure Synapse Analytics enables efficient transfer of large data sets between the [Apache Spark runtime](../../synapse-analytics/spark/apache-spark-overview.md) and the [Dedicated SQL pool](../../synapse-analytics/sql-data-warehouse/sql-data-warehouse-overview-what-is.md). The connector is implemented using `Scala` language. The connector is shipped as a default library within Azure Synapse environment - workspace Notebook and Serverless Spark Pool runtime. To use the Connector with other notebook language choices, use the Spark magic command - `%%spark`.
+The Azure Synapse Dedicated SQL Pool Connector for Apache Spark in Azure Synapse Analytics enables efficient transfer of large data sets between the [Apache Spark runtime](../../synapse-analytics/spark/apache-spark-overview.md) and the [Dedicated SQL pool](../../synapse-analytics/sql-data-warehouse/sql-data-warehouse-overview-what-is.md). The connector is implemented using `Scala` language. The connector is shipped as a default library with Azure Synapse Workspace. To use the Connector with other notebook language choices, use the Spark magic command - `%%spark`.
At a high-level, the connector provides the following capabilities:
@@ -46,7 +46,7 @@ At a high-level, the connector provides the following capabilities:
## Pre-requisites
-This section details necessary pre-requisite steps include Azure Resource setup and Configurations including authentication and authorization requirements for using the Azure Synapse Dedicated SQL Pool Connector for Apache Spark.
+Pre-requisites such as setting up required Azure resources and steps to configure them are discussed in this section.
### Azure Resources
@@ -145,7 +145,7 @@ Azure Synapse Dedicated SQL Pool Connector for Apache Spark - [API Documentation
To successfully bootstrap and orchestrate the read or write operation, the Connector expects certain configuration parameters. The object definition - `com.microsoft.spark.sqlanalytics.utils.Constants` provides a list of standardized constants for each parameter key.
-Following table describes the essential configuration options that must be set for each usage scenario:
+The following table describes the essential configuration options that must be set for each usage scenario:
|Usage Scenario| Options to configure |
|--------------|----------------------------------|
@@ -504,7 +504,7 @@ Upon completion, the read response snippet is displayed in the cell's output. Fa
By default, a write response is printed to the cell output. On failure, the current cell is marked as failed, and subsequent cell executions will be aborted. The other approach is to pass the [callback handle](#write-request-callback-handle) option to the `synapsesql` method. The callback handle will provide programmatic access to the write response.
-## Things to Note
+## Additional Considerations
* When reading from the Azure Synapse Dedicated SQL Pool tables:
* Consider applying necessary filters on the DataFrame to take advantage of the Connector's column-pruning feature.
From 4f80761f8f2ead2112745cf39086be0c2ffd3831 Mon Sep 17 00:00:00 2001
From: rovin-ms
Date: Wed, 27 Apr 2022 11:47:40 -0400
Subject: [PATCH 12/39] changes for correct links
---
articles/orbital/space-partner-program-overview.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/articles/orbital/space-partner-program-overview.md b/articles/orbital/space-partner-program-overview.md
index c541d468c151c..ba29117f52ce3 100644
--- a/articles/orbital/space-partner-program-overview.md
+++ b/articles/orbital/space-partner-program-overview.md
@@ -61,7 +61,8 @@ To join the program, we ask partners to commit to:
## Next steps
-- [Sign up for MS Startups for access to credits and support](https://partner.microsoft.com/?msclkid=0ea9c859bb5611ec801255d300e7c499)
+- [Sign up for the Microsoft Partner Network](https://partner.microsoft.com/?msclkid=0ea9c859bb5611ec801255d300e7c499)
+- [Sign up for MS Startups for access to credits and support](https://startups.microsoft.com/)
- [Downlink data from satellites using Azure Orbital](overview.md)
- [Analyze space data on Azure](/azure/architecture/example-scenario/data/geospatial-data-processing-analytics-azure)
- [Drive insights with geospatial partners on Azure – ESRI and visualize with Power BI](https://azuremarketplace.microsoft.com/en/marketplace/apps/esri.arcgis-enterprise?tab=Overview)
From ebfc8ef0272afc3d4343fc4ba381c9180d24f4d6 Mon Sep 17 00:00:00 2001
From: Tejaswi Kolli
Date: Wed, 27 Apr 2022 17:22:05 -0700
Subject: [PATCH 13/39] Update docfx.json
added tejaswikolli as doc writer for container registry
---
docfx.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docfx.json b/docfx.json
index 115cb74c4c28e..7149ae89824a0 100644
--- a/docfx.json
+++ b/docfx.json
@@ -288,7 +288,7 @@
"articles/cognitive-services/Translator/**/*.md": "laujan",
"articles/connectors/*.md": "ecfan",
"articles/container-instances/**/*.md": "macolso",
- "articles/container-registry/**/*.md": "dlepow",
+ "articles/container-registry/**/*.md": "tejaswikolli",
"articles/data-catalog/*.md": "ChandraKavya",
"articles/data-lake-analytics/*.md": "xujxu",
"articles/defender-for-cloud/*.md": "elazark",
From e4fe7cb17c7b7af067ab71f08124e1326953ca91 Mon Sep 17 00:00:00 2001
From: Alex Wolf
Date: Thu, 28 Apr 2022 10:49:58 -0400
Subject: [PATCH 14/39] added github actions
---
.../container-apps/deploy-visual-studio.md | 19 ++++++++++++++++--
.../container-apps-deployment-type.png | Bin 0 -> 19282 bytes
.../container-apps-github-actions.png | Bin 0 -> 37716 bytes
3 files changed, 17 insertions(+), 2 deletions(-)
create mode 100644 articles/container-apps/media/visual-studio/container-apps-deployment-type.png
create mode 100644 articles/container-apps/media/visual-studio/container-apps-github-actions.png
diff --git a/articles/container-apps/deploy-visual-studio.md b/articles/container-apps/deploy-visual-studio.md
index 20eb92751737b..cbedca54b8da8 100644
--- a/articles/container-apps/deploy-visual-studio.md
+++ b/articles/container-apps/deploy-visual-studio.md
@@ -99,7 +99,7 @@ The Visual Studio publish dialogs will help you choose existing Azure resources,
:::image type="content" source="media/visual-studio/container-apps-choose-registry.png" alt-text="A screenshot showing how select the created registry.":::
-### Publish the app
+### Publish the app using Visual Studio
While the resources and publishing profile are created, you still need to publish and deploy the app to Azure.
@@ -109,9 +109,24 @@ Choose **Publish** in the upper right of the publishing profile screen to deploy
When the app finishes deploying, Visual Studio opens a browser to the URL of your deployed site. This page may initially display an error if all of the proper resources have not finished provisioning. You can continue to refresh the browser periodically to check if the deployment has fully completed.
-
:::image type="content" source="media/visual-studio/container-apps-site.png" alt-text="A screenshot showing the published site.":::
+### Publish the app using GitHub
+
+Container Apps can also be deployed using CI/CD through [GitHub actions](https://docs.github.com/en/actions), which are a powerful tool for automating, customizing, and executing development workflows directly through GitHub repository of your project.
+
+If Visual Studio detects the project you are publishing is hosted in GitHub through the presence of a .git directory, the publish flow presents an additional **Deployment type** step. This stage allows developers to choose whether to publish directly through Visual Studio using the steps shown earlier in the article, or through a GitHub Actions workflow.
+
+:::image type="content" source="media/visual-studio/container-apps-deployment-type.png" alt-text="A screenshot showing the deployment type.":::
+
+If you select the GitHub Actions workflow, Visual Studio will add a .github folder to the root directory of the project, along with a generated yml file inside of it. The yml file contains GitHub Actions configurations to build and deploy your app to Azure every time you push your code.
+
+After you make a change and push your code, you can see the progress of the build and deploy process in GitHub under the **Actions** tab. This page provides detailed logs and indicators regarding the progress and health of the workflow.
+
+:::image type="content" source="media/visual-studio/container-apps-github-actions.png" alt-text="A screenshot showing GitHub actions.":::
+
+Once you see a green checkmark next to the build and deploy jobs the workflow is complete. When you browse to your Container Apps site you should see the latest changes applied.
+
## Clean up resources
If you're not going to continue to use this application, you can delete the Azure Container Apps instance and all the associated services by removing the resource group.
diff --git a/articles/container-apps/media/visual-studio/container-apps-deployment-type.png b/articles/container-apps/media/visual-studio/container-apps-deployment-type.png
new file mode 100644
index 0000000000000000000000000000000000000000..827a5f2e06bef4a67c4c3f4deff9d6098abfaded
GIT binary patch
literal 19282
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
Jxa@TQzX7dd!Sw(D
literal 0
HcmV?d00001
diff --git a/articles/container-apps/media/visual-studio/container-apps-github-actions.png b/articles/container-apps/media/visual-studio/container-apps-github-actions.png
new file mode 100644
index 0000000000000000000000000000000000000000..68b1291ee1e78a7787b3202c82ad797135e09b12
GIT binary patch
literal 37716
zcmcG#by!qi)ISO$pi&|NQiGDx(hU-VgrE}A-3>#xpdy{pAs{8)UD7#7_s~NRFu*Xt
zz&-eV-~0UjyZ4WK_w&G<*=P1Td#}Cr+G~A2`-Hw%ktcXW`3M68gFxY}>_-d?tWpdN
z%|2(CMu<7z2Z_`|c0(2OA+3P>JiR@a_%n)_rP1`iGqMH{=)?&oLBa
zrPMvs_m}*9)i*P4Z)Y%=>X@XT&@osyazA|kmOnc*U)@3A9={x=Zrg{eVjY`x^6o*M
zV%Gr=8Qtw~oNoF7N2Eu_n%b4^Iodi^&nBKIH-4aGWc-WsG_HR{@yR2Fv2IqWWGF3c
z*zAxu-Yo86OIEZF53l8D<5v2f9_%uGZ%d0Vw^xh!zw%J33r7@_?!U4e@ofM8_wV;}
z#O>#en5C{CYk;jP;-3RIlOERAg!Ml*#x9oQ#i!6@`?<~t)cO_t)R6s#QG5`9Qf93K4lJ`eGB!+C1p?(O?)U9$7Idd!m$5{P*wQ@%Jd2QojplhdJgEWaL#_ceRd&tOG
zL?~a^Q3Oq4X#ov`q-a3g*3$XAkB-XpEW#9l
z-!8pvphekhL;=65t4(9nglh6sAkPnMDKPyCwzzN$#XXYvc{K2K9sMtyx4u4v;6Haea-U5h0}J>M3!O=0Wtr*X{hvahEO
zg43mUxD*ry#BNk?W%cx^3C;+vkBK%h7L!wZb7;jn1RaOA1`N?*-@aW+sqBpXIIqR0
zi~?onuA5@4t&x0>h}hVUMT&FMQh0G#8xFl6o0muW--hUsk{zCAmVSJ66gj62D9Zh^
zrFc)Q9R<04R>Aiz4Cr|r(>n{D!AM|KF4=oxfc9{od!0PZ_dk;p5fu?qM-mdqM{i%w
z5gnp$h`d^J(zo*SJ5>fr?QI4lwb*+j|0u*4yyD-KJ3sL9tB7a3hhO=V9~fa7LSKda
zJ0SkgpRVow_j@6^!1YO+4;R_bs+>jB@LfPzDZ--RE%0Tf0Y}5}uQTD+EP^fvwXxJ?
zJ~M?*GwqPshWi$yqifPLUR7J>;FE4#K5B8ES%n`GZxt1{1`4vaT!*Z0kVLdAu1euu
z1zfKz_O&$8Ro|Jj{8RgA{nS6(((+BV!}NqBRgWkWdVBif`K(Vc^7c>MG_-^qHCh#X
z_9!sQLK_k{6x13HqVzE4b#&+I3*uBoBGVpz;I3RuM@330!Ht^snvwUM)-Ie?H2qdw
z(Tnwc(>^=i`2i!_{7#HG=jf5MZ()*lrJu)r>ZtfKGHCR+MIa3iNvwptzsv{YevfEL
zbS7bX{E1doOG{`*R(6*u694xL-h6(*#u}lG;YBQhLakZAWV*D2lNM;!K3670Hiv7A
zJ;`l9>A-x)!b+X&sgnK1M?^%HTl=~xms3>1
z>0x`ejQpq>$4TM3Lf9d%I_^O1U{6_rg4%WubH(0>;ld)(JMTP6q
z>CuE8`=I4+p#8C89q?>q)$wYlio8=zeP(uJQRr4a6J=DJDyn#)(kKF#E5J>ZKpt8j
zuzZ-;vR8|;opWGo-zqn6?z6SD+P^LS^XJY){Co`R4JEt&{CUWWRZP+sUFitfYccqs
zqNR25d`j|qr2)dl%WDZ8Jn&egn6zi-TplW0%M<6?=9dg<+ZT0dMD5i(?X}oB3^m5r
zO>5fRm@K~b-GexeP0tV73wy-zbET!V`-h{MW?m1mvYLL{(NR}xts)3boK8;uyXY>@
znL$HyXGJ^JsqNH8c6wsz
zr%G6wqlG2d)P_~*Bw%*Eis}~bEkJsU3mqQair(C8BhRc%{S;Q$G59!`wMD2KAj=qb3fcGW@e@>5te5|+>fSg4aa}6$o55S5t%RSh(NJl+wN(bn8<-O
zwD8HBnqC4H<$QeXngOR{7mHYMIb;A_B4v~}XcY6=mAGRZ+8lP18PL2S;qp?D_48m5
zwYSi`3-$xl&na#rj)2-pjt9V;0p^)!294dbTxkL<82+Nsm<@bD-skm{w45<~GpR>`
z+u{1GhEEVBJ}?e=V=G(np@!obTN5TC9bHHjV4aJJ;DU+SsQR00oONd9`zzO|*Udw&
zNA4d8u|+#IQ)Ug+Xk4
z{?Mi>UX$8*{s^U$dj>9ma2Xt1jJEwKOn!E=@*b&_%J&s;FBOiedGHQ}Yxj5E
zwS0mUS1y3N$oOW;N9_mo2R{e2jlp?ggYVUltnc-nr;qFil3Vza;{B4`CFif;>CAhY
zX|M0i^zod3jwV1&IU;5+|ouK(ni^ictfvbomcExknKc
z6<$l0QGK1<9e5mQl8sOAD-aIud5l;C4jl90;m9~0l8zRQ;*jgUhsvGqCKQJW-9
zG+-d5)R~EMt4M{I{crbAES7
z>-M6(x_n|0UWq&B;c}0+osxiDROmV_t7;!5Lg#SHvUk$l?r{=5=bHU{vo)sJ3VE=-6hS~E*Pp-Lu;v6qIrUBZNtG_I8;jJaW
z^JmC3qpy!N2!##VcB4UzUU7e$V(NXk=C(vyGw5ZOd2x#%yyul4>bMyBcV3(PzXd4_7`_0kmT;zZ2vvp{PS1GL^_O0J#)pzn6Ge*;aqs0i-OLG5EfG%+xo0+AmW2+X(Z62`^F`Wa
z0xtOx#O)IWkF>Y4?d~c5pW#Zz8&_~`Bv(r6n!VlX$B*%PoFJ9059&5JwO|Wwk5P8T
zhCT_0SH*=9Vs-P9#qYom9JB{}gRH4Jc_h+w?|B7J-b#pA)bu5`AI~tKeC6_u1wNbn
z+;4!D(6=e3XXlE^iwt%iZ@%_#e`M@E`>G}%pA@Jz
zN1I~P|3udp%y0ui(UnhuYJE&X!oIUt+IL(F?gKpL!a0K;yym@aO2Lf9(5(=)q?5fr
zj`71E6f=Djm^0aP-DL67ZW@zQqXXm3#f~p>#m>Tp6fK`t9rg)F9I&rLK>-Pd*OoNO
zC;_(VWk;fpXDNR!ZoQ(I{SB1gSu&_0P6kXt*x}%3GqoWBx^WPhv>RpE_vGdM-!E89
ziU=zXq-&o)ibFKMy6Aj;
zTU3C~Rroc3zR)$H;2_j5!!NI(!rO;An$abBuPQ
zv~1f8INUo_9?Z7#f75SxW!KtAM^AsSv}jMV$v@eS`)mnHPfwqbh}=yHo@8EHcWxtq
zxZxoEP6HmfB+Wg)5qC8gIhLZ&^1t*@@g3Vf*EZXz
ztwCL}mt6{oEcxq-AJD#`^q56&_+@E0t>Jew>aoP*bC{bhGwj-4R%5so`X-~Ax;2mB
zB`Zhr&JkIX(K)F2Lg<{nb_u&@YQ5wM*T^VL2ABo6$4RfE2h~O%i)M#V34Den8QIub
z84V{_8c1FZComOf?mZ%ABDo`$)@8bwFOr|~8--Pil
z{V$B>CRw2M+~9-~j$8|5cmnNiAXoP*0lJ{#Z&=2$ve9BnehM#!!f@JMDA~iq;VZ`VehfAMQQGFP?f_7ECRPGqB4e9j^0Mi|_Gq3P8!=9XEQtW|)tA!?Fj6JlkW_V}crW-b-wtmck1
za2HmYU8j%cP)U>ZQ}B4Lrd_evzS4V~x;uemLq$DkgvjqQitYhP8s~@`*$Z7tl$Khu
z1k@%R9lZk5zn%5VPO+fG6$*)K`=GgV1r5+M{iu86h-su6#(p
zg8jA$*cFkfw@WfEstb?efEYen-|x01fL7OVet(+(Sp;W~{f$b0C0N*_Nk5S7W&e_m
ztN0_cb9t_-{W)LNugjYZacPg50t7oVAJ~~OVV|S*`rpyplaCP2`=B?-`k)m_K@_pF
zdP(?@4K-J*)JpO4Rs!!7!=MeD`+vf2+&
zcdNIgT9?s20d$LLCI5@i#rFLWtaNQ_8@-xi@sMTh5!k4VmX?PS+lpRf6q7?Q9M$vf
zk;=DsFx=aw4E^?n4kFI#o$vG(Pv;RPptfc|x0?~hiJAJpJ1h;SF3V<&-Hqj4B<-VL
zvx{AjFTm|1roJWGi4FG+mXQ+-4yl-qk|f?7B|tJ~InM`UCS4TaO4Egzi?$}kxdfw8
zrQ+U9?alJB>k(}rL~_>+evT!LPS1fL4URTgjpP>H{3*TZwyrMI{0eTc1A~2~6zs#~
za-*zIK$YEk>DGrpq&Mf2_^iXwI8v7KxPYZt16k-V1vP3WJrQXj>;^LWSs=v)YWBfi
zo|ZM4^EztHmPY3vEw_s^`mEhOcWQ@^_k@&Q;_Yykj?pxTM16AeQz^d1+yiX!@P*H)
z*z8W;kIs^YS*{!e^JC-(D#q8pIUX$S98nk*kA55U%!_B107A+QkOkJEfd3!a98){$&35j`D!qj{pU
zAP}Uo*Hhq`n#l1U6bn8kBU1tPWl7{ZM)bs)kh>}94T7GgHw%-2g#XDrTBitEDO8to
zbC>hHG*Haz!}ufPPw~rP#j&k1n%Tc8=+`f^D>G$DFV~bl^Z2;96z3t1>r2BKPkqDr
z)|7}n5k>1xoaKsEVN;gdlZ>5>O=&M(TxAN#WaxWPN5yv6h<(h)b!)?i)gxUZ5K!Rq(CqVT*a5D6L^
z#xw>O9-R32ecEZ51ynx(7cSe^EyS^qn?XwLfAL{U0$)wIyD7t{=BLu%?XkWQKw1)r~25`L8Ai8m+A;%H+dA=G$p?Vi`TQOs2;qUG*ap_c3&SnmT6jYPwx-;Mx;27L1tEPAi1|J4IjFlW4|tob+hoIC#J
zpt=*znl6B5Vkg`8pwRET$yb5=%qt275`3qjtj}N?X3hOmt9%3QzT^hzU;bv~2;2d4
zkaf^mD6wt4>ht_Jg^jZ#{O0U&jSC>XZc)?Sn?Zb{1%Q#eOVh0tU6PwyeZtG
zN;L9XO69S_$*`kZu=Ty%nDR3x6rEbqWlqcyF7}%`Q9w;{;LIMs-fSaG(|Wst3Pq7{%9upyW=X6ytJXO
zo6?dg2%6>&;CLfmll(>c(<%UJ;LUj~THnHbptmpna&rR~a?}dH9oykmo8cY&rBdU=T9W){9V6|bsg}4HIh*+k8RJa9BkH{mYNrNM8g|Ab7$gAkt+=sozN2Tk!*39R(Oi}Ss%+nK&Qh~a|7j+Uy0sa8tj_f9n
z>vp_)U^h6_8|+>Bx<9XP)n;Aet#R)M*y(ck_z+!eN19sBb|LD8H5O2!MhvaYT?EV^9B<*bL-}jBE0(v{
z0qMOJLEJAUxcpIE-90_W?Ex2oNYc$^86EbT77e+A^{WhXK3`9w0m0#QTuH-0h+ygF
zu@5h*6T-V{LKUJk7#M5^^+-r-4zW1zw50$uoLcgoYt2pEy0{?Oc&MObCvM)SE-Li^xD(VwCJ0aG+&ps
zp3eo(92fS1jbA0$EtzB~_b{NfH6C4x%4
z1ltIUF@O#Hl9^_YlvHBKB5W{XPR$-}nnrO20{a0TQCQI>RkFQ5TPzDIPUW?ED8tT{
zyp{XLcctO{{`SDvGR}5NHt&r}mEeiUr&(w1ATg>xGi@iIloV3MzN(5y+i)Rz$t50CjON)Om5!3~G{^
zq|WMfJ&?lFMKVnpc{y8PDz~}z{
zx0Ji$S%SpGu@PCXVv}wVl0j(jtERn1vEDTvORB7VOIII(vtmIP@Rs2I%v(ICBO^Cj
ziwXj6hv+;i>N|0muA=+^?k)LxGYI!Z74&jpc&?sDfHU*kB~n2#Q(6hECK=5L^2C%B
zcrQI2V{QGTV-AGH2gC=xk?on4#}5H?Fu(MS-M+N61$-39%Id!jV0t@ny)5zZQb2*_
z*X~0Y`EP^rva>U@#4e+UA#IV9R1*yxSMKZROK*c~$jEhBH~gw~?ah)QlyS3IutDR!
zT7l1@P5?k@xLL4$8WR`GFar|?vwbbYY@@l^6HOPp!L*)my!Uf!WucSSP&kkb`a=OR
zsvQjSB+xmUV?(_379t@m1)ZX&p#ah#qvtDDG{JlEt2#HNz!@Kth&(>YH6iZtvvLlA
z-8*~alvBU1@uuuGfd5~Y{gTDBiD{4!VPI!ZuQ;mcB)Gr7)GOlI{PMP{_`4$X8E*mM
z!8DU#ofx!YDmhusS4Xd9#>+qS@w2+8_%b(4*VnanTu#)EB@P`)ByL1xv10;(OTmn<
zT6X}-kdE$2;R|k`3V62QLwD__{LOaH5TQuY7Q4@-!F
zeJMBthnN@wSY_bZI3uSvmvO7>z|MMXuADK2K!kCkaSNi=(P`?)7{4CB%Y-6*!+<5<
z&I=2p`0R;h@eie>7HX=YSKkPzzL_Uu^mwgl@Nu#dlX2%CCDh8Kv95q>OvnLTi7Xt6KRd?Y3M`cgN(cy9bR=O19?jPF
z=jp3!%vnTcRsUv4mO)k2fgSc@3Lm`C}U%Bq#TG$AR<;Uiq7tI%C!y2J&l(X
zl+wZ`H=o0Q4KH~Rb%T14(MF~WvD}maqt^ZkT5mrqoW!Q*I5v~i?6~Dc(VtHWVAH#G
zZ?eNGuiF3g1&F*=dSCba^O0zD`1f$vLtXR(aN7mQaf-;jlQu|tr|G4P{1_r~RJXC}
zeyh(>5HchBJ2`LP#c1d|0(8c&vG`2L;G%4Oee{nqBPF+T&3?aP@+TU#nQrEt
z4`&&kcE_V<>CI$O{cH~#*>&R-n%7|lCsZ|HqX`|Ity1I91!YFV^pMqTuZF*|3F4VWl&K#ZOJ1M+A;JBX^GfWw#V
zLh;aMj1t-2Hd!1v#blwvo|Sq1r5!u3_{g)0_Lkd=_oLA5r5*@iHD~-MuxwGC*Vf&W
zk|X+GN&S7h9z3&S2J4NwfQI$E{0di+GT#l4FqewN3^sxN!Bt*gyS!box-%+OAEYR1
z7v>cZJ#o>lGvhg1KFR-%A2?K~9Q!=f(p8<_ZK@Yq6rXDa-OGzITJC@LMidu^C)8!`
zq0ZQywE%NJ13T;HxPDS9m6C4#gx6BVa`9~;9LA6JYowpSi`~_KtQjtt)Y|=dAUY;C
zj&SO;0srs0kA-X_q`8%`rlFziS_vv67Bn8sYI!AW>@*c4{7I$e8gqg6DtcD8;a>tV
zIX%o{7#JQ;`S(&&l0vo%-A9{hxhMoBnFu}CHe5(+_mBxDm@b6C|%@bByyF*l20p9}FHv7dKY_4BFNW7!HF&EOey#jJrn4GfUP4+jUe1
zj1fviX?s?)gH`(R7pUNg(8H3PZ3->Tm{9w8V%|q{wat$y|Iv>aJJFV|Pt!%mmzMtQ
zC6}K1YHrDix*|{Ol?wLsE9BfS{DLRDXli=xOI)mWlyqypVcVH%ya}4)?{*qBZMuvj
zTWAZdYM1y_JEDZw6mlSR06BE{(A?WlHUZ(Raxj(4XkN?b(CG@=X3g~Z{S>CRbXC@H
zo``A&7rE)eF%YjTrrm~1>szFnhy0zlId?^->-xB%%e|T?F^M*W+dN$e-$t3SxdRf`
z22q8hFo&;2Q4b*EZefj43m(D+dML%{i6)v8XCu?NC1eP~YfQYX$>*%h`rKVb_z)L%
zX2z~9^KGKeo6~XeynUu+9ffR8dNB&iMn7xC_o^#%kZ9s=hI=G!V)ZW=AVS*v#-qXG
zL*%VVNp+k7plB@WS@$m+Uk_nfv6lMdG_UKOeC9qR?H;AsT}?B#f<|fU*VlBm?z?cD
ztS<_jI%PJL_MJ7H`(~oRnOAC~r|S6^N#z;QK3RMBK!`ylr}|3O{XL3F+vrpk_iF8J7B4Nl9L2(JGfGKI`jnwd&sINOk0;#
z^?Har_A?BuMfHZ*Al>y96I^Dfj->4LzmZQ)?KQ8x?&gGVH-$u
z4kfaiX{*E|-n?{v!IoR>S?2WBnfooo()^Hq(PKWlV&7D!iA~COM0$Gl9(3zUu;9)z
zrcf&%U(1i^s4T}OX=!XHXUc1Rg9nbk4R^NuYwddy#~&fU^_br+lD$7e+2$UfC^o0I
z@~>E$R*|iD3GI4sPU4hLTnO>kE+#yyEIXtA96DF_UhHq02{x;5psWX@8*f&u0>vPC+1|JCwP*0mA&kAdJ~
zs<{shK^&mEgHZVC>?l?rxGNEs#9LQ@(W&-6E@sHD2qY0OC^1BiEH&sK?0d2pwc5SN
zzoAiDpQUCUK3!p?Ai?pqXL3vyrN;IW`K0ASf4L!)&UAn>>c{*^RHZ7JSfWz6%;n->
z%on{xj$_w0RVD}v#5;a;aX{X)Y|NbM9J(-a+ajLQGF7=>y-Bp-c>La97;h!rbyCgC
z>vw`%US-Mf2%Tv5yq2mor`Hxr!+?rNJB3q5Z;gVAAm**2$mHy3=j1?yjihvG`+717
zc~zW!2`hUYJS3tyDV`epEKRdw^C<}N*5m8qs!rw0E|}xFJIBfGq5#|Ffd(P!MaC7`
zYQ>FJ!Pzg4L66ywL{OqrF?e?Rv3~wVR{7Ft73azUWri=Zb+WxBNaGwT@O>sT5D}SW
z{?2jK1KbRwo-lDRH3v}6ERolK&3ld3`yq`fAJU7x2Zk=~Wgz!5z9{?(xL@j1!E9+@
zyR`<*=*w@yDf#Tqa?WJm!ku|;wj(Z9!H^Y_xY(zUEXnx=dZ|Amqh#=FRn2s6%MT@1
z!;ls94i~c!sxeH`=#dH?f_;XgGvhH#)soW=tFpP?(QUowR$b%{Z)_YYDp`Kr8RvVR
z0(rgTeftKa1CUQ|+TkyHeC~8mzFe8
zc+RRwU8h#RzJxB3!V?GjoI4}QtBC2YZD
zN{2;h>m!NSDf+1Rd!FKlS2^v{mkh+h;FPTvDmkT1!aC=g1%_t>)@JPcZc?*1m^(iU
zQ1Radw69!n5#V<
z+et;_sJNws(?Z_#DTN1>b?xTEbtK;hpI2dEh
zEb~`&Wy0*p-+OOP4e?)gPK=8Wa@0Z**f2eov_WK=7yjkcjTkX0nyj!&zGa
za?$%)ZSAxdUdu@?y-?qS&@4C1_OibpoHiJfs5pZ?4j!^Y@4uhE@7vZFFV6P275hq^
zWlxcc=G)^GSj1jT&Z#=nxQbtN^h4M5F9Sm5^Qvq{KUVNA=^d&0?XO~{TP@!j2>)0$
zq$aKjB>lOmhx>S-VV|R<*_(~4wcGbh0V&Ji@U^0Hdbj4@;%
zug-5TXvll5hEJZNI%6`MW=me=h8%uwjaN~m1C(g!h}aS6fF{}#=_k&Ue9vvVGFc(}
z!vA+1M|L4`Pgkb}n(eq|CrY@aWw+p5>XbUv(~GtA^{`R|zC)3Q;b}#DG^Mk$*kq%=
z#lxefkUQV9kSgV(E{bb#xKQc9S-hdOCC#&yr*_B-y*QkowLG7@*PKDM-V!a2vt6L_
zH>y qB`pckmgwE$f)s;PqLlU
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 |