<!-- 
RSS generated by JIRA (8.20.10#820010-sha1:ace47f9899e9ee25d7157d59aa17ab06aee30d3d) at Wed Feb 07 20:36:50 UTC 2024

It is possible to restrict the fields that are returned in this document by specifying the 'field' parameter in your request.
For example, to request only the issue key and summary append 'field=key&field=summary' to the URL of your request.
-->
<rss version="0.92" >
<channel>
    <title>OpenDaylight JIRA</title>
    <link>https://jira.opendaylight.org</link>
    <description>This file is an XML representation of an issue</description>
    <language>en-us</language>    <build-info>
        <version>8.20.10</version>
        <build-number>820010</build-number>
        <build-date>22-06-2022</build-date>
    </build-info>


<item>
            <title>[PLAS-7] Users need to specify unfolding/handling of nested array elements in schemas</title>
                <link>https://jira.opendaylight.org/browse/PLAS-7</link>
                <project id="10600" key="PLAS">plastic</project>
                    <description></description>
                <environment></environment>
        <key id="32365">PLAS-7</key>
            <summary>Users need to specify unfolding/handling of nested array elements in schemas</summary>
                <type id="10103" iconUrl="https://jira.opendaylight.org/secure/viewavatar?size=xsmall&amp;avatarId=10311&amp;avatarType=issuetype">New Feature</type>
                                            <priority id="3" iconUrl="https://jira.opendaylight.org/images/icons/priorities/major.svg">Medium</priority>
                        <status id="10002" iconUrl="https://jira.opendaylight.org/" description="">Done</status>
                    <statusCategory id="3" key="done" colorName="green"/>
                                    <resolution id="10000">Done</resolution>
                                        <assignee username="-1">Unassigned</assignee>
                                    <reporter username="allanclarke">Allan Clarke</reporter>
                        <labels>
                    </labels>
                <created>Mon, 27 Jan 2020 20:08:14 +0000</created>
                <updated>Thu, 30 Jul 2020 15:31:50 +0000</updated>
                            <resolved>Thu, 30 Jul 2020 15:31:50 +0000</resolved>
                                                                        <due></due>
                            <votes>0</votes>
                                    <watches>1</watches>
                                                                                                                <comments>
                            <comment id="67705" author="allanclarke" created="Tue, 28 Jan 2020 20:45:29 +0000"  >&lt;p&gt;Today Plastic allows binding on the input side and expansion on the output side for collections (JSon lists)&lt;br/&gt;
embedded within a given payload. Today this feature has limitations. &lt;/p&gt;

&lt;p&gt;    ${abc&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&lt;/p&gt;

&lt;p&gt;First, it does not handle nested arrays withtout the schema designer breaking up the translation into &lt;br/&gt;
multiple levels using multiple intput/output schemas. Second, it sort-of allows re-use of the asterisk &lt;br/&gt;
for sibling arrays (and just hopes that the array lengths are the same). Conceptually there is only a &lt;br/&gt;
single asterisk and it represents only a single length.&lt;/p&gt;

&lt;p&gt;   Side note: the sibling array issue either results in a short output or an error, depending on&lt;br/&gt;
   which array Plastic encounters first. If array A is of size 10 and B is of 20, if Plastic encounters&lt;br/&gt;
   A first in expanding an output array that uses both A and B, then there will be 10 members of that&lt;br/&gt;
   output array. If it encounters B first, then when it gets to the 11th expansion, it will fail to &lt;br/&gt;
   find an 11th value for A and will error out.&lt;/p&gt;

&lt;p&gt;To handle an arbitrary number of collection sizes, the asterisk needs to represent an arbitrary number&lt;br/&gt;
of values through two possible means. Plastic can generalize the current scheme by having an asterisk&lt;br/&gt;
usage per level of nesting. You might see this say in a schema using this syntax&lt;/p&gt;

&lt;p&gt;    ${abc&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&lt;/p&gt;

&lt;p&gt;This is simple to understand and can handle arbitrary nesting by adding more &quot;&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;&quot; to match the nesting&lt;br/&gt;
level.&lt;/p&gt;

&lt;p&gt;    Side note: there is an interesting case of how to flatten. If the input payload has an array&lt;br/&gt;
    within an array so &lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt; is used and the output has only a single array, then Plastic needs&lt;br/&gt;
    to map two dimensions into one by flattening.&lt;/p&gt;

&lt;p&gt;Using only the nesting level and multiple &lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt; does not fix the sibling array issue, because two sibling&lt;br/&gt;
arrays sharing a parent array still might have different lengths.&lt;/p&gt;

&lt;p&gt;A new expansion feature can do better however.&lt;/p&gt;

&lt;p&gt;An iterator comes into existence when there are one or more &lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt; as part of an arrayed variable when&lt;br/&gt;
the payload is matched against an input schema. Iterators are not create on the output side, they are&lt;br/&gt;
just used to expand arrays. Iterators will have a name that is a derivative of the variable name to&lt;br/&gt;
which they were bound.&lt;/p&gt;

&lt;p&gt;Most importantly, iterators will be merged together so that mixing outputs together like the sibling&lt;br/&gt;
array alluded to above are handled intuitively.&lt;/p&gt;

&lt;p&gt;Lets look at examples. &lt;/p&gt;


&lt;p&gt;1 - Introducing Iterators&lt;br/&gt;
-------------------------&lt;/p&gt;

&lt;p&gt;Consider this in the INPUT schema...&lt;/p&gt;

&lt;p&gt;    ${abc&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&lt;/p&gt;

&lt;p&gt;Consider this on the OUTPUT schema...&lt;/p&gt;

&lt;p&gt;    ${abc&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&lt;/p&gt;

&lt;p&gt;The new feature would create an iterator with the name &apos;abc&apos; and the length L (from the payload) when&lt;br/&gt;
the payload is bound to the input schema. On the output side, the abc variable will automatically be&lt;br/&gt;
using the abc iterator from the input side.&lt;/p&gt;

&lt;p&gt;So right now our working definition of an iterator is a name and a range 0..(L-1). Later on when we&lt;br/&gt;
cover nested arrays, we&apos;ll expand the definition of an iterator to be more complex.&lt;/p&gt;

&lt;p&gt;2 - Independent Sibling Arrays&lt;br/&gt;
------------------------------&lt;/p&gt;

&lt;p&gt;Payload...&lt;/p&gt;
    {
	&quot;abc&quot;: [ &apos;aa&apos;, &apos;bb&apos;, ... &apos;zz&apos; ],
        &quot;colors&quot;: [ &quot;red&quot;, &quot;green&quot;, &quot;blue&quot; ]
    }

&lt;p&gt;Input schema...&lt;br/&gt;
    {&lt;br/&gt;
	&quot;abc&quot;: [ &quot;${abc&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&quot; ],&lt;br/&gt;
	&quot;colors&quot;: [ &quot;${colors&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&quot; ]&lt;br/&gt;
    }&lt;/p&gt;

&lt;p&gt;Internal bindings...&lt;/p&gt;

&lt;p&gt;    abc&lt;span class=&quot;error&quot;&gt;&amp;#91;0&amp;#93;&lt;/span&gt; = aa&lt;br/&gt;
    abc&lt;span class=&quot;error&quot;&gt;&amp;#91;1&amp;#93;&lt;/span&gt; = bb&lt;br/&gt;
    ...&lt;br/&gt;
    abc&lt;span class=&quot;error&quot;&gt;&amp;#91;25&amp;#93;&lt;/span&gt; = zz&lt;/p&gt;

&lt;p&gt;    _&lt;span class=&quot;error&quot;&gt;&amp;#91;abc&amp;#93;&lt;/span&gt; = (26)&lt;/p&gt;

&lt;p&gt;    colors&lt;span class=&quot;error&quot;&gt;&amp;#91;0&amp;#93;&lt;/span&gt; = red&lt;br/&gt;
    colors&lt;span class=&quot;error&quot;&gt;&amp;#91;1&amp;#93;&lt;/span&gt; = green&lt;br/&gt;
    colors&lt;span class=&quot;error&quot;&gt;&amp;#91;2&amp;#93;&lt;/span&gt; = blue&lt;/p&gt;

&lt;p&gt;    _&lt;span class=&quot;error&quot;&gt;&amp;#91;colors&amp;#93;&lt;/span&gt; = (3)&lt;/p&gt;

&lt;p&gt;Output schema...&lt;br/&gt;
    {&lt;br/&gt;
	&quot;foo&quot;: [ &quot;${abc&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&quot; ],&lt;br/&gt;
	&quot;bar&quot;: [ &quot;${colors&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&quot; ]&lt;br/&gt;
    }&lt;/p&gt;

&lt;p&gt;Output...&lt;/p&gt;
    {
	&quot;foo&quot;: [ &apos;aa&apos;, &apos;bb&apos;, ... &apos;zz&apos; ],
	&quot;bar&quot;: [ &quot;red&quot;, &quot;green&quot;, &quot;blue&quot; ]
    }

&lt;p&gt;We introduce the internal naming for the iterator (_&lt;span class=&quot;error&quot;&gt;&amp;#91;name&amp;#93;&lt;/span&gt;). We introduced the (n,m,...) as a way to &lt;br/&gt;
represent the ranges of the indices. They are a list of ints with one per dimension. So (26) above &lt;br/&gt;
is a list of one number.&lt;/p&gt;

&lt;p&gt;Output Steps&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Encounter owning collection and push on parent stack with empty iterator&lt;/li&gt;
	&lt;li&gt;Encounter array variable&lt;/li&gt;
	&lt;li&gt;Verify iterator exists and dimensionality matches else ERROR&lt;/li&gt;
	&lt;li&gt;Impose iterator on iterator stack (effectively replaces empty iterator)&lt;/li&gt;
	&lt;li&gt;Start iterate, clone, recurse&lt;/li&gt;
	&lt;li&gt;Pop parent stack including iterator&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;4 - Mixing Input Arrays into a Single Output Array&lt;br/&gt;
--------------------------------------------------&lt;/p&gt;

&lt;p&gt;Payload...&lt;/p&gt;
    {
	&quot;aaa&quot;: [ &apos;aa&apos;, &apos;bb&apos;, &apos;cc&apos; ],
        &quot;colors&quot;: [ &quot;red&quot;, &quot;green&quot;, &quot;blue&quot;, &quot;purple&quot; ]
    }

&lt;p&gt;Input schema...&lt;br/&gt;
    {&lt;br/&gt;
	&quot;aaa&quot;: [ &quot;${aaa&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&quot; ],&lt;br/&gt;
	&quot;colors&quot; [ &quot;${colors&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&quot; ]&lt;br/&gt;
    }&lt;/p&gt;

&lt;p&gt;Internal bindings...&lt;/p&gt;

&lt;p&gt;    aaa&lt;span class=&quot;error&quot;&gt;&amp;#91;0&amp;#93;&lt;/span&gt; = aa&lt;br/&gt;
    aaa&lt;span class=&quot;error&quot;&gt;&amp;#91;1&amp;#93;&lt;/span&gt; = bb&lt;br/&gt;
    aaa&lt;span class=&quot;error&quot;&gt;&amp;#91;2&amp;#93;&lt;/span&gt; = cc&lt;/p&gt;

&lt;p&gt;    _&lt;span class=&quot;error&quot;&gt;&amp;#91;aaa&amp;#93;&lt;/span&gt; = (3)&lt;/p&gt;

&lt;p&gt;    colors&lt;span class=&quot;error&quot;&gt;&amp;#91;0&amp;#93;&lt;/span&gt; = red&lt;br/&gt;
    colors&lt;span class=&quot;error&quot;&gt;&amp;#91;1&amp;#93;&lt;/span&gt; = green&lt;br/&gt;
    colors&lt;span class=&quot;error&quot;&gt;&amp;#91;2&amp;#93;&lt;/span&gt; = blue&lt;br/&gt;
    colors&lt;span class=&quot;error&quot;&gt;&amp;#91;3&amp;#93;&lt;/span&gt; = purple&lt;/p&gt;

&lt;p&gt;    _&lt;span class=&quot;error&quot;&gt;&amp;#91;colors&amp;#93;&lt;/span&gt; = (4)&lt;/p&gt;

&lt;p&gt;Output schema...&lt;br/&gt;
    {&lt;br/&gt;
	&quot;foobar&quot;: [ &quot;${aaa&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;=xx}/${colors&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;=gray}&quot; ]&lt;br/&gt;
    }&lt;/p&gt;

&lt;p&gt;Output...&lt;/p&gt;
    {
	&quot;foobar&quot;: [ &quot;aa/red&quot;, &quot;bb/green&quot;, &quot;cc/blue&quot;, &quot;xx/purple&quot; ]
    }


&lt;p&gt;The &quot;foobar&quot; array in the output schema is constructed from two arrayed variables &quot;aaa&quot; and&lt;br/&gt;
&quot;colors&quot;. If the length for aaa is not the same as the length for colors, then this would&lt;br/&gt;
result in an error, unless there are defaults present.&lt;/p&gt;

&lt;p&gt;Output Steps&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Encounter owning collection and push on parent stack with empty iterator&lt;/li&gt;
	&lt;li&gt;Encounter array variables&lt;/li&gt;
	&lt;li&gt;Verify iterators exists and dimensionality matches else ERROR&lt;/li&gt;
	&lt;li&gt;Impose iterator aaa on iterator stack (effectively replacing empty iterator)&lt;/li&gt;
	&lt;li&gt;Impose iterator colors&lt;/li&gt;
&lt;/ul&gt;
&lt;ul class=&quot;alternate&quot; type=&quot;square&quot;&gt;
	&lt;li&gt;existing iterator, so need to merge&lt;/li&gt;
	&lt;li&gt;for each dimension, take the larger range&lt;/li&gt;
	&lt;li&gt;if dimension is missing, then it wins&lt;/li&gt;
	&lt;li&gt;merged iterator now has two names aaa and colors&lt;/li&gt;
	&lt;li&gt;no worry yet about imposing up the parent stack because dimension = 1&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;Start iterate, clone, recurse&lt;/li&gt;
	&lt;li&gt;Pop iterator stack when popping parent stack&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;5 - Multivariable Example&lt;br/&gt;
-------------------------&lt;br/&gt;
Payload...&lt;br/&gt;
  {&lt;br/&gt;
    &quot;deviceName&quot;: &quot;CXP-2501&quot;,&lt;br/&gt;
    &quot;interfaceName&quot;: &quot;TCP/1/0/24&quot;,&lt;br/&gt;
    &quot;addresses&quot;: [&lt;br/&gt;
      &lt;/p&gt;
{
        &quot;address&quot;: &quot;10.10.100.100&quot;,
        &quot;prefix-length&quot;: &quot;24&quot;
      }
&lt;p&gt;,&lt;br/&gt;
      &lt;/p&gt;
{
        &quot;address&quot;: &quot;10.10.100.221&quot;,
        &quot;prefix-length&quot;: &quot;24&quot;
      }
&lt;p&gt;,&lt;/p&gt;
      {
        &quot;address&quot;: &quot;10.10.100.168&quot;,
        &quot;prefix-length&quot;: &quot;24&quot;
      }
&lt;p&gt;    ]&lt;br/&gt;
  }&lt;/p&gt;

&lt;p&gt;Input schema...&lt;br/&gt;
  {&lt;br/&gt;
    &quot;deviceName&quot;: &quot;${dName}&quot;,&lt;br/&gt;
    &quot;interfaceName&quot;: &quot;${iName}&quot;,&lt;br/&gt;
    &quot;addresses&quot;: [&lt;br/&gt;
      {&lt;br/&gt;
        &quot;address&quot;: &quot;${addr&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&quot;,&lt;br/&gt;
        &quot;prefix-length&quot;: &quot;${pref-len&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&quot;&lt;br/&gt;
      }&lt;br/&gt;
    ]&lt;br/&gt;
  }&lt;/p&gt;

&lt;p&gt;    addr&lt;span class=&quot;error&quot;&gt;&amp;#91;0&amp;#93;&lt;/span&gt; = 10.10.100.100&lt;br/&gt;
    addr&lt;span class=&quot;error&quot;&gt;&amp;#91;1&amp;#93;&lt;/span&gt; = 10.10.100.221&lt;br/&gt;
    addr&lt;span class=&quot;error&quot;&gt;&amp;#91;2&amp;#93;&lt;/span&gt; = 10.10.100.168&lt;/p&gt;

&lt;p&gt;    _&lt;span class=&quot;error&quot;&gt;&amp;#91;addr&amp;#93;&lt;/span&gt; = (3)&lt;/p&gt;

&lt;p&gt;    pref&lt;span class=&quot;error&quot;&gt;&amp;#91;0&amp;#93;&lt;/span&gt; = 24&lt;br/&gt;
    pref&lt;span class=&quot;error&quot;&gt;&amp;#91;1&amp;#93;&lt;/span&gt; = 24&lt;br/&gt;
    pref&lt;span class=&quot;error&quot;&gt;&amp;#91;2&amp;#93;&lt;/span&gt; = 24&lt;/p&gt;

&lt;p&gt;    _&lt;span class=&quot;error&quot;&gt;&amp;#91;pref-len&amp;#93;&lt;/span&gt; = (3)&lt;/p&gt;

&lt;p&gt;Output schema...&lt;br/&gt;
  {&lt;br/&gt;
    &quot;dev-name&quot;: &quot;${dName}&quot;,&lt;br/&gt;
    &quot;interface-name&quot;: &quot;${iName}&quot;,&lt;br/&gt;
    &quot;objects&quot;: [&lt;br/&gt;
      {&lt;br/&gt;
        &quot;subnet&quot;: &quot;${addr&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}/${pref-len&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&quot;&lt;br/&gt;
      }&lt;br/&gt;
    ]&lt;br/&gt;
  }&lt;/p&gt;

&lt;p&gt;There are two iterators named &apos;addr&apos; and &apos;pref-len&apos; that are associated with the parent array.&lt;br/&gt;
It turns out that they have the same range.&lt;/p&gt;

&lt;p&gt;Output Steps&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;very similar to the previous example&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;6 - Multi-dimensional Example (two deep)&lt;br/&gt;
----------------------------------------&lt;/p&gt;

&lt;p&gt;Payload...&lt;br/&gt;
    {&lt;br/&gt;
	&quot;aaa&quot;: [ &lt;br/&gt;
	    &lt;/p&gt;
{
		&quot;id&quot;: &quot;1&quot;,
	        &quot;bbb&quot;: [ &apos;a&apos;, &apos;b&apos;, &apos;c&apos; ]
            }
&lt;p&gt;,&lt;br/&gt;
	    &lt;/p&gt;
{
		&quot;id&quot;: &quot;2&quot;,
	        &quot;bbb&quot;: [ &apos;d&apos;, &apos;e&apos; ]
            }
&lt;p&gt;,&lt;br/&gt;
	    &lt;/p&gt;
{
		&quot;id&quot;: &quot;3&quot;,
	        &quot;bbb&quot;: [ &apos;f&apos; ]
            }
&lt;p&gt;,&lt;/p&gt;
            {
		&quot;id&quot;: &quot;4&quot;,
	        &quot;bbb&quot;: [ ]
            }
&lt;p&gt;	]&lt;br/&gt;
    }&lt;/p&gt;

&lt;p&gt;Input schema...&lt;br/&gt;
    {&lt;br/&gt;
	&quot;aaa&quot;: [ &amp;lt;------------ parent/owning array&lt;br/&gt;
	    {&lt;br/&gt;
		&quot;id&quot;: &quot;${id&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;},&lt;br/&gt;
	        &quot;bbb&quot;: [ &amp;lt;-------------- child/nested array&lt;br/&gt;
		    &quot;${bbb&lt;span class=&quot;error&quot;&gt;&amp;#91;^&amp;#93;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&quot;&lt;br/&gt;
		],&lt;br/&gt;
            }&lt;br/&gt;
	]&lt;br/&gt;
    }&lt;/p&gt;

&lt;p&gt;Rule: if &quot;id&quot; or &quot;bbb&quot; is missing, then its an error (that might be resolved through early classifier normalization)&lt;/p&gt;

&lt;p&gt;     id&lt;span class=&quot;error&quot;&gt;&amp;#91;0&amp;#93;&lt;/span&gt; = 1&lt;br/&gt;
     id&lt;span class=&quot;error&quot;&gt;&amp;#91;1&amp;#93;&lt;/span&gt; = 2&lt;br/&gt;
     id&lt;span class=&quot;error&quot;&gt;&amp;#91;2&amp;#93;&lt;/span&gt; = 3&lt;br/&gt;
     id&lt;span class=&quot;error&quot;&gt;&amp;#91;3&amp;#93;&lt;/span&gt; = 4&lt;/p&gt;

&lt;p&gt;     _&lt;span class=&quot;error&quot;&gt;&amp;#91;id&amp;#93;&lt;/span&gt; = (4)&lt;/p&gt;

&lt;p&gt;     bbb&lt;span class=&quot;error&quot;&gt;&amp;#91;0&amp;#93;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;0&amp;#93;&lt;/span&gt; = a&lt;br/&gt;
     bbb&lt;span class=&quot;error&quot;&gt;&amp;#91;0&amp;#93;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;1&amp;#93;&lt;/span&gt; = b&lt;br/&gt;
     bbb&lt;span class=&quot;error&quot;&gt;&amp;#91;0&amp;#93;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;2&amp;#93;&lt;/span&gt; = c&lt;br/&gt;
     bbb&lt;span class=&quot;error&quot;&gt;&amp;#91;1&amp;#93;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;0&amp;#93;&lt;/span&gt; = d&lt;br/&gt;
     bbb&lt;span class=&quot;error&quot;&gt;&amp;#91;1&amp;#93;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;1&amp;#93;&lt;/span&gt; = e&lt;br/&gt;
     bbb&lt;span class=&quot;error&quot;&gt;&amp;#91;2&amp;#93;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;0&amp;#93;&lt;/span&gt; = f&lt;/p&gt;

&lt;p&gt;     _&lt;span class=&quot;error&quot;&gt;&amp;#91;bbb&amp;#93;&lt;/span&gt; = (4,3)&lt;/p&gt;

&lt;p&gt;Note: this example shows that you cannot even count on rectangular matrices (ie, bbb is not 4x3=12)!&lt;br/&gt;
And because of this, we may have shortened ranges (they must be dealt with). Worse, they actually&lt;br/&gt;
can be real holes and can be at any level of dimension. So even though there are only 6 entries &lt;br/&gt;
for bbb, we have to iterate over all 12 possibilities to be sure to cover everything.&lt;/p&gt;

&lt;p&gt;Note that had bbb been given default values, it would have &quot;filled in the holes&quot; so that it is a&lt;br/&gt;
squared off 4x3&lt;/p&gt;

&lt;p&gt;6A - Flattening&lt;br/&gt;
---------------&lt;/p&gt;

&lt;p&gt;Output schema...&lt;br/&gt;
    {&lt;br/&gt;
	&quot;foo&quot;: [&lt;br/&gt;
	    &quot;${id&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&quot;&lt;br/&gt;
	],&lt;br/&gt;
	&quot;bar&quot;: [&lt;br/&gt;
	    &quot;${bbb&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&quot;&lt;br/&gt;
	]&lt;br/&gt;
    }&lt;/p&gt;

&lt;p&gt;Output...&lt;/p&gt;
    {
	&quot;foo&quot;: [ 1, 2, 3, 4 ],
	&quot;bar&quot;: [ &apos;a&apos;, &apos;b&apos;, &apos;c&apos;, &apos;d&apos;, &apos;e&apos;, &apos;f&apos; ]
    }

&lt;p&gt;Flattening occurs when the number asterisks is the same as the number of dimensions on the data.&lt;/p&gt;


&lt;p&gt;Rule: silently ignore indices in bbb that don&apos;t exist (to allow for holes in data)&lt;/p&gt;


&lt;p&gt;Output Steps&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Encounter owning collection and push on parent stack with empty iterator&lt;/li&gt;
	&lt;li&gt;Encounter array variable called id&lt;/li&gt;
	&lt;li&gt;Verify iterator exists and dimensionality matches else ERROR&lt;/li&gt;
	&lt;li&gt;Impose iterator id on iterator stack (effectively replacing empty iterator)&lt;/li&gt;
	&lt;li&gt;Start iterate, clone, recurse&lt;/li&gt;
	&lt;li&gt;Pop iterator stack when popping parent stack&lt;/li&gt;
&lt;/ul&gt;


&lt;ul&gt;
	&lt;li&gt;Encounter bar collection and push on parent stack with empty iterator&lt;/li&gt;
	&lt;li&gt;Encounter array variable called bbb&lt;/li&gt;
	&lt;li&gt;Verify iterator exists and dimensionality matches else ERROR&lt;/li&gt;
	&lt;li&gt;Impose iterator id on iterator stack&lt;/li&gt;
&lt;/ul&gt;
&lt;ul class=&quot;alternate&quot; type=&quot;square&quot;&gt;
	&lt;li&gt;empty iterator is there&lt;/li&gt;
	&lt;li&gt;parent stack is 1 deep (argument to make iterator stack and parent stack be the same)&lt;/li&gt;
	&lt;li&gt;dimensionality is 2&lt;/li&gt;
	&lt;li&gt;all of dimensionality is handled at this depth&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;Start iterate, clone, recurse&lt;/li&gt;
	&lt;li&gt;Pop iterator stack when popping parent stack&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Similar output schema but top level array and using new ^ ...&lt;br/&gt;
    [&lt;br/&gt;
	{&lt;br/&gt;
	  	&quot;foo&quot;: [&lt;br/&gt;
		    &quot;${id&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&quot;&lt;br/&gt;
		],&lt;br/&gt;
		&quot;bar&quot;: [&lt;br/&gt;
		    &quot;${bbb&lt;span class=&quot;error&quot;&gt;&amp;#91;^&amp;#93;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&quot;&lt;br/&gt;
		]&lt;br/&gt;
	}&lt;br/&gt;
    ]&lt;/p&gt;

&lt;p&gt;Output...&lt;br/&gt;
    [&lt;br/&gt;
	&lt;/p&gt;
{
		&quot;foo&quot;: [ 1, 2, 3, 4 ],
		&quot;bar&quot;: [ &apos;a&apos;, &apos;b&apos;, &apos;c&apos; ]
	}
&lt;p&gt;,&lt;br/&gt;
	&lt;/p&gt;
{
		&quot;foo&quot;: [ 1, 2, 3, 4 ],
		&quot;bar&quot;: [ &apos;d&apos;, &apos;e&apos; ]
	}
&lt;p&gt;,&lt;br/&gt;
	&lt;/p&gt;
{
		&quot;foo&quot;: [ 1, 2, 3, 4 ],
		&quot;bar&quot;: [ &apos;f&apos; ]
	}
&lt;p&gt;,&lt;br/&gt;
	&lt;/p&gt;
{
		&quot;foo&quot;: [ 1, 2, 3, 4 ],
		&quot;bar&quot;: [ ]
	}
&lt;p&gt;,&lt;br/&gt;
    ]&lt;/p&gt;

&lt;p&gt;New syntax is &lt;span class=&quot;error&quot;&gt;&amp;#91;^&amp;#93;&lt;/span&gt; which means that this dimension is going to come from a parent array. A&lt;br/&gt;
valid syntax is now extended to be zero or more &lt;span class=&quot;error&quot;&gt;&amp;#91;^&amp;#93;&lt;/span&gt; followed by one or more &lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;. No alternating&lt;br/&gt;
of ^ and *.&lt;/p&gt;

&lt;p&gt;For inputs, the only acceptable syntax is &lt;span class=&quot;error&quot;&gt;&amp;#91;^&amp;#93;&lt;/span&gt;...&lt;span class=&quot;error&quot;&gt;&amp;#91;^&amp;#93;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;. For no other reason, this is just to be &lt;br/&gt;
consistent with the output usage. Syntax of &lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;...&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt; for two or more dimensions would be an &lt;br/&gt;
error.&lt;/p&gt;

&lt;p&gt;So if there are multiple dimensions of &lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt; in the output schema, then some kind of flattening&lt;br/&gt;
is happening. It normally would be &lt;span class=&quot;error&quot;&gt;&amp;#91;^&amp;#93;&lt;/span&gt;...&lt;span class=&quot;error&quot;&gt;&amp;#91;^&amp;#93;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt; for conventional usage.&lt;/p&gt;


&lt;p&gt;Algorithmic implication is that you don&apos;t know how many iterations there are without&lt;br/&gt;
recursing completely into your children. If their dimensionality is large enough, it&lt;br/&gt;
could reach back and affect your size.&lt;/p&gt;

&lt;p&gt;The fixed relationship between parent collection and expansion is just how it is. &lt;/p&gt;

&lt;p&gt;In today&apos;s Plastic, the logic looks for the immediate parent as the expansion point. If &lt;br/&gt;
you didn&apos;t like this simplification, say you wanted expansion to occur at a parent&apos;s parent,&lt;br/&gt;
then you needed to code.&lt;/p&gt;

&lt;p&gt;After this implementation, the logic will look up the parent stack to handle each dimension of the &lt;br/&gt;
iteration. If there are enough parents, then flattening occurs.&lt;/p&gt;

&lt;p&gt;If you don&apos;t like these simplifications, then you need to code.&lt;/p&gt;



&lt;p&gt;6B - Mixing Input Arrays into a Flattened Output Array&lt;br/&gt;
------------------------------------------------------&lt;/p&gt;

&lt;p&gt;What if I want to leverage the original arrays?&lt;/p&gt;

&lt;p&gt;Desired output...&lt;br/&gt;
    [&lt;br/&gt;
	&apos;1/a&apos;, &lt;br/&gt;
	&apos;1/b&apos;, &lt;br/&gt;
	&apos;1/c&apos;,&lt;br/&gt;
	&apos;2/d&apos;, &lt;br/&gt;
	&apos;2/e&apos;,&lt;br/&gt;
	&apos;3/f&apos;&lt;br/&gt;
    ]&lt;/p&gt;

&lt;p&gt;Output schema...&lt;br/&gt;
    [&lt;br/&gt;
	&quot;${id&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&quot;/&quot;${bbb&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&quot;&lt;br/&gt;
    ]&lt;/p&gt;

&lt;p&gt;This is a flattening because of &lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;. That dimension wins out so the flattening is 2 dimensional.&lt;br/&gt;
The iterators for id and bbb will be merged into a single iterator. The first &lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt; will have a range of &lt;br/&gt;
the larger of id and bbb. Then second &lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt; will have the range of the second dimension from bbb. This&lt;br/&gt;
means that the leftmost &lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt; in both iterators really need to have the same range to avoid issues.&lt;/p&gt;

&lt;p&gt;Note that i=(4) and bbb=(4,3) and there are no entries for bbb&lt;span class=&quot;error&quot;&gt;&amp;#91;3&amp;#93;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt; so the only choice is to error&lt;br/&gt;
out or to skip that expansion. If there are default values associated with id and/or bbb, they can&lt;br/&gt;
be used to fill in holes. If not, then it should be an error. This is a mixed hole because it takes&lt;br/&gt;
values from two variables to create a single output value. Had the output value just been from a single&lt;br/&gt;
variable, then this would have been a simple hole and skipped.&lt;/p&gt;


&lt;p&gt;Rule: holes in simple output values will be skipped in interations, unless there is a default value, &lt;br/&gt;
but holes in mixed output values result in an error.&lt;/p&gt;

&lt;p&gt;Had the output schema been...&lt;br/&gt;
    [&lt;br/&gt;
	&quot;${id&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&quot;/&quot;${bbb&lt;span class=&quot;error&quot;&gt;&amp;#91;^&amp;#93;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&quot;&lt;br/&gt;
    ]&lt;/p&gt;

&lt;p&gt;then it would have been an error because there is no parent array to supply the missing dimension.&lt;/p&gt;


&lt;p&gt;Rule: using ^ and not having a parent array to supply the missing dimension is an error.&lt;/p&gt;



&lt;p&gt;6C - Naive Isomorphic Conversion&lt;br/&gt;
--------------------------------&lt;/p&gt;

&lt;p&gt;Output schema...&lt;br/&gt;
    {&lt;br/&gt;
	&quot;AAA&quot;: [&lt;br/&gt;
	    {&lt;br/&gt;
		&quot;ID&quot;: &quot;${id&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;},&lt;br/&gt;
	        &quot;BBB&quot;: [&lt;br/&gt;
		    &quot;${bbb&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&quot;&lt;br/&gt;
		]&lt;br/&gt;
            }&lt;br/&gt;
	]&lt;br/&gt;
    }&lt;/p&gt;

&lt;p&gt;Output...&lt;br/&gt;
    {&lt;br/&gt;
	&quot;aaa&quot;: [ &lt;br/&gt;
	    &lt;/p&gt;
{
		&quot;id&quot;: &quot;1&quot;,
	        &quot;bbb&quot;: [ &apos;a&apos;, &apos;b&apos;, &apos;c&apos;, &apos;d&apos;, &apos;e&apos;, &apos;f&apos; ]
            }
&lt;p&gt;,&lt;br/&gt;
	    &lt;/p&gt;
{
		&quot;id&quot;: &quot;2&quot;,
	        &quot;bbb&quot;: [ &apos;a&apos;, &apos;b&apos;, &apos;c&apos;, &apos;d&apos;, &apos;e&apos;, &apos;f&apos; ]
            }
&lt;p&gt;,&lt;/p&gt;
	    {
		&quot;id&quot;: &quot;3&quot;,
	        &quot;bbb&quot;: [ &apos;a&apos;, &apos;b&apos;, &apos;c&apos;, &apos;d&apos;, &apos;e&apos;, &apos;f&apos; ]
            }
            {
		&quot;id&quot;: &quot;4&quot;,
	        &quot;bbb&quot;: [ &apos;a&apos;, &apos;b&apos;, &apos;c&apos;, &apos;d&apos;, &apos;e&apos;, &apos;f&apos; ]
            }
&lt;p&gt;	]&lt;br/&gt;
    }&lt;/p&gt;

&lt;p&gt;6D - Isomorphic Conversion (as a sanity check)&lt;br/&gt;
-----------------------------------------------------&lt;/p&gt;

&lt;p&gt;Output schema...&lt;br/&gt;
    {&lt;br/&gt;
	&quot;AAA&quot;: [&lt;br/&gt;
	    {&lt;br/&gt;
		&quot;ID&quot;: &quot;${id&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;},&lt;br/&gt;
	        &quot;BBB&quot;: [&lt;br/&gt;
		    &quot;${bbb&lt;span class=&quot;error&quot;&gt;&amp;#91;^&amp;#93;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;*&amp;#93;&lt;/span&gt;}&quot;&lt;br/&gt;
		],&lt;br/&gt;
            }&lt;br/&gt;
	]&lt;br/&gt;
    }&lt;br/&gt;
Output...&lt;br/&gt;
    {&lt;br/&gt;
	&quot;aaa&quot;: [ &lt;br/&gt;
	    &lt;/p&gt;
{
		&quot;id&quot;: &quot;1&quot;,
	        &quot;bbb&quot;: [ &apos;a&apos;, &apos;b&apos;, &apos;c&apos; ]
            }
&lt;p&gt;,&lt;br/&gt;
	    &lt;/p&gt;
{
		&quot;id&quot;: &quot;2&quot;,
	        &quot;bbb&quot;: [ &apos;d&apos;, &apos;e&apos; ]
            }
&lt;p&gt;,&lt;/p&gt;
	    {
		&quot;id&quot;: &quot;3&quot;,
	        &quot;bbb&quot;: [ &apos;f&apos; ]
            }
            {
		&quot;id&quot;: &quot;4&quot;,
	        &quot;bbb&quot;: [ ]
            }
&lt;p&gt;	]&lt;br/&gt;
    }&lt;/p&gt;

&lt;p&gt;Design Notes&lt;br/&gt;
------------&lt;/p&gt;

&lt;p&gt;MoArray logic &lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;will need to create iterator&lt;/li&gt;
	&lt;li&gt;dump an array for debug including iterator&lt;/li&gt;
	&lt;li&gt;copy iterator from one array to another&lt;/li&gt;
	&lt;li&gt;Need way to create missing iterator for legacy morpher logic&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Reserve for internal use variable names with&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;leading: _&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Illegal variable names&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;containing: . [ ] * ~ ^ ? {} &amp;amp; | ( ) @&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Iterator is special attribute &quot;_&lt;span class=&quot;error&quot;&gt;&amp;#91;name&amp;#93;&lt;/span&gt;&quot; and is an array of int[]&lt;br/&gt;
Error if dimensionality of variable is not equal to the dimensionality of the bound values&lt;/p&gt;

&lt;p&gt;Iterator (excluding empty iterator) has&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;one or more names&lt;/li&gt;
	&lt;li&gt;one or more dimensions&lt;/li&gt;
	&lt;li&gt;each dimension has a range 0 ... L-1&lt;/li&gt;
	&lt;li&gt;merging where larger ranges and bigger dimensions win&lt;/li&gt;
	&lt;li&gt;incrementable with a current value&lt;/li&gt;
	&lt;li&gt;incrementing only applies to non-parent dimensions&lt;/li&gt;
	&lt;li&gt;a concept of &quot;is done&quot;, which needs to be checked FIRST to allow for zero length arrays&lt;/li&gt;
	&lt;li&gt;&quot;is done&quot; only applies to non-parent dimension&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Algorithm&lt;br/&gt;
---------&lt;/p&gt;

&lt;p&gt;Recurse through schema&lt;br/&gt;
When you hit an array then push onto parent stack with empty iterator&lt;br/&gt;
Recurse through nearby children and collect iterators specifications (don&apos;t drill into arrays)&lt;br/&gt;
For each iterator specification&lt;br/&gt;
  if input schema then&lt;br/&gt;
    validate iterator syntax&lt;br/&gt;
    create iterator&lt;br/&gt;
  if output schema then&lt;br/&gt;
    validate iterator syntax&lt;br/&gt;
    validate the iterator is bound&lt;br/&gt;
    valid dimensions of bound values matches specification&lt;br/&gt;
  if iterator has parent references then&lt;br/&gt;
    link all parent references up the iterator inheritance chain&lt;br/&gt;
  impose/merge iterator on TOS&lt;/p&gt;

&lt;p&gt;loop if iteration is not done then&lt;br/&gt;
  increment iterator&lt;br/&gt;
  clone&lt;br/&gt;
  walk cloned output&lt;br/&gt;
  if hit array, recurse and push&lt;br/&gt;
  when resolving arrayed variable, need to look up stack of pushed iterators for resolution&lt;/p&gt;


&lt;p&gt;QUESTIONS&lt;/p&gt;

&lt;p&gt;All ^^^^^ should be semantically valid? &lt;br/&gt;
JW TMO example&lt;/p&gt;</comment>
                    </comments>
                    <attachments>
                    </attachments>
                <subtasks>
                    </subtasks>
                <customfields>
                                                <customfield id="customfield_11400" key="com.atlassian.jira.plugins.jira-development-integration-plugin:devsummary">
                        <customfieldname>Development</customfieldname>
                        <customfieldvalues>
                            
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    <customfield id="customfield_10000" key="com.pyxis.greenhopper.jira:gh-lexo-rank">
                        <customfieldname>Rank</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>0|i03qy7:</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                    </customfields>
    </item>
</channel>
</rss>