Core-Gadget - Data Pipelining

This is a DRAFT

     <section title="Data Pipelining" anchor="DataPipelining">
    
      <t>Data Pipelining is a declarative mechanism for defining the data a 
      gadget requires from the container. XML Elements are used to associate
      variable keys with specific kinds of data from a variety of different 
      sources. For instance, the &lt;os:DataRequest&gt; element can be used
      to access social data provided by the OpenSocial container, while the 
      &lt;os:HttpRequest&gt; element can provide access to content from any 
      HTTP endpoint.</t>
      
      <t>All Data Pipeline elements have a 'key' attribute whose value is
      used to uniquely identify the data. Such keys can be used within 
      Expression Language statements used for Variable Substitution or 
      with JavaScript API calls. Key names are always case-sensitive.</t>

      <figure><preamble>The following illustrates a basic example of 
      Data Pipelining in a partial gadget specification:</preamble>
      <artwork xml:space="preserve"><![CDATA[
  <Module xmlns:os="http://ns.opensocial.org/2008/markup">
    ...
    <Data>
      <os:DataRequest key="viewer" method="people.get" userId="@viewer" fields="name,birthday" />
      <os:HttpRequest key="remote" href="http://example.com/api" />
    </Data>
    <Content type="html">
      The viewer name is ${viewer.name}.
      
      The remote content is "${remote.result.content}".
    </Content>
  </Module>
      ]]></artwork></figure>
      
      <t>The Data Pipeline elements can appear:
        <list style="symbols">
          <t>As children of the &lt;Data&gt; element,</t>
          <t>As direct children of the &lt;Content&gt; element when the Proxied 
          Content model is used, and </t>
          <t>Within specially formatted HTML &lt;script&gt; tags included
          within HTML Content.</t>
        </list>
      </t>
      
      <t>The placement of Data Pipeline elements will determine where the 
      data associatd with the key specified will be made available to the 
      container while the gadget is being rendered. The considerations 
      and requirements for each of the options listed above are discussed 
      in detail in the relevant sections that follow.</t>
      
      <section title="The DataContext" anchor="DataContext">
        <t>For every gadget instance, a <spanx style="verb">DataContext</spanx>
        object is created that maintains all of the data associated with the 
        gadget instance's Data Pipeline elements. The information contained 
        within the <spanx style="verb">DataContext</spanx> is available for
        use with Variable Substitution via Expression Language statements 
        or via the <spanx style="verb">opensocial.data</spanx> APIs; and while
        the data contained within the <spanx style="verb">DataContext</spanx> 
        is generally populated through processing of the Data Pipeline 
        elements, the <spanx style="verb">opensocial.data</spanx> APIs can
        be used to modify values or add additional keys.</t>
      </section>
      
      <section title="Data Pipeline Elements and the Data Block">
      
        <t>By default, when Data Pipeline elements appear as children of the 
        &lt;Data&gt; element, the container will process the elements and 
        register the resulting data with the <spanx style="verb">DataContext</spanx>
        for all views.</t>
        
        <t>Individual Data Pipeline elements, however, MAY specify a "view" 
        attribute whose value is a comma separated list of specific views 
        for which the element is associated. Such elements will only be 
        processed and added to the <spanx style="verb">DataContext</spanx>
        when the identified views are being rendered.</t>
        
        <figure><preamble>In the following example, the &lt;os:HttpRequest&gt;
        element using key "foo" is registered globally and available within 
        all views while the &lt;os:HttpRequest&gt; element using key "bar"
        is only processed and available when the "example" view is being 
        rendered:</preamble><artwork><![CDATA[
  <Module>
    ...
    <Data>
      <os:HttpRequest key="foo" href="http://example.com/api" />
      <os:HttpRequest key="bar" href="http://example.com/api" view="example"/>
    </Data>
    <Content type="html">
      ...
    </Content>
    <Content type="html" view="example">
      ...
    </Content>
  </Module>
        ]]></artwork></figure>
        
        <t>Multiple Data Pipeline elements MUST NOT share the same value for
        the key attribute unless each is specifically targeted at a different 
        view. In the following example, the key "foo" would resolve to the 
        value "abc" when the default view is rendered and to "123" when the 
        "example" view is rendered:</t>
        
        <figure><artwork><![CDATA[
  <Module>
    ...
    <Data>
      <os:Var key="foo" value="abc" />
      <os:Var key="foo" value="abc" view="example" />
    </Data>
    <Content type="html">
      ...
    </Content>
    <Content type="html" view="example">
      ...
    </Content>
  </Module>       
        ]]></artwork></figure>
        
        <t>Note that currently, this specification does not specify
        exactly when the container processes the collection of Data Pipeline
        elements, nor are containers required to process data elements in 
        any particular order. Containers that process Data Pipeline elements
        to populate the <spanx style="verb">DataContext</spanx> will likely
        do so regardless of whether the referenced key is ever actually 
        used within an expression statement or API call.</t>
      
      </section>
      
      <section title="Data Pipeline Elements within HTML Content">
      
        <t>When using HTML Content, Data Pipeline elements MAY appear
        within the HTML inside a special &lt;script&gt; tag.</t>
        
        <figure><preamble>For instance,</preamble><artwork>
  &lt;Module>
    &lt;ModulePrefs&gt;
      &lt;Require feature="opensocial-data" />
    &lt;/ModulePrefs&gt;
    &lt;Content type="html">&lt;![CDATA[
      &lt;script xmlns:os="http://ns.opensocial.org/2008/markup" type="text/os-data">
        &lt;os:HttpRequest key="foo" href="http://example.com/api" />
        &lt;os:Var key="bar" value="abc123"/>
      &lt;/script>
    ]]>&lt;/Content>
  &lt;/Module>
        </artwork></figure>
        
        <t>As illustrated, when Data Pipeline elements are embedded within 
        HTML Content, the gadget specification MUST require the "opensocial-data"
        feature using the &lt;Require&gt; element within the &lt;ModulePrefs&gt;.</t>
        
        <t>The Data Pipeline elements themselves are contained within an
        HTML script tag whose type attribute specifies "text/os-data". Also
        note that the Data Pipeline XML namespace is declared for the "os:" 
        prefix. This is required in order for the embedded Data Pipeline 
        elements to processed properly while the content is being rendered.</t>
      
        <t>Data Pipeline elements defined in this manner are scoped specifically
        to the &lt;Content&gt; element in which they are embedded, meaning that
        the data each provides to the <spanx style="verb">DataContext</spanx>
        will be available for expression statements and API calls that are 
        also in the same &lt;Content&gt; element.</t>
        
        <t>If an embedded Data Pipeline element specifies the same key as a
        Data Pipeline element contained within the &lt;Data&gt; element, 
        the value provided by the embedded elements takes precedence. In the 
        following example, the variable "foo" will resolve to "123" when 
        the default view is rendered:</t>
      
        <figure><artwork>
  &lt;Module>
    &lt;ModulePrefs&gt;
      &lt;Require feature="opensocial-data" />
    &lt;/ModulePrefs&gt;
    &lt;Data&gt;
     &lt;os:Var key="foo" value="abc"/>
    &lt;/Data&gt;
    &lt;Content type="html">&lt;![CDATA[
      &lt;script xmlns:os="http://ns.opensocial.org/2008/markup" type="text/os-data">
        &lt;os:Var key="foo" value="123"/>
      &lt;/script>
    ]]>&lt;/Content>
  &lt;/Module>
        </artwork></figure>

      </section>
      
      <section title="Data Pipeline Elements and Proxied Content">
      
        <t>When using Proxied Content to render a view for a gadget,
        the container typically sends an HTTP GET request to the IRI
        provided by the &lt;Content&gt; element's href attribute. 
        In such cases, any information the remote endpoint needs to 
        generate the necessary content in response is provided within
        the IRI as query string parameters. There are times, however,
        when the endpoint requires significantly more information 
        than what can be adequately conveyed by the limited nature
        of query string parameters. To address such cases, Data Pipeline
        elements can be used directly within a &lt;Content&gt; element
        to define a collection of data that is to be sent to the 
        remote IRI using an HTTP POST request instead of GET.</t>
        
        <figure><preamble>For instance, with typical, non-pipelined 
        Proxy content:</preamble><artwork><![CDATA[
  <Content type="html" href="http://example.org/remote-server?id=${ViewParams.id}" />
        ]]></artwork></figure>
        
        <figure><preamble>The ${ViewParams.id} expression would be replaced with
        an appropriate value drawn from the View Parameters passed into the 
        gadget, and HTTP request sent to the remote endpoint by the 
        container would use HTTP GET:</preamble><![CDATA[
  GET /remote-server?id=abc123 HTTP/1.1
  Host: example.org
  Accept: application/json
        ]]></figure>
        
        <figure><preamble>However, when using Proxied Content with the 
        Data Pipeline elements, a developer can pass complex structured
        data to remote endpoint:</preamble><artwork><![CDATA[
  <Content type="html" href="http://example.org/remote-server">
    <os:Var key="id" value="${ViewParams.id}" />
    <os:Var key="name">
      {
        "givenName": "John",
        "familyName": "Doe"
      }
    </os:Var>
  </Content>
        ]]></artwork></figure>
        
        <figure><preamble>The request is transformed into an HTTP POST with
        a JSON-formatted payload containing the data specified by the 
        pipeline elements:</preamble><artwork><![CDATA[
  POST /remote-server HTTP/1.1
  Host: example.org
  Content-Type: application-json
  
  {
    "id" : "abc123",
    "name": {
      "givenName": "John",
      "familyName": "Doe"
    }
  }
        ]]></artwork></figure>
        
        <t>As illustrated by the example, each of the keys defined by the 
        Data Pipeline elements contained within the &lt;Content&gt; are 
        used as the property names in the JSON object sent to the remote 
        endpoint. The value of each property is the value returned by 
        processing the Data Pipeline element.</t>
        
        <t>&lt;Content&lt; element's of this type can contain any number 
        of Data Pipeline elements, each of which MUST have a corresponding 
        property in the generated JSON object that is sent to the server, 
        regardless of whether the attempt to process a particular Data Pipeline
        element results in an error or not. The value will be included within
        the JSON exactly as it is provided by the <spanx style="verb">DataContext</spanx>. 
        Only pipelined data contained within the &lt;Content&gt; will be 
        included in the generated JSON object.</t>
        
        <figure><preamble>In the follow example, assume that the processing
        of the &lt;os:DataRequest&gt; element fails and error details are 
        provided by the <spanx style="verb">DataContext</spanx>:</preamble>
        <artwork><![CDATA[
  <Content type="html" href="http://example.org">
    <os:Var key="key1" value="abc" />
    <os:DataRequest key="key2" method="people.get" userId="@viewer" groupId="@frields" />
  </Content>
        ]]></artwork></figure>
        
        <figure><preamble>The JSON data posted to the remote server would 
        include the value of "key1" and the error information for "key2":</preamble>
        <artwork><![CDATA[
  POST / HTTP/1.1
  Host: example.org
  Content-Type: application/json
  
  {
    "key1" : "abc",
    "key2" : {
      "error" : {
        "message" : "Processing Error",
        "code" : 500
      }
    }
  }
        ]]></artwork></figure>
        
        <t>When a gadget specification uses unrecognized Data Pipeline tags,
        the container is given the choice of either ignoring it or specifying
        a 404 (Not Found) error within the JSON using the basic error structure
        defined in [TODO: Reference to Core API spec].</t>
        
        <figure><preamble>In the example below, the gadget specification uses
        an undefined, hypothetical Data Pipeline extension:</preamble><artwork><![CDATA[
  <Content type="html" href="http://example.org">
    <os:Var key="key1" value="abc" />
    <osx:MyExtension key="key2" attr="val" />
  </Content>
        ]]></artwork></figure>
        
        <figure><preamble>The JSON generated for the HTTP POST would either 
        omit "key2" entirely:</preamble>
        <artwork><![CDATA[
  POST / HTTP/1.1
  Host: example.org
  Content-Type: application/json
   
  {
    "key1" : "abc"
  }
        ]]></artwork></figure>

        <figure><preamble>Or indicate that key2 could not be resolved:</preamble>
        <artwork><![CDATA[
  POST / HTTP/1.1
  Host: example.org
  Content-Type: application/json
   
  {
    "key1" : "abc",
    "key2" : {
      "error: {
        "message": "Not Found",
        "code": 404
      }
    }
  }
        ]]></artwork></figure>

        <t>In response to the HTTP POST request, the remote server SHOULD
        return HTML content suitable for rendering by the container. Such
        content will be processed in the same way as type "html" &lt;Content&gt;
        elements and MAY contain embedded Data Pipeline elements using the 
        customized HTML &lt;script&gt; tag.</t>

      </section>
      
      <section title="The Data Pipeline Elements">
      
        <t>This specification currently defines three Data Pipeline elements:
          <list style="hanging">
            <t hangText="os:DataRequest">Used to access social data provided
            by the container.</t>
            <t hangText="os:HttpRequest">Used to access data provided by 
            a remote endpoint.</t>
            <t hangText="os:Var">Used to define static, literal variables.</t>
          </list>
        </t>
        
        <t>The XML Namespace for each of the Data Pipeline elements is
        "http://ns.opensocial.org/2008/markup". By convention, this 
        specification uses the namespace prefix "os:" for the Data
        Pipeline Namespace. Note, however, that the choice of prefix
        is arbitrary and not semantically equivalent.</t>
        
        <t>Implementations MAY define additional Data Pipeline elements 
        that use an XML Namespace other than "http://ns.opensocial.org/2008/markup".
        Such extensions MUST contain a "key" attribute whose value specifies
        the name that will be used to associate that element's resolved value
        within the <spanx style="verb">DataContext</spanx>. Containers are 
        recommended to ignore any Data Pipeline elements they do not support or 
        do not understand.</t>
      
        <figure><artwork>
  namespace os = "http://ns.opensocial.org/2008/markup"
        
  BaseDataPipeline = {
    attribute key { text },
    undefinedAttribute*
  }
        </artwork></figure>
      
        <section title="The &lt;os:DataRequest&gt; Element" anchor="DataRequest">
        
          <t>The &lt;os:DataRequest&gt;</t> element is used to access social
          data provided by the container. It is generally equivalent to the 
          JavaScript API methods provided to the gadget by the container to 
          access information such as the identity of the current viewer, 
          a particular users group of friends, an activity stream, and so forth.
          the &lt;os:DataRequest&gt; element can only be used to access content
          and cannot be used to modify social data stored by the container.</t>

          <figure><artwork>
  DataRequest = element os:DataRequest {
    BaseDataPipeline,
    attribute method { text }
  }
          </artwork></figure>

          <t>In addition to the "key" attribute required for all Data Pipeline
          elements, the &lt;os:DataRequest&gt; element MUST contain a "method"
          attribute whose value identifies the data retrieval operation that
          is to be performed as defined by [TODO: Reference to new core data/api
          spec]. All additional attributes contained by the &lt;os:DataRequest&gt;
          are to be mapped directly to the identically named input parameters 
          for the data retrieval operation specified by the "method".</t>
          
          <t>Child elements or any additional content provided within the 
          &lt;os:DataRequest&gt; element SHOULD be ignored.</t>
          
          <t>For example, the "people.get" operation defined by 
          [TODO: Core Data/API Spec] allows a gadget to retrieve information
          about people known to the container. It can, for instance, be used
          to retrieve basic profile details about an individual or retrieve a 
          listing of associated profiles (e.g. a "friends" list).</t>
          
          <figure><preamble>When invoked using the JavaScript API to retrieve the listing
          of profiles associated with the gadget's current viewer, the 
          method is invoked as:</preamble><artwork>
  var params = {"userId": "@viewer", "groupId": "@friends"};
  osapi.people.get(params).execute(callback);
  
  function callback(friends) { ... }
          </artwork></figure>
          
          <figure><preamble>The equivalent operation using the &lt;os:DataRequest&gt;
          element would be:</preamble><artwork><![CDATA[
  <os:DataRequest key="friends" method="people.get" userId="@viewer" groupId="@friends" />
          ]]></artwork></figure>
          
          <t>Assuming the method identified was processed successfully, the 
          "friends" variable will be added to the <spanx style="verb">DataContext</spanx>
          with a value identical to that provided as input to the callback 
          function in the previous JavaScript API.</t>
        
        </section>
        
        <section title="The &lt;os:HttpRequest&gt; Element" anchor="HttpRequest">
        
          <t>The &lt;os:HttpRequest&gt;</t> element is used to access arbitrary
          content from a remote HTTP endpoint. It is generally equivalent to the 
          <spanx style="verb">osapi.http</spanx> JavaScript API methods provided 
          to the gadget by the container. Currently, only HTTP GET and POST 
          methods are supported.</t>
          
          <figure><artwork>
  DataRequest = element os:DataRequest {
    BaseDataPipeline,
    SignedFetch,
    attribute method { "get" | "post" },
    attribute href { IRI }
  }
          </artwork></figure>
        
          <t>In addition to the "key" attribute required for all Data Pipeline
          elements, the &lt;os:HttpRequest&gt; element MUST contain a "method"
          attribute whose value is either "get" or "post" indicating the HTTP 
          request method to use for the request, and an "href" attribute whose
          value specifies a dereferenceable IRI to which the request will be 
          sent. If not specified, the value of the "method" attribute will be 
          assumed to be "get". All additional attributes contained by the 
          &lt;os:HttpRequest&gt; are to be mapped directly to the identically 
          named input parameters defined for corresponding 
          <spanx style="verb">osapi.http.get</spanx> or <spanx style="verb">osapi.http.post</spanx>
          JavaScript APIs.</t>
          
          <t>Child elements or any additional content provided within the 
          &lt;os:HttpRequest&gt; element SHOULD be ignored.</t>
          
          <figure><preamble>For example, the <spanx style="verb">osapi.http.get</spanx>
          operation can be used to retrieve content from a remote endpoint 
          located a "http://example.org/foo":</preamble><artwork>
  var params = {"format":"json", "authz":"signed"};
  osapi.http.get(params).execute(callback);
  
  function callback(results) { ... }
          </artwork></figure>
          
          <figure><preamble>The equivalent operation using the &lt;os:HttpRequest&gt;
          element would be:</preamble><artwork><![CDATA[
  <os:HttpRequest key="results" format="json" authz="signed" />
          ]]></artwork></figure>
          
          <t>Assuming the method identified was processed successfully, the 
          "results" variable will be added to the <spanx style="verb">DataContext</spanx>
          with a value identical to that provided as input to the callback 
          function in the previous JavaScript API.</t>
          
          <t>The exact structure of the value stored within the <spanx style="verb">DataContext</spanx>
          will depend on the type of response returned by the remote endpoint.
          Currently, the only supported options are for the server to return 
          JSON-formatted data, textual content (e.g. plain text or HTML) or 
          an error response. Binary content is currently not supported.</t>
          
          <figure><preamble>If the server returns a JSON formatted response
          such as:</preamble><artwork>
  HTTP/1.1 200 OK
  Content-Type: application/json
  
  { "data" : "xyz" }
          </artwork></figure>
        
          <figure><preamble>The value stored within the <spanx style="verb">DataContext</spanx>
          would be:</preamble><artwork>
  {
    "result" : {
      "content" : {
        "data" : "xyz"
      },
      "status" : 200,
      "headers" : {
        "Content-Type" : [
          "application/json"
        ]
      }
    }
  }
          </artwork></figure>
        
          <figure><preamble>If the server turns textual content such as:</preamble>
          <artwork><![CDATA[
  HTTP/1.1 200 OK
  Content-Type: text/html
  
  <html><head>...</head><body>Hello World</body></html>
          ]]></artwork></figure>
        
          <figure><preamble>The value stored within the <spanx style="verb">DataContext</spanx>
          would be:</preamble><artwork><![CDATA[
  {
    "result" : {
      "content" : "<html><head>...</head><body>Hello World</body></html>",
      "result": 200,
      "headers" : {
        "Content-Type" : [
          "text/html"
        ]
      }
    }
  }
          ]]></artwork></figure>
        
          <figure><preamble>If the server returns an error, or if the content 
          returned by the server is neither text-based or valid JSON, the value
          stored by the <spanx style="verb">DataContext</spanx> will specify an 
          error with an appropriate value indicating the nature of the error.
          Within the value of the "error" property, the "data" property contains
          the content actually returned by the server, if any.</preamble>
          <artwork><![CDATA[
  {
    "error" : {
      "code" : 404,
      "message" : "Not Found",
      "data" : {
        "content" : "<html><body>File not found</body></html>",
        "headers" : {
          "Content-Type" : [
            "text/html"
          ]
        }
      }
    }
  }
          ]]></artwork></figure>
        
        </section>
        
        <section title="The &lt;os:Var&gt; Element" anchor="Var">
        
          <t>The &lt;os:Var&gt;</t> element is used to declare a string 
          JSON object, or JavaScript array as a literal value or associate 
          the results of evaluating an Expression Statement with a key.</t>
          
          <figure><artwork>
  SimpleVar = element os:Var {
    BaseDataPipeline,
    value { text }
  }
  
  JsonVar = element os:Var {
    BaseDataPipeline,
    text
  }
  
  Var = SimpleVar | JsonVar
          </artwork></figure>
        
          <t>In addition to the "key" attribute required for all 
          Data Pipeline elements, the &lt;os:Var&gt; element can either 
          contain a "value" attribute or contain textual content.</t>
          
          <figure><preamble>The following &lt;os:Var&gt; examples are equivalent:</preamble>
          <artwork><![CDATA[
  <os:Var key="key1" value="ABC" />
  
  <os:Var key="key1">ABC</os:Var>
          ]]></artwork></figure>
  
          <t>When determining the value to store within the <spanx style="verb">DataContext</spanx>,
          the container will:
            <list style="symbols">
              <t>First apply Variable Substitution to replace all Expression
              Language statements appearing within the value,</t>
              <t>Then, attempt to parse the string as a JavaScript Array. For
              instance, if the value is "[1,2,3,4,5]", then a JavaScript Array
              containing the values 1, 2, 3, 4 and 5 will be created. If 
              successfully parsed, the Array will be stored into the 
              <spanx style="verb">DataContext</spanx> and processing will end.</t>
              <t>If unable to parse as an array, the container will attempt 
              to parse the value as a JSON Object. If successfully parsed, the
              object will be stored into the <spanx style="verb">DataContext</spanx>
              and processing will end.</t>
              <t>If the value is still unable to be parsed, it will be stored 
              within the <spanx style="verb">DataContext</spanx> as a literal
              string value.</t>
            </list>
          </t>
          
          <figure><preamble>Given the example,</preamble><artwork><![CDATA[
  <os:Var key="key1">
    [{"data": ${1+1}}]
  <os:Var>
          ]]></artwork></figure>
         
          <figure><preamble>The value stored within the <spanx style="verb">DataContext</spanx>
          will be a JavaScript array containing a JSON object with a single 
          property "data" whose value is the result of processing the Expression
          Language statement "${1+1}":</preamble><artwork><![CDATA[
  [
    { "data":2 }
  ]
          ]]></artwork></figure>
        
        </section>
        
        <section title="Expression Statements within Data Pipeline Attributes">
        
          <t>The attributes used with the &lt;os:DataRequest&gt; 
          and &lt;os:HttpRequest&gt; elements often require values that 
          vary depending on a range of criteria including input parameters
          or the results returned by other Data Pipeline elements.</t>
          
          <t>For instance, when the gadget needs to display the next 
          set of results from a paged-collection, the view 
          parameters specifying the current page can be passed into
          the &lt;os:HttpRequest&gt; or &lt;os:DataRequest&gt;
          using Expression Language statements:</t>
          
          <figure><artwork><![CDATA[
  <os:DataRequest key="PagedFriends" method="people.get" 
    userId="@owner" groupId="@friends" 
    startIndex="${ViewParams.first}" 
    count="20"/>
          ]]></artwork></figure>
          
          <t>Likewise, the results of one Data Pipeline element can 
          be passed as attribute values in another. For instance, 
          we can reference the stored value for the "PagedFriends"
          key generated by processing the previous example within 
          an &lt;os:HttpRequest&gt;:</t>
          
          <figure><artwork><![CDATA[
  <os:HttpRequest href="http://example.com/api?ids=${PagedFriends.ids}"/>
          ]]></artwork></figure>
          
          <t>When referencing the results of other Data Pipeline elements 
          in this way, Expression Language statements can access the input 
          parameters and additional metadata about the referenced results by using the special reserved
          "Request" property on the referenced key, e.g. "${PagedFriends.Request.userId}"</t>
          
          <t>The metadata properties provided by the "Request" property include:
            <list style="symbols">
              <t>All of the attributes defined on the referenced Data Pipeline
              element (in the previous example, these would include "key", "method",
              "userId", "groupId", "startIndex", and "count"),
              <t>The properties "totalResults", "count" and "startIndex" if 
              the value stored by referenced key is a Collection object 
              as defined by [TODO: Reference Core Data]; the values of which
              map to the corresponding values of the stored collection.</t>
            </list>
          </t>
          
          <t>These properties are determined dynamically by the container 
          and can be used within any Expression Language statement:</t>
          
          <figure><artwork><![CDATA[
  <os:DataRequest key="Page1" method="people.get"
    userId="@owner" groupId="@friends"
    startIndex="${ViewParams.first}" count="20"/>

  <os:DataRequest key="Page2" method="people.get" 
    userId="${Page1.Request.userId}" groupId="@friends"
    startIndex="${Page1.Request.startIndex + Page1.Request.count}"
    count="${Page1.Request.count}"/>          
          ]]></artwork></figure>
        
        </section>
      </section>
  </section>
    <!--  END DATA PIPELINING -->

a