Chapter 2: SDTM Metadata and Define.xml for Base SAS Implementation

SDTM Metadata

Table of Contents Metadata

Variable-Level Metadata

Codelist Metadata

Value-Level Metadata

Where Clause Metadata

Computational Method Metadata

Comments Metadata

External Links

Building Define.xml

Define File Header Metadata

Define File Creation SAS Program

Chapter Summary

This chapter provides the SDTM metadata required to implement our Base SAS solution, which creates an SDTM database. Microsoft Excel files are used to store the SDTM metadata that the SAS code (presented in Chapter 3) will leverage to create the SDTM datasets. The chapter ends with a call to the SAS macro using the SDTM metadata that is stored in Microsoft Excel to create the define.xml file.

More Information

Appendix B - SDTM Metadata

Author Pages (http://support.sas.com/publishing/authors/index.html) - %make_define2 SAS Macro

See Also

Study Data Tabulation Model Implementation Guide version 3.2

Define-XML version 2.0

Study Data Technical Conformance Guide

SDTM Metadata

It is our assertion that in order to build SDTM files quickly and accurately, it is essential to have good metadata to drive your process. However, for the sake of argument, let us look at just using Base SAS alone to perform the SDTM data conversions. You might write SAS programs that look something like this:

data dm;

  set sourcedata.demographics;

  length usubjid $ 24 race $ 30;       

  label usubjid = “Unique Subject ID”  

        race   = “Race”;

  usubjid = put(subject,10.);

  if nrace = 1 then   

    race = ‘WHITE’;

  else if nrace = 2 then

    race = ‘BLACK OR AFRICAN AMERICAN’;

  else if nrace = 3 then

    race = ‘OTHER’;

run;

   Variable lengths are buried in the SAS code, which makes them hard to change globally and difficult to make consistent across domains.

   Variable labels are buried in the SAS code, which makes them hard to change globally and difficult to make consistent across domains.

   SDTM-controlled terminology is buried in the SAS code, making it hard to verify, maintain, and get into the define.xml file.

If you take this type of Base SAS approach to your SDTM conversion work, then you will run into the following problems because your SDTM metadata is buried in your SAS code:

   Your SAS code will be hard to maintain.

   Achieving variable attribute consistency across SDTM domains will be difficult. Lengths, labels, and variable types can vary for the same variable across domains.

   You will have a very difficult time building a proper define.xml file for your submission. At best, your define.xml file will be based on the data that was observed and will omit possible controlled terminology values that are not actually observed.

In this chapter, we use Microsoft Excel files to house our SDTM metadata for later use in SAS. You could, and probably should, have your metadata stored in a more robust tool than Microsoft Excel files, such as a relational database such as Oracle or a tool like SAS Clinical Data Integration (to be discussed in Chapter 5). However, for the purposes of this chapter, we chose the Excel file format because it is readily available to most users and tends to be the common exchange mechanism of business data in lieu of sufficient software. Our goal is to have a central SDTM metadata repository so that you can more easily generate valid SDTM domains and so that you can build a proper define.xml file in the end.

The CDISC metadata standard that we comply with is the Define-XMLfinal version 2.0 from the http://www.cdisc.org/define-xml website, published in March of 2013. The SDTM target metadata that we use is based on the SDTM version 1.4 and Implementation Guide version 3.2. To view our define.xml file, we will use the define2-0-0.xsl style sheet that comes with the Define-XML final version 2.0 release package, which can also be found on the author pages. The CDISC-supplied metadata spreadsheet for the SDTM, which can be found on the CDISC SHARE website at http://www.cdisc.org/standards/share, provides a good source for populating some of the SDTM metadata mentioned later as well. Unfortunately, this metadata spreadsheet is currently available for download only for CDISC members.

Table of Contents Metadata

The Table of Contents metadata is called that because it represents the metadata required to produce the Table of Contents section of the define.xml file. The Table of Contents in the define.xml file is just what it sounds like, a list of the domain datasets, what they are for, and where they can be found. This metadata is used to populate the ItemGroupDef section of the define.xml file.

The metadata that we use in the Table of Contents metadata is described in the following table.

Table 2.1: Table of Contents Metadata

Excel Column Description
OID The unique ODM element identifier (OID) of the SDTM domain and a merge key with the variable level metadata. This can be the same as NAME but does not have to be. OIDs are unique ODM identifiers and do not have to match end-user NAMEs. OIDs enable define.xml elements to reference one another.
NAME The name of the SDTM domain that will be placed in define.xml.
REPEATING Set to No for domains that are one record per subject like DM. Set to Yes for domains that have more than one record per subject.
ISREFERENCEDATA Set to No for subject-level data. Set to Yes for reference data such as the trial design model datasets.
PURPOSE Purpose for SDTM datasets should be set to Tabulation.
LABEL Descriptive label of the domain. You can find these defined for the standard domains in the CDISC SDTM documentation.
STRUCTURE Put domain dataset structure here. You can find these defined for the standard domains in the CDISC SDTM documentation.
CLASS Set to the general SDTM class. You can find these defined for the standard domains in the CDISC SDTM documentation.
ARCHIVELOCATIONID This is the file reference to where the actual domain dataset lives. If you assume that the SDTM domains will be located in the same folder as the define.xml file, you can just set this to ./domainname where domainname is your domain name (for example, ./AE).
COMMENTOID Set to a COMMENTOID value that should exist in the COMMENTS spreadsheet.

To see the Table of Contents metadata that we use for this chapter, refer to “Appendix B.1 – Table of Contents Metadata.” When the Table of Contents metadata is put in the define.xml and rendered in a web browser with the stylesheet, it looks like this:

image

Variable-Level Metadata

Domain-level or dataset-level metadata is descriptive information about the SDTM domain itself. This metadata is used to define the domain or dataset variable content that is the ItemRef component of the define.xml file. It is also used within the variable definitions section or ItemDef of the define.xml file. This metadata is the workhorse of building the SDTM domains in Base SAS because it holds the definitional framework of each SDTM domain and variable. This metadata contains definitions such as your SAS label, SAS variable type, SAS variable length, any codelist name, and other associated metadata. Each row in this metadata represents a variable in an SDTM domain dataset.

The variable-level metadata is described in the following table.

Table 2.2: Variable-Level Metadata

Excel Column Description
DOMAIN This is the name of the SDTM domain and should match the NAME in the Table of Contents metadata file.  
VARNUM The order of the variable as it is to appear in the SDTM domain, as well as the order in which it appears in define.xml. You can get the general order of SDTM variables from the SDTM metadata spreadsheet sdtmv1_2_sdtmigv3_1_2_2009_03_27_final.xls. However, if you add variables to domains as the SDTM allows, then you need to insert those variables as best you can.
VARIABLE The name of the SDTM variable required by CDISC.
TYPE This should be text, integer, float, datetime, date, or time, as appropriate. Note that SAS datasets have types of only numeric or character, so you need to add this lower level of variable type specificity.
LENGTH The length of the SDTM variable for TYPEs of integer, float, or text only. For SAS numeric variables, you can generally just set this to 8. For character variables, you need to define what this length is. Note that CDISC does not dictate variable lengths. You should stop to deliberate about what your standard lengths should be. Also note that the FDA addressed the issue of having needlessly long text variables in the Study Data Technical Conformance Guide.
LABEL The label of the SDTM variable required by CDISC.
SIGNIFICANTDIGITS If type=float, then this should be populated with the integer representing the number of decimal places for the variable.
ORIGIN This text should describe where the variable comes from. ORIGIN types are under controlled terminology in define 2.0. Valid values are: CRF, Derived, Assigned, Protocol, eDT, and Predecessor. “CRF” may be followed by “Page” or “Pages” and the corresponding annotated CRF page numbers (for example, “CRF Page 1”).
If Derived, then a COMPUTATIONMETHODOID should be provided. Predecessor is typically used for ADaM data. Refer to Chapter 6 for further details.
COMMENTOID This provides the OID to a row in the Comments spreadsheet.
DISPLAYFORMAT This is the display format for numeric values.
COMPUTATIONMETHODOID If the variable has a computational method, then this variable points to that computational method unique identifier (for example, AGECALCULATION).
CODELISTNAME If the variable has controlled terminology, whether CDISC-supplied or not, this variable points to the unique identifier of that codelist. This CODELISTNAME value is also used to populate the CODELIST OID.
MANDATORY This specifies whether an observation for the variable is mandatory to be present and not null. It can be populated with Yes or No. The authors suggest that SDTM variables that have a core definition of Required be set to Yes. Otherwise, this is set to No.
ROLE In general, this is the role of the SDTM variable, as required by CDISC.
ROLECODELIST Here we set this to ROLECODE everywhere as the unique identifier that points to the ROLECODE codelist for ROLE.
SASFIELDNAME This can be left blank, and the %make_define2 macro will populate this element with same value as VARIABLE. Otherwise, if your SAS dataset variable name differs from the name that you wish to use in the SAS transport file in an FDA submission, then the SAS transport file variable name can be specified here.

To see the variable-level metadata that we use in this chapter, refer to “Appendix B.2 –Variable-Level Metadata.” When the variable level metadata is put in the define.xml and rendered in a web browser, the section for the AE domain looks like this:

image

Codelist Metadata

Codelists are the controlled terminology applied to your SDTM variables. An example of this controlled terminology is attached to the SEX variable in the DM domain. The SEX variable has the CDISC-defined controlled terminology set called “SEX,” which includes M=Male, F=Female, and other codes. You will probably need to get your codelist data from multiple places. You can get the CDISC standard SDTM codelists by going to the CDISC website at http://www.cdisc.org/standards/foundational/terminology, which points you to the NCI Enterprise Vocabulary Services (EVS). EVS has the codelists available to you in Microsoft Excel format. You will also have other codelists that your data might use. These can be local to your company or to the trial. Finally, you might need to point to external codelists such as ones used for various medical dictionaries.

The codelist metadata is described in the following table.

Table 2.3: Codelist Metadata

Excel Column Description
CODELISTNAME The unique short name of the codelist. This is also used for the codelist OID in the define.xml file. For codelists that come from published CDISC-controlled terminology, you can find this name in the “CDISC submission value” column in blue highlighting. Otherwise, you can define this CODELISTNAME as you need to.
RANK This is an optional rank order for the codelist item. If alphabetical order is sufficient, then RANK can be left blank. However, if the coded terms should be listed in a non-alphabetical order that makes more sense, then RANK should indicate that ordering.
CODEDVALUE This is the value that you will find in the SDTM file in the result field, for example. For codelists that come from published CDISC-controlled terminology, you can find these values in the “CDISC submission value” column (not highlighted in blue). Otherwise, you can define these values as needed for your project.
TRANSLATED The text “translation” of the CODEDVALUE, which is often the same as CODEDVALUE. For codelists that come from published CDISC-controlled terminology, you can find these translated values in the “CDISC synonym(s)” column. If the “CDISC synonym(s)” column is blank, you can copy the value of the “CDISC submission value” over for this value. If this is not for a CDISC-controlled term, then you can define these values as needed for your project.
TYPE The data type of the codelist. This can be text, float, or integer.
CODELISTDICTIONARY This is the name of the external codelist dictionary. It is populated for externally defined codelists only (for example, MedDRA).
CODELISTVERSION This is populated for externally defined codelists only. It is the version number of CODELISTDICTIONARY.
ORDERNUMBER Controls the order in which the codelist items appear in the define file.

Note that the following four variables are used in the Base SAS code in Chapter 3 to make value mapping from source to SDTM target easier. These variables are not used as part of making define.xml later in this chapter.

SOURCEDATASET This variable points to the source dataset that contains the variable that will be mapped to the SDTM-controlled terminology. For codelists that do not have direct source data associations, this can be left blank.
SOURCEVARIABLE This variable points to the source variable that will be mapped to the SDTM-controlled terminology. For codelists that do not have direct source data associations, this can be left blank.
SOURCEVALUE This variable points to the source variable value that contains the actual value that will be mapped to a given SDTM-controlled terminology value. For codelists that do not have direct source data associations, this can be left blank.
SOURCETYPE This should be set to number or character, depending on whether the SOURCEVARIABLE is numeric or character in SAS. For codelists that do not have direct source data associations, this can be left blank.

To see the codelist metadata that we use for this chapter, refer to “Appendix B.3 – Codelist Metadata.” When the codelist metadata is put in the define.xml and rendered in a web browser, the section for the AESEV codelist looks like this:

image

Value-Level Metadata

Because the SDTM contains a lot of its data structured in a name/value pair and somewhat normalized data structure, there is sometimes a need to have more specificity about what a given record contains. This specificity can be stored in value-level metadata. You will notice that a lot of the same metadata fields are used in the variable-level metadata.

The value-level metadata is described in the following table.

Table 2.4: Value-Level Metadata

Excel Column Description
DOMAIN The domain for the source variable
VARIABLE The name of the source variable for which value-level metadata is being provided.
WHERECLAUSEOID Provides the OID for a row in the WHERE_CLAUSES spreadsheet.
VALUEVAR The variable to be used by VALUENAME.
VALUENAME Sets of records for which value-level metadata apply can be uniquely identified when the variable specified by VALUEVAR contains values that equal VALUENAME.
TYPE This should be text, integer, float, datetime, date, or time, as appropriate. Note that SAS datasets have only numeric or character types, so you need to add this lower level of variable type specificity.
LENGTH The length of the item for TYPEs of integer, float, or text only. For SAS numeric variables, you can generally just set this to 8. For character variables, you need to define what this length is. Note that CDISC does not require variable lengths. You should stop and deliberate about what your standard lengths should be.
LABEL The label of the value-level item.
SIGNIFICANTDIGITS If the type=float, then this should be populated with the integer representing the number of decimal places for the item.
ORIGIN This text should describe where the variable comes from. ORIGIN types are under controlled terminology in define 2.0. Valid values are: CRF, Derived, Assigned, Protocol, eDT, and Predecessor. “CRF” may be followed by “Page” or “Pages” and the corresponding annotated CRF page numbers (for example, “CRF Page 1”).
If Derived, then a COMPUTATIONMETHODOID or a COMMENTOID should be provided. Predecessor is another allowed value but is typically used for ADaM data. Refer to Chapter 6 for further details.
If Derived, then a COMPUTATIONMETHODOID or a COMMENTOID should be provided. Predecessor is typically used for ADaM data. Refer to Chapter 6 for further details.
COMMENTOID The unique ID for a comment that appears in the COMMENTS spreadsheet.
DISPLAYFORMAT This is the display format for numeric items.
COMPUTATIONMETHODOID If the value has a computational method, then this variable points to that computational method unique identifier (for example, AGECALCULATION) that appears in the COMPUTATION_METHOD spreadsheet.
CODELISTNAME If the item has controlled terminology, whether CDISC-supplied or not, this variable points to the unique identifier of that code list. For codelists, we use CODELISTNAME to populate the CODELIST OID as well.
MANDATORY This specifies whether the item is mandatory. It can be populated with Yes or No.
ROLE In general, this is the role of the SDTM item as required by CDISC.
ROLECODELIST We set this to ROLECODE for all records as the unique identifier that points to the ROLECODE codelist that defines the controlled terms for ROLE.

The first two fields, DOMAIN and VARIABLE, are used by the %make_define2 program to create a unique VALUELISTOID in the define file.  This provides a standard naming convention and obviates the need to come up with one independently.

The WHERECLAUSEOID can be left blank for simple relationships based only on the variable specified by VALUEVAR being equal to the value specified by VALUENAME.  In these situations, %make_define2 will create the where clause.  This is the case for all of our example data except for one situation.  Consider the glucose lab test.  Regardless of whether glucose is measured by a blood chemistry panel or by a urinalysis, we should have LBTESTCD=GLUC.  Other fields, such as LBCAT, can be used to distinguish between the two specimen types.  Since the blood chemistry result is a numeric one while the urinalysis result is character based, with a discrete code list (“NEGATIVE” and “POSITIVE”), value-level metadata is definitely needed to set the two apart.

To see the value-level metadata that we use for this chapter, refer to “Appendix B.4 – Value-Level Metadata.” When the value-level metadata is put in the define.xml and rendered in a web browser, you can see it in two places. If you look at the variable LBORRES in the LB variable metadata, you see it is a hyperlink:

image

If you click on that hyperlink (./lb.xpt), it takes you to the value-level metadata table where you can see the value-level metadata for LBORRES:

image

As discussed, most “values” are defined simply by LBTESTCD. But in the case of glucose, we also need to consider the value of LBCAT to distinguish between the blood chemistry and urinalysis results.  The urinalysis result is the only character one, and it has a code list associated with it.

Where Clause Metadata

Where clause metadata is new to Define-XML version 2.0.  The information needed to construct this type of metadata is provided in the following table.

Table 2.5: Where Clause Metadata

Excel Column Description
WHERECLAUSEOID An OID for the where clause.
SEQ A counter to control the order in which the where clause is constructed.
SOFTHARD If an actual data value fails the constraint, it is either rejected (a Hard constraint) or a warning is produced (a Soft constraint). In the context of Define-XML, this has no meaning. So all values may be set to Soft.
ITEMOID The ITEMOID should uniquely identify the variable being compared. Usually [DOMAIN].[VARIABLE] should suffice.
COMPARATOR The comparison operator. Valid values are LT, LE, GT, GE, EQ, NE, IN, and NOTIN.
VALUES The actual data value used for the comparison.
COMMENTOID An optional reference to an OID in the Comments spreadsheet.

Although where clauses exist in the define.xml file for every value level metadata item, they only need to be specified in the metadata spreadsheet for records that cannot be uniquely identified by only one variable value.  The %make_define2 macro will create them for these simple situations.  For example, for the albumin value-level metadata, the macro creates a WHERECLAUSEOID equal to WC.LB.ORRES.ALB, and this where clause is designed to check for LBTESTCD EQ ALB.  An example of the actual where clause XML is as follows:

 

<def:WhereClauseDef OID="WC.LB.LBORRES.ALB">

 <RangeCheck SoftHard="Soft" def:ItemOID="LB.LBTESTCD" Comparator="EQ">

   <CheckValue>ALB</CheckValue>

 </RangeCheck>

</def:WhereClauseDef>

 

This is being shown to help prevent you from creating your own WHERECLAUSEOID that might conflict with the ones that %make_define2 automatically creates.

As mentioned earlier, the only where clauses that need to be constructed for our example data are those associated with the glucose lab test.  We saw how this metadata gets represented in the define file in the previous section “Value Level Metadata.” The following screen shot demonstrates how the glucose-related where clauses are captured in spreadsheet.

image

Computational Method Metadata

Although the CDISC SDTM can be described as containing primarily the collected data for a clinical trial, you can store some derived information in the SDTM. Total scores for a questionnaire, derived laboratory values, and even the AGE variable in DM can be considered derived content that is appropriate to store in the SDTM. The define.xml file gives you a place to store this derivation, and as such we have metadata to hold that information.

The computational method metadata is described in the following table.

Table 2.6: Computational Method Metadata

Excel Column Description
COMPUTATIONMETHODOID This variable points to that computational method unique identifier (for example, “AGECALCULATION”).
LABEL A descriptive label to associate with the computational method.
TYPE Valid values are Computation and Imputation. A Computation uses an algorithm to derive a value. An Imputation is the process of replacing missing data with substitute values.
COMPUTATIONMETHOD A text string that describes the computational method. This can be natural language text, pseudo code, or even executable code.

To see the computational algorithm metadata that we use for this chapter, refer to “Appendix B.5 –Computational Method Metadata.” When the computational algorithm metadata is put in the define.xml and rendered in a web browser, the information about computational methods is in two places. The first is in the variable-level metadata section as is seen for AGE in the lower right corner of this snippet of the define file for the DM domain:

image

There is also a separate section of the define file where all computational methods are displayed.  Navigating there, you can also find the age algorithm:

image

Comments Metadata

Any ItemGroupDef or ItemDef metadata element can have a comment associated with it, as we saw in many of the previous metadata sections.  This is a change from version 1.0, which allowed specific comment attributes to each element.  The change is a good one since it allows identical comments to be specified once, but referenced in multiple locations.  The Comments metadata spreadsheet provides a common place to specify unique comments.   The comments metadata is described in the following table.

Table 2.7: Comments Metadata

Excel Column Description
COMMENTOID The unique OID for the comment.
COMMENT A comment itself, which is a free-text string

There is also a separate section of the define file where all unique comments are displayed.  Navigating there, you can also find the two comments applied to our SDTM data:

image

External Links

Typically, an SDTM define file has links to two documents: the annotated CRFs and a reviewer’s guide.  These files, and additional supplemental documents if desired, should now be specified in the External_Links spreadsheet.  The External_Links metadata is described in the following table.

Table 2.8: External Links Metadata

Excel Column Description
LeafID The unique ID for the linked document
LeafRelPath The relative path to the linked document, including the full filename
LeafPageRef A specific named destination or page number within a PDF document.
LeafPageRefType Valid values are “PhysicalRef” and “NamedDestination.” If LeafPageType=NamedDestination, then the NamedDestination must exist within the PDF document. If PhysicalRef, then a list of page numbers can be provided, separated by a space.
Title A title for the document as you wish for it to appear in the define.xml file
SupplementalDoc Valid values recognized by %make_define2 are Y, y, Yes, or 1. If any of these values are present, then the linked document will appear in the navigation pane.
AnnotatedCRF Valid values recognized by %make_define2 are Y, y, Yes, or 1. If any of these values are present, then the linked annotated CRF document will appear in the navigation pane and will be designated as such in the XML. This designation will allow links from variables with an origin of CRF to target this document and the specified pages within the document.

For our SDTM example, we have two externally linked documents: the CRT reviewer’s guide and the annotated CRF document.  The following screenshot shows how these are represented in the External_Links spreadsheet.

image

Note that the LeafRelPath values specify only the filenames since these documents reside (or will reside) in the same directory as the define file.  The corresponding XML in the define file is as follows:

 

    <def:AnnotatedCRF>

       <def:DocumentRef leafID="blankcrf"/>

     </def:AnnotatedCRF>

     <def:leaf ID="blankcrf"

       xlink:href="blankcrf.pdf">

        <def:title>Annotated Case Report Form </def:title>

     </def:leaf>

     <def:SupplementalDoc>

       <def:DocumentRef leafID="CRTRG"/>

     </def:SupplementalDoc>

     <def:leaf ID="CRTRG"

       xlink:href="reviewersguide.pdf">

       <def:title>CRT Reviewer's Guide </def:title>

     </def:leaf>

 

Building Define.xml

A significant benefit to using metadata files to drive your SDTM domain creation is that you have the essential ingredients to build define.xml. Each of the spreadsheets introduced earlier in this chapter represent separate parts of the metadata file:

   Table of Contents metadata file

   Variable-level metadata file

   Codelist metadata file

   Value-level metadata file

   Where clause metadata file

   Computational method metadata file

   Comments metadata file

   External links metadata file

Define File Header Metadata

Now you just need to define one more set of metadata, and you can create the define.xml file. This last remaining piece is the header information for define.xml. That metadata file is described in the following table.

Table 2.9: Metadata File for Define.xml

Excel Column Description
FILEOID A unique identifier for the define.xml file.
STUDYOID A unique identifier for the study.
STUDYNAME A short name of the study.
STUDYDESCRIPTION A long text description of the study.
PROTOCOLNAME A short name of the study. Can be equal to STUDYNAME.
STANDARD The CDISC standard (in this case, SDTM. In Chapter 6, it would be ADaM).
VERSION The version number of the standard.
SCHEMALOCATION The location of the XML schema file that defines the structure of define.xml. Currently not used by %make_define2.
STYLESHEET The name of the XSL style sheet that will be used to render the define.xml file in your web browser. Note that in this book, the style sheet used for the SDTM is the one that was released with the define.xml version 1.0.

To see the define header metadata that we use for this chapter, refer to “Appendix B.6 – Define Header Metadata.” This metadata as defined is essentially metadata about define.xml itself, so it does not actually render visually in the define file when opened by a web browser.

Define File Creation SAS Program

Refer to the authors’ SAS web pages (http://support.sas.com/publishing/authors/index.html  for the %make_define2 SAS macro code that is used to generate define.xml for this SDTM data. The call to make the define.xml file looks like this:

%make_define2(path=C:SDTM_metadata, metadata=SDTM_METADATA.xlsx)

In this call, the path macro parameter points to the folder where the metadata spreadsheet and the define file are finally stored. The metadata parameter points to the name of the SDTM metadata spreadsheet that contains tabs for all of the metadata defined above. The %make_define2 SAS macro assumes that your XSL style sheet that is defined in the define file header metadata field STYLESHEET already exists in the folder that is defined by the path macro parameter.

Chapter Summary

The best approach to implementing the SDTM in Base SAS is through the heavy use of metadata to drive your conversion process.

Build a metadata repository to hold your SDTM metadata, both to make conversions easier and to make building your define.xml file possible.

Leverage your metadata files to build your define.xml file with a program like make_define2.sas. You can customize this program as you see fit to create more metadata-driven parameters as you need to.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset