Skip to main content

Class XBRApiEtl

The XBRApiEtl class provides methods for extracting and loading data from various sources.

The XBRApiEtl class functions like the BRApi from OneStream. It can be thought of as the main entrypoint into programmatically extracting and loading data from various sources. For Example:

var tabularEtlManager = XBRApi.Etl.GetTabularEtlManager(si); tabularEtlManager.ExtractAndLoad(sourceDataDefinition, destinationDataDefinition);

Namespace: Workspace.XBR.Xperiflow.SubApis

Assembly: Xperiflow.dll

Declaration
public class XBRApiEtl

Methods

GetTabularEtlManager(SessionInfo, IXperiflowStorageClient)

Instantiates an a Tabular ETL Manager that provides functionality for extracting and loading data.

Declaration
public ITabularEtlManager GetTabularEtlManager(SessionInfo si, IXperiflowStorageClient xperiflowStorageClient = null)
Returns

Workspace.XBR.Xperiflow.Etl.Tabular.ITabularEtlManager

ITabularEtlManager

Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe SessionInfo object
Workspace.XBR.Xperiflow.Core.RestApi.Storage.IXperiflowStorageClientxperiflowStorageClient

GetUnstructuredEtlManager(SessionInfo, IXperiflowStorageClient)

The Unstructured ETL Manager. This is used to extract and load data from unstructured sources and data formats (.json, .xml, .png, .docx, .pdf, etc. ). This interface leverages the Stream objects as its primary data transfer mechanism.

Note that this does not support SQL based connection contexts, containers, and data formats.

Use the XBRApi to instantiate an [Workspace.XBR.Xperiflow.Etl.Unstructured.IUnstructuredEtlManager](../Xperiflow.Etl.Unstructured/IUnstructuredEtlManager.md). For example:

Example:

` var etlManager = XBRApi.Etl.GetUnstructuredEtlManager(si); `

Example:

` var stream = etlManager.Extract(sourceData); `

Example:

` etlManager.Load(destinationData, stream) `
  • OR more simply-

Example:

` etlManager.ExtractAndLoad(sourceDataDefinition, destinationDataDefinition); `
Declaration
public IUnstructuredEtlManager GetUnstructuredEtlManager(SessionInfo si, IXperiflowStorageClient xperiflowStorageClient = null)
Returns

Workspace.XBR.Xperiflow.Etl.Unstructured.IUnstructuredEtlManager

Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe SessionInfo object.
Workspace.XBR.Xperiflow.Core.RestApi.Storage.IXperiflowStorageClientxperiflowStorageClient

CreateDataDefinition(SessionInfo, IConnectionContext, IDataContainerContext)

Creates a [Workspace.XBR.Xperiflow.Etl.DataDefinition](../Xperiflow.Etl/DataDefinition.md) object by automatically inferring the DataFormat.

Declaration
public DataDefinition CreateDataDefinition(SessionInfo si, IConnectionContext connectionContext, IDataContainerContext dataContainerContext)
Returns

Workspace.XBR.Xperiflow.Etl.DataDefinition

A DataDefinition object representation of the data.

Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe SessionInfo object.
Workspace.XBR.Xperiflow.Etl.IConnectionContextconnectionContextThe connection context (where the data is).
Workspace.XBR.Xperiflow.Etl.IDataContainerContextdataContainerContextThe data container context (how the data is stored).

CreateOneStreamFileSystemDataDefinition(SessionInfo, FileSystemLocation, string)

Creates a [Workspace.XBR.Xperiflow.Etl.DataDefinition](../Xperiflow.Etl/DataDefinition.md) for a file that is expected to exist within a OneStream file system. This will automatically infer the Workspace.XBR.Xperiflow.Etl.IDataFormat by inspecting the file extension.

Declaration
public DataDefinition CreateOneStreamFileSystemDataDefinition(SessionInfo si, FileSystemLocation fileSystemLocation, string filePath)
Returns

Workspace.XBR.Xperiflow.Etl.DataDefinition

A DataDefinition object representation of the data stored in the OneStream file system.

Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe SessionInfo object.
OneStream.Shared.Wcf.FileSystemLocationfileSystemLocationThe OneStream file system location.
System.StringfilePathThe file path. The file extension will be used to infer the Workspace.XBR.Xperiflow.Etl.IDataFormat.

CreateMetaFileSystemDataDefinition(SessionInfo, string, string)

Creates a [Workspace.XBR.Xperiflow.Etl.DataDefinition](../Xperiflow.Etl/DataDefinition.md) for a file that is expected to exist within a MetaFileSystem. This will automatically infer the Workspace.XBR.Xperiflow.Etl.IDataFormat by inspecting the file extension.

Declaration
public DataDefinition CreateMetaFileSystemDataDefinition(SessionInfo si, string connectionKey, string filePath)
Returns

Workspace.XBR.Xperiflow.Etl.DataDefinition

A DataDefinition object representation of the data stored in the MetaFileSystem.

Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe SessionInfo object.
System.StringconnectionKeyThe Workspace.XBR.Xperiflow.MetaFileSystem.IMetaFileSystemClient connection key.
System.StringfilePathThe file path. The file extension will be used to infer the Workspace.XBR.Xperiflow.Etl.IDataFormat.

CreateOneStreamSqlConnectionDataDefinition(SessionInfo, string, string)

Creates a [Workspace.XBR.Xperiflow.Etl.DataDefinition](../Xperiflow.Etl/DataDefinition.md) for a table that is expected to exist within a OneStream SQL Database.

Declaration
public DataDefinition CreateOneStreamSqlConnectionDataDefinition(SessionInfo si, string connectionKey, string tableName)
Returns

Workspace.XBR.Xperiflow.Etl.DataDefinition

A DataDefinition object representation of the data stored in a OneStream SQL Table.

Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe SessionInfo object.
System.StringconnectionKeyThe OneStream SQL Database connection key.
System.StringtableNameThe table name.

GetOneStreamDatabaseTableAsDataReader(SessionInfo, string, string)

Creates an IDataReader that provides a means of forward-only reading of a OneStream Database Table.

Declaration
public IDataReader GetOneStreamDatabaseTableAsDataReader(SessionInfo si, string connectionKey, string tableName)
Returns

System.Data.IDataReader

An IDataReader object

Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe SessionInfo object
System.StringconnectionKeyThe OneStream SQL Database connection key
System.StringtableNameThe OneStream SQL Database table name to read
Exceptions

System.ArgumentException

OneStream.Shared.Common.XFException

ExtractOneStreamDatabaseTableAsDataTable(SessionInfo, string, string)

Creates a DataTable that contains data loaded from a OneStream Database Table.

Declaration
public DataTable ExtractOneStreamDatabaseTableAsDataTable(SessionInfo si, string connectionKey, string tableName)
Returns

System.Data.DataTable

A DataTable object

Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe SessionInfo object
System.StringconnectionKeyThe OneStream SQL Database connection key
System.StringtableNameThe OneStream SQL Database table name to read
Exceptions

OneStream.Shared.Common.XFException

ExtractMetaFileSystemParquetAsDataTable(SessionInfo, MetaFileSystemLocation, string)

Creates a DataTable that contains data loaded from a Parquet file stored in a MetaFileSystem.

Declaration
public DataTable ExtractMetaFileSystemParquetAsDataTable(SessionInfo si, MetaFileSystemLocation metaFileSystemLocation, string filePath)
Returns

System.Data.DataTable

A DataTable object

Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe SessionInfo object
Workspace.XBR.Xperiflow.MetaFileSystem.MetaFileSystemLocationmetaFileSystemLocationAn [Workspace.XBR.Xperiflow.MetaFileSystem.MetaFileSystemLocation](../Xperiflow.MetaFileSystem/MetaFileSystemLocation.md) enum representing the MetaFileSystem connection key
System.StringfilePathThe file path of the file to extract
Exceptions

OneStream.Shared.Common.XFException

ExtractMetaFileSystemParquetAsDataTable(SessionInfo, string, string, IMetaFileSystemClient)

Creates a DataTable that contains data loaded from a Parquet file stored in a MetaFileSystem.

Declaration
public DataTable ExtractMetaFileSystemParquetAsDataTable(SessionInfo si, string connectionKey, string filePath, IMetaFileSystemClient metaFileSystemClient = null)
Returns

System.Data.DataTable

A DataTable object

Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe SessionInfo object
System.StringconnectionKeyThe MetaFileSystem connection key
System.StringfilePathThe file path of the file to extract
Workspace.XBR.Xperiflow.MetaFileSystem.IMetaFileSystemClientmetaFileSystemClient
Exceptions

OneStream.Shared.Common.XFException

ExtractOneStreamFileSystemParquetAsDataTable(SessionInfo, FileSystemLocation, string)

Creates a DataTable that contains data loaded from a Parquet file stored in a OneStreamFileSystem.

Declaration
public DataTable ExtractOneStreamFileSystemParquetAsDataTable(SessionInfo si, FileSystemLocation fileSystemLocation, string filePath)
Returns

System.Data.DataTable

A DataTable object

Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe SessionInfo object
OneStream.Shared.Wcf.FileSystemLocationfileSystemLocationAn enum representing the OneStream file system location (i.e., Application Database, System Database, Fileshare)
System.StringfilePathThe file path of the file to extract
Exceptions

OneStream.Shared.Common.XFException

ExtractMetaFileSystemCsvAsDataTable(SessionInfo, string, string, bool, string[]?, int, int, Dictionary<string, ColumnInferenceInfo>?, ColumnInferenceHandler, IMetaFileSystemClient)

Creates a DataTable that contains data loaded from a CSV file stored in a MetaFileSystem.

Declaration
public DataTable ExtractMetaFileSystemCsvAsDataTable(SessionInfo si, string connectionKey, string filePath, bool headersIncluded = false, string[]? columnNames = null, int numRows = -1, int guessRows = 10000, Dictionary<string, ColumnInferenceInfo>? columnInferenceInfo = null, ColumnInferenceHandler defaultHandler = ColumnInferenceHandler.InferDataType, IMetaFileSystemClient metaFileSystemClient = null)
Returns

System.Data.DataTable

A DataTable object

Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe SessionInfo object
System.StringconnectionKeyThe MetaFileSystem connection key
System.StringfilePathThe file path of the file to extract
System.BooleanheadersIncludedA bool identifying whether headers are included in the data
System.String[]columnNamesAn optional string array of column names to set in the DataTable
System.Int32numRowsThe number of rows to read into the DataTable
System.Int32guessRowsThe number of rows to use to guess column types
System.Collections.Generic.Dictionary<System.String,Workspace.XBR.Xperiflow.Etl.Tabular.Utilities.ColumnInferenceInfo>columnInferenceInfoA Dictionary of column names to [Workspace.XBR.Xperiflow.Etl.Tabular.Utilities.ColumnInferenceInfo](../Xperiflow.Etl.Tabular.Utilities/ColumnInferenceInfo.md) objects
Workspace.XBR.Xperiflow.Etl.Tabular.Utilities.ColumnInferenceHandlerdefaultHandlerThe [Workspace.XBR.Xperiflow.Etl.Tabular.Utilities.ColumnInferenceHandler](../Xperiflow.Etl.Tabular.Utilities/ColumnInferenceHandler.md) enum to use when identifying column types
Workspace.XBR.Xperiflow.MetaFileSystem.IMetaFileSystemClientmetaFileSystemClient

ExtractMetaFileSystemCsvAsDataTable(SessionInfo, MetaFileSystemLocation, string, bool, string[]?, int, int, Dictionary<string, ColumnInferenceInfo>?, ColumnInferenceHandler)

Creates a DataTable that contains data loaded from a CSV file stored in a MetaFileSystem.

Declaration
public DataTable ExtractMetaFileSystemCsvAsDataTable(SessionInfo si, MetaFileSystemLocation metaFileSystemLocation, string filePath, bool headersIncluded = false, string[]? columnNames = null, int numRows = -1, int guessRows = 10000, Dictionary<string, ColumnInferenceInfo>? columnInferenceInfo = null, ColumnInferenceHandler defaultHandler = ColumnInferenceHandler.InferDataType)
Returns

System.Data.DataTable

A DataTable object

Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe SessionInfo object
Workspace.XBR.Xperiflow.MetaFileSystem.MetaFileSystemLocationmetaFileSystemLocationAn [Workspace.XBR.Xperiflow.MetaFileSystem.MetaFileSystemLocation](../Xperiflow.MetaFileSystem/MetaFileSystemLocation.md) enum representing the MetaFileSystem connection key
System.StringfilePathThe file path of the file to extract
System.BooleanheadersIncludedA bool identifying whether headers are included in the data
System.String[]columnNamesAn optional string array of column names to set in the DataTable
System.Int32numRowsThe number of rows to read into the DataTable
System.Int32guessRowsThe number of rows to use to guess column types
System.Collections.Generic.Dictionary<System.String,Workspace.XBR.Xperiflow.Etl.Tabular.Utilities.ColumnInferenceInfo>columnInferenceInfoA Dictionary of column names to [Workspace.XBR.Xperiflow.Etl.Tabular.Utilities.ColumnInferenceInfo](../Xperiflow.Etl.Tabular.Utilities/ColumnInferenceInfo.md) objects
Workspace.XBR.Xperiflow.Etl.Tabular.Utilities.ColumnInferenceHandlerdefaultHandlerThe [Workspace.XBR.Xperiflow.Etl.Tabular.Utilities.ColumnInferenceHandler](../Xperiflow.Etl.Tabular.Utilities/ColumnInferenceHandler.md) enum to use when identifying column types

ExtractOneStreamFileSystemCsvAsDataTable(SessionInfo, FileSystemLocation, string, bool, string[]?, int, int, Dictionary<string, ColumnInferenceInfo>?, ColumnInferenceHandler)

Creates a DataTable that contains data loaded from a CSV file stored in a OneStream file system.

Declaration
public DataTable ExtractOneStreamFileSystemCsvAsDataTable(SessionInfo si, FileSystemLocation fileSystemLocation, string filePath, bool headersIncluded = false, string[]? columnNames = null, int numRows = -1, int guessRows = 10000, Dictionary<string, ColumnInferenceInfo>? columnInferenceInfo = null, ColumnInferenceHandler defaultHandler = ColumnInferenceHandler.InferDataType)
Returns

System.Data.DataTable

A DataTable object

Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe SessionInfo object
OneStream.Shared.Wcf.FileSystemLocationfileSystemLocationAn enum representing the OneStream file system location (i.e., Application Database, System Database, Fileshare)
System.StringfilePathThe file path of the file to extract
System.BooleanheadersIncludedA bool identifying whether headers are included in the data
System.String[]columnNamesAn optional string array of column names to set in the DataTable
System.Int32numRowsThe number of rows to read into the DataTable
System.Int32guessRowsThe number of rows to use to guess column types
System.Collections.Generic.Dictionary<System.String,Workspace.XBR.Xperiflow.Etl.Tabular.Utilities.ColumnInferenceInfo>columnInferenceInfoA Dictionary of column names to [Workspace.XBR.Xperiflow.Etl.Tabular.Utilities.ColumnInferenceInfo](../Xperiflow.Etl.Tabular.Utilities/ColumnInferenceInfo.md) objects
Workspace.XBR.Xperiflow.Etl.Tabular.Utilities.ColumnInferenceHandlerdefaultHandlerThe [Workspace.XBR.Xperiflow.Etl.Tabular.Utilities.ColumnInferenceHandler](../Xperiflow.Etl.Tabular.Utilities/ColumnInferenceHandler.md) enum to use when identifying column types

LoadTableToOneStreamDatabase(SessionInfo, string, DataTable, bool)

Writes the contents of a DataTable to a OneStream SQL Database Table. The table name will be determined by the DataTable.TableName property. If the table already exists, an error will be thrown if overwriteOk is set to false.

Declaration
public void LoadTableToOneStreamDatabase(SessionInfo si, string connectionKey, DataTable dt, bool overwriteOk = false)
Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe SessionInfo object
System.StringconnectionKeyThe OneStream SQL Database connection key
System.Data.DataTabledtThe DataTable to write to the OneStream SQL Database
System.BooleanoverwriteOkA bool indicating whether it's OK to overwrite an existing table
Exceptions

System.ArgumentException

System.Exception

OneStream.Shared.Common.XFException

LoadTableToOneStreamDatabase(SessionInfo, string, DataTable, BlendTableLoadTypes, BlendTableIndexTypes)

Writes the contents of a DataTable to a OneStream SQL Database table within the database specified by the dbConnectionKey. This will create, replace, or append depending on the loadType specified.

Declaration
public void LoadTableToOneStreamDatabase(SessionInfo si, string connectionKey, DataTable dt, BlendTableLoadTypes tableLoadType, BlendTableIndexTypes tableIndexType)
Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe session info object for the current session
System.StringconnectionKeyThe key of the database connection to use for the operation
System.Data.DataTabledtThe DataTable to persist as a database table
OneStream.Shared.Common.BlendTableLoadTypestableLoadTypeThe type of operation to perform: create, replace, or append
OneStream.Shared.Common.BlendTableIndexTypestableIndexTypeThe BlendTableIndexType
Exceptions

OneStream.Shared.Common.XFException

LoadParquetToMetaFileSystem(SessionInfo, string, string, DataTable, bool)

Writes the contents of a DataTable to a Parquet file in the MetaFileSystem based on a MetaFileSystem connection key.

Declaration
public void LoadParquetToMetaFileSystem(SessionInfo si, string connectionKey, string filePath, DataTable dt, bool overwriteOk = false)
Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe SessionInfo object
System.StringconnectionKeyThe MetaFileSystem connection key
System.StringfilePathThe file path of the file to write. Note that if directories included in the path do not exist, an error will be thrown
System.Data.DataTabledtThe DataTable to write to the MetaFileSystem
System.BooleanoverwriteOkA bool indicating whether it's OK to overwrite a file that already exists at filePath
Exceptions

OneStream.Shared.Common.XFException

LoadParquetToMetaFileSystem(SessionInfo, MetaFileSystemLocation, string, DataTable, bool)

Writes the contents of a DataTable to a Parquet file in the MetaFileSystem based on a Workspace.XBR.Xperiflow.MetaFileSystem.MetaFileSystemLocation.

Declaration
public void LoadParquetToMetaFileSystem(SessionInfo si, MetaFileSystemLocation metaFileSystemLocation, string filePath, DataTable dt, bool overwriteOk = false)
Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe SessionInfo object
Workspace.XBR.Xperiflow.MetaFileSystem.MetaFileSystemLocationmetaFileSystemLocationAn [Workspace.XBR.Xperiflow.MetaFileSystem.MetaFileSystemLocation](../Xperiflow.MetaFileSystem/MetaFileSystemLocation.md) enum representing the MetaFileSystem connection key
System.StringfilePathThe file path of the file to write. Note that if directories included in the path do not exist, an error will be thrown
System.Data.DataTabledtThe DataTable to write to the MetaFileSystem
System.BooleanoverwriteOkA bool indicating whether it's OK to overwrite a file that already exists at filePath
Exceptions

OneStream.Shared.Common.XFException

LoadParquetToOneStreamFileSystem(SessionInfo, FileSystemLocation, string, DataTable, bool)

Writes the contents of a DataTable to a Parquet file in the OneStream FileSystem

Declaration
public void LoadParquetToOneStreamFileSystem(SessionInfo si, FileSystemLocation fileSystemLocation, string filePath, DataTable dt, bool overwriteOk = false)
Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe SessionInfo object
OneStream.Shared.Wcf.FileSystemLocationfileSystemLocationAn enum representing the OneStream file system location (i.e., Application Database, System Database, Fileshare)
System.StringfilePathThe file path of the file to write
System.Data.DataTabledtThe DataTable to write to the OneStream file system
System.BooleanoverwriteOkA bool indicating whether it's OK to overwrite a file that already exists at filePath

LoadCsvToMetaFileSystem(SessionInfo, string, string, DataTable, bool, char, bool)

Writes the contents of a DataTable to a CSV file in the MetaFileSystem based on a MetaFileSystem connection key.

Declaration
public void LoadCsvToMetaFileSystem(SessionInfo si, string connectionKey, string filePath, DataTable dt, bool includeHeaders = true, char delimiter = ',', bool overwriteOk = false)
Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe SessionInfo object
System.StringconnectionKeyThe MetaFileSystem connection key
System.StringfilePathThe file path of the file to write. Note that if directories included in the path do not exist, an error will be thrown
System.Data.DataTabledtThe DataTable to write to the MetaFileSystem
System.BooleanincludeHeadersA bool indicating whether column headers should be written to the file
System.ChardelimiterThe delimiter to use when writing the file
System.BooleanoverwriteOkA bool indicating whether it's OK to overwrite a file that already exists at filePath

LoadCsvToMetaFileSystem(SessionInfo, MetaFileSystemLocation, string, DataTable, bool, char, bool)

Writes the contents of a DataTable to a CSV file in the MetaFileSystem based on a Workspace.XBR.Xperiflow.MetaFileSystem.MetaFileSystemLocation.

Declaration
public void LoadCsvToMetaFileSystem(SessionInfo si, MetaFileSystemLocation metaFileSystemLocation, string filePath, DataTable dt, bool includeHeaders = true, char delimiter = ',', bool overwriteOk = false)
Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosiThe SessionInfo object
Workspace.XBR.Xperiflow.MetaFileSystem.MetaFileSystemLocationmetaFileSystemLocationAn [Workspace.XBR.Xperiflow.MetaFileSystem.MetaFileSystemLocation](../Xperiflow.MetaFileSystem/MetaFileSystemLocation.md) enum representing the MetaFileSystem connection key
System.StringfilePathThe file path of the file to write. Note that if directories included in the path do not exist, an error will be thrown
System.Data.DataTabledtThe DataTable to write to the MetaFileSystem
System.BooleanincludeHeadersA bool indicating whether column headers should be written to the file
System.ChardelimiterThe delimiter to use when writing the file
System.BooleanoverwriteOkA bool indicating whether it's OK to overwrite a file that already exists at filePath

LoadCsvToOneStreamFileSystem(SessionInfo, FileSystemLocation, string, DataTable, bool, char, bool)

Writes the contents of a DataTable to a CSV file in the OneStream FileSystem

Declaration
public void LoadCsvToOneStreamFileSystem(SessionInfo si, FileSystemLocation fileSystemLocation, string filePath, DataTable dt, bool includeHeaders = true, char delimiter = ',', bool overwriteOk = false)
Parameters
TypeNameDescription
OneStream.Shared.Common.SessionInfosi
OneStream.Shared.Wcf.FileSystemLocationfileSystemLocationAn enum representing the OneStream file system location (i.e., Application Database, System Database, Fileshare)
System.StringfilePathThe file path of the file to write. If a file already exists at filePath, an error will be thrown if overwriteOk is set to false.
System.Data.DataTabledtThe DataTable to write to the OneStream file system
System.BooleanincludeHeadersA bool indicating whether column headers should be written to the file
System.ChardelimiterThe delimiter to use when writing the file
System.BooleanoverwriteOkA bool indicating whether it's OK to overwrite a file that already exists at filePath

Inherited Members

  • System.Object.Equals(System.Object)
  • System.Object.Equals(System.Object,System.Object)
  • System.Object.GetHashCode
  • System.Object.GetType
  • System.Object.MemberwiseClone
  • System.Object.ReferenceEquals(System.Object,System.Object)
  • System.Object.ToString

Was this page helpful?