Browse Source

Merge branch 'candidate-7.4.x'

Signed-off-by: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 5 years ago
parent
commit
c5b70455e1
34 changed files with 1026 additions and 822 deletions
  1. 2 0
      common/thorhelper/thorcommon.cpp
  2. 1 1
      common/thorhelper/thorsoapcall.cpp
  3. 1 1
      dali/sasha/saxref.cpp
  4. 2 7
      docs/EN_US/ConfiguringHPCC/ConfiguringHPCC.xml
  5. 111 0
      docs/EN_US/ECLLanguageReference/ECLR_mods/SpecStruc-BeginC++.xml
  6. 30 12
      docs/EN_US/HPCCSystemAdmin/HPCCSystemAdministratorsGuide.xml
  7. BIN
      docs/EN_US/images/ImageSource/SA004.snag
  8. BIN
      docs/EN_US/images/SA004.jpg
  9. BIN
      docs/EN_US/images/gs-ht02.jpg
  10. 3 0
      ecl/hql/hqlexpr.cpp
  11. 10 0
      ecl/hql/hqlgram2.cpp
  12. 5 5
      ecl/hql/hqlutil.cpp
  13. 1 1
      ecl/hqlcpp/hqlttcpp.cpp
  14. 4 0
      ecl/hthor/hthorkey.cpp
  15. 40 73
      esp/src/eclwatch/HexViewWidget.js
  16. 7 7
      esp/src/eclwatch/templates/DFUQueryWidget.html
  17. 74 77
      esp/src/eclwatch/templates/DFUSearchWidget.html
  18. 2 2
      esp/src/eclwatch/templates/HPCCPlatformWidget.html
  19. 4 4
      esp/src/eclwatch/templates/LFDetailsWidget.html
  20. 1 2
      esp/src/eclwatch/templates/LogVisualizationWidget.html
  21. 2 2
      esp/src/eclwatch/templates/UserQueryWidget.html
  22. 39 39
      esp/src/eclwatch/templates/WUDetailsWidget.html
  23. 1 1
      esp/src/lws.config.js
  24. 611 560
      esp/src/package-lock.json
  25. 9 10
      esp/src/package.json
  26. 3 0
      initfiles/componentfiles/configschema/xsd/roxie.xsd
  27. 7 0
      initfiles/componentfiles/configxml/roxie.xsd.in
  28. 1 0
      roxie/ccd/ccd.hpp
  29. 4 1
      roxie/ccd/ccdfile.cpp
  30. 2 0
      roxie/ccd/ccdmain.cpp
  31. 41 12
      rtl/eclrtl/rtldynfield.cpp
  32. 5 4
      thorlcr/activities/keyedjoin/thkeyedjoinslave.cpp
  33. 1 1
      thorlcr/activities/soapcall/thsoapcallslave.cpp
  34. 2 0
      thorlcr/slave/slavmain.cpp

+ 2 - 0
common/thorhelper/thorcommon.cpp

@@ -2089,6 +2089,8 @@ static bool getTranslators(Owned<const IDynamicTransform> &translator, Owned<con
         if ((projectedFormat != sourceFormat) && (projectedCrc != sourceCrc))
         if ((projectedFormat != sourceFormat) && (projectedCrc != sourceCrc))
         {
         {
             translator.setown(createRecordTranslator(projectedFormat->queryRecordAccessor(true), sourceFormat->queryRecordAccessor(true)));
             translator.setown(createRecordTranslator(projectedFormat->queryRecordAccessor(true), sourceFormat->queryRecordAccessor(true)));
+            DBGLOG("Record layout translator created for %s", tracing);
+            translator->describe();
 
 
             if (!translator->canTranslate())
             if (!translator->canTranslate())
                 throw MakeStringException(0, "Untranslatable record layout mismatch detected for file %s", tracing);
                 throw MakeStringException(0, "Untranslatable record layout mismatch detected for file %s", tracing);

+ 1 - 1
common/thorhelper/thorsoapcall.cpp

@@ -1568,7 +1568,7 @@ private:
             if (url.userPasswordPair.length() > 0)
             if (url.userPasswordPair.length() > 0)
             {
             {
                 StringBuffer authToken;
                 StringBuffer authToken;
-                JBASE64_Encode(url.userPasswordPair.str(), url.userPasswordPair.length(), authToken);
+                JBASE64_Encode(url.userPasswordPair.str(), url.userPasswordPair.length(), authToken, false);
                 request.append("Authorization: Basic ").append(authToken).append("\r\n");
                 request.append("Authorization: Basic ").append(authToken).append("\r\n");
             }
             }
             else if (master->authToken.length() > 0)
             else if (master->authToken.length() > 0)

+ 1 - 1
dali/sasha/saxref.cpp

@@ -1400,7 +1400,7 @@ public:
                         dt->addProp("MinIP",s1.str());
                         dt->addProp("MinIP",s1.str());
                     }
                     }
                     if (d->minsize[drv]<d->maxsize[drv]) {
                     if (d->minsize[drv]<d->maxsize[drv]) {
-                        __int64 av = d->totalsize[drv]/(__int64)grp->ordinality();
+                        __int64 av = d->totalsize[drv]/(__int64)rawgrp->ordinality();
                         if (av) {
                         if (av) {
                             unsigned pcp = (unsigned)(d->maxsize[drv]*100/av);
                             unsigned pcp = (unsigned)(d->maxsize[drv]*100/av);
                             unsigned pcn = (unsigned)(d->minsize[drv]*100/av);
                             unsigned pcn = (unsigned)(d->minsize[drv]*100/av);

+ 2 - 7
docs/EN_US/ConfiguringHPCC/ConfiguringHPCC.xml

@@ -1696,6 +1696,8 @@ sudo -u hpcc cp /etc/HPCCSystems/source/NewEnvironment.xml /etc/HPCCSystems/envi
                         xmlns:xi="http://www.w3.org/2001/XInclude" />
                         xmlns:xi="http://www.w3.org/2001/XInclude" />
           </para>
           </para>
 
 
+          <?hard-pagebreak ?>
+
           <para>Additional information about the available Authentication
           <para>Additional information about the available Authentication
           methods:</para>
           methods:</para>
 
 
@@ -1714,13 +1716,6 @@ sudo -u hpcc cp /etc/HPCCSystems/source/NewEnvironment.xml /etc/HPCCSystems/envi
                   </row>
                   </row>
 
 
                   <row>
                   <row>
-                    <entry>local</entry>
-
-                    <entry>uses the local credentials for the server running
-                    the ESP</entry>
-                  </row>
-
-                  <row>
                     <entry>ldap</entry>
                     <entry>ldap</entry>
 
 
                     <entry>uses Lightweight Directory Access Protocol for
                     <entry>uses Lightweight Directory Access Protocol for

+ 111 - 0
docs/EN_US/ECLLanguageReference/ECLR_mods/SpecStruc-BeginC++.xml

@@ -192,6 +192,117 @@ ENDC++;
 isUpper('JIM');
 isUpper('JIM');
 
 
 </programlisting>
 </programlisting>
+
+    <para>Parameters can also include streamed datasets. </para>
+
+    <para>If stream is specified on the dataset then the parameter is passed
+    as an IRowStream. The next row from the dataset is obtained by
+    calling:</para>
+
+    <para><programlisting>dataset-&gt;nextRow(); </programlisting></para>
+
+    <para>After it has been processed the row must be freed by calling </para>
+
+    <para><programlisting>rtlReleaseRow(next); </programlisting></para>
+
+    <para>For example: </para>
+
+    <para><programlisting>traceDataset(STREAMED DATASET(r) ds, BOOLEAN isLocal = FALSE) := EMBED(C++)
+#include &lt;stdio.h&gt;
+#body
+  for(;;)
+  {
+    const byte * next = (const byte *)ds-&gt;nextRow();
+    if (!next)
+      return;
+    unsigned __int64 id = *(__uint64 *)(next);
+    size32_t lenName = *(size32_t *)(next + sizeof(__uint64));
+    const char * name = (char *)(next + sizeof(__uint64) + sizeof(size32_t));
+    printf("id(%u) name(%.*s)\n", (unsigned)id, lenName, name);
+    rtlReleaseRow(next);
+  }
+ENDEMBED;</programlisting></para>
+
+    <para>If the result of a c++ function is a streamed dataset, then it needs
+    to return an instance of an IRowStream interface. The function will also
+    be passed an extra implicit parameter:</para>
+
+    <para><programlisting>IEngineRowAllocator * _resultAllocator</programlisting></para>
+
+    <para>which is used to allocate the rows that are returned from the
+    function. </para>
+
+    <para>For example:</para>
+
+    <para><programlisting>// This function takes two streamed inputs and outputs the result of two values 
+// from the left multiplied together and added to a row from the right.
+
+STREAMED DATASET(r) myDataset(STREAMED DATASET(r) ds1, STREAMED DATASET(r) ds2)
+  := EMBED(C++ : activity)
+#include &lt;stdio.h&gt;
+#body
+    class MyStreamInlineDataset : public RtlCInterface, implements IRowStream
+    {
+    public:
+
+        MyStreamInlineDataset(IEngineRowAllocator * _resultAllocator, IRowStream * _ds1, 
+                              IRowStream * _ds2)
+          : resultAllocator(_resultAllocator), ds1(_ds1), ds2(_ds2)
+        {
+        }
+        RTLIMPLEMENT_IINTERFACE        virtual const void *nextRow() override
+        {
+            const byte * next1a = (const byte *)ds1-&gt;nextRow();
+            if (!next1a)
+                return nullptr;
+            const byte * next1b = (const byte *)ds1-&gt;nextRow();
+            const byte * next2 = (const byte *)ds2-&gt;nextRow();
+            if (!next1b || !next2)
+                rtlFailUnexpected();
+            unsigned __int64 value1a = *(const unsigned __int64 *)next1a;
+            unsigned __int64 value1b = *(const unsigned __int64 *)next1b;
+            unsigned __int64 value2 = *(const unsigned __int64 *)next2;
+            rtlReleaseRow(next1a);
+            rtlReleaseRow(next1b);
+            rtlReleaseRow(next2);
+            
+            unsigned __int64 result = value1a * value1b + value2;
+            RtlDynamicRowBuilder rowBuilder(resultAllocator);
+            byte * row = rowBuilder.getSelf();
+            *(__uint64 *)(row) = result;
+            return rowBuilder.finalizeRowClear(sizeof(unsigned __int64));
+        }
+        virtual void stop() override
+        {
+            ds1-&gt;stop();
+            ds2-&gt;stop();
+        }
+    protected:
+        Linked&lt;IEngineRowAllocator&gt; resultAllocator;
+        IRowStream * ds1;
+        IRowStream * ds2;
+    };    return new MyStreamInlineDataset(_resultAllocator, ds1, ds2);
+ENDEMBED;
+</programlisting></para>
+
+    <para>Note: If the resulting row does not have a fixed size, you should
+    call: </para>
+
+    <para><programlisting>byte * row = rowBuilder.ensureCapacity(&lt;totalSize&gt;, nullptr); </programlisting></para>
+
+    <para>instead of: </para>
+
+    <para><programlisting>byte * row = rowBuilder.getSelf(); </programlisting></para>
+
+    <para>This code uses a RtlDynamicRowBuilder which is a class used by the
+    code generator. Instead of using the RtlDynamicRowBuilder class, you could
+    directly call resultAllocator-&gt;createRow().</para>
+
+    <para>When a data type is included in an input row, rather than being
+    passed as a parameter, the format is the same as the parameters, except
+    that instead of having a pointer to the string etc., the string follows
+    the 4-byte length. The data in the row is not aligned; that is, it has
+    packing of 1. </para>
   </sect2>
   </sect2>
 
 
   <sect2 id="BeginCPP_Available_Options">
   <sect2 id="BeginCPP_Available_Options">

+ 30 - 12
docs/EN_US/HPCCSystemAdmin/HPCCSystemAdministratorsGuide.xml

@@ -39,7 +39,7 @@
       similarity to actual persons, living or dead, is purely
       similarity to actual persons, living or dead, is purely
       coincidental.</para>
       coincidental.</para>
 
 
-      <para />
+      <para></para>
     </legalnotice>
     </legalnotice>
 
 
     <xi:include href="common/Version.xml"
     <xi:include href="common/Version.xml"
@@ -268,7 +268,7 @@
           <para>ECLCC Server uses a queue to convert workunits one at a time,
           <para>ECLCC Server uses a queue to convert workunits one at a time,
           however you can have ECLCC Servers deployed in the system to
           however you can have ECLCC Servers deployed in the system to
           increase throughput and they will automatically load balance as
           increase throughput and they will automatically load balance as
-          required.</para>
+          required. </para>
         </sect3>
         </sect3>
 
 
         <sect3 id="SysAdm_ECLAgent">
         <sect3 id="SysAdm_ECLAgent">
@@ -282,6 +282,17 @@
           spawned on-demand when you submit a workunit.</para>
           spawned on-demand when you submit a workunit.</para>
         </sect3>
         </sect3>
 
 
+        <sect3 id="ECLScheduler">
+          <title>ECL Scheduler</title>
+
+          <para>The ECL Scheduler provides a means of automating processes
+          within ECL code or to chain processes together to work in sequence.
+          ECL Scheduling is event-based. The ECL Scheduler monitors a Schedule
+          list containing registered Workunits and Events and executes any
+          Workunits associated with an Event when that Event is triggered.
+          </para>
+        </sect3>
+
         <sect3 id="SysAdm_ESPServer">
         <sect3 id="SysAdm_ESPServer">
           <title>ESP Server</title>
           <title>ESP Server</title>
 
 
@@ -1115,7 +1126,8 @@
     desired you can edit the environment files using any xml or text editor
     desired you can edit the environment files using any xml or text editor
     however the file structure must remain valid.</para>
     however the file structure must remain valid.</para>
 
 
-    <para><figure>
+    <para>
+      <figure>
         <title>Sample Production Configuration</title>
         <title>Sample Production Configuration</title>
 
 
         <mediaobject>
         <mediaobject>
@@ -1123,7 +1135,8 @@
             <imagedata fileref="images/SA008.jpg" />
             <imagedata fileref="images/SA008.jpg" />
           </imageobject>
           </imageobject>
         </mediaobject>
         </mediaobject>
-      </figure></para>
+      </figure>
+    </para>
 
 
     <!--/*Including special SysAdmin Config Module -paras- */-->
     <!--/*Including special SysAdmin Config Module -paras- */-->
 
 
@@ -1169,7 +1182,9 @@
 
 
             <tbody>
             <tbody>
               <row>
               <row>
-                <entry><inlinegraphic fileref="images/caution.png" /></entry>
+                <entry>
+                  <inlinegraphic fileref="images/caution.png" />
+                </entry>
 
 
                 <entry><emphasis role="bold">WARNING</emphasis>: These
                 <entry><emphasis role="bold">WARNING</emphasis>: These
                 settings are essential to proper system operation. Only expert
                 settings are essential to proper system operation. Only expert
@@ -1199,7 +1214,8 @@
 
 
       <para>The default envrionment.conf:</para>
       <para>The default envrionment.conf:</para>
 
 
-      <para><programlisting>## Default environment configuration file for OpenHPCC
+      <para>
+        <programlisting>## Default environment configuration file for OpenHPCC
 
 
 [DEFAULT]
 [DEFAULT]
 configs=/etc/HPCCSystems
 configs=/etc/HPCCSystems
@@ -1276,7 +1292,8 @@ useDropZoneRestriction=true
 # NB: for now this only applies to the last cached server 
 # NB: for now this only applies to the last cached server 
 #dafsConnectFailRetrySeconds=10
 #dafsConnectFailRetrySeconds=10
 
 
-</programlisting></para>
+</programlisting>
+      </para>
 
 
       <para>The default environment.conf file includes several comments and
       <para>The default environment.conf file includes several comments and
       explanations for many of the values defined in it.</para>
       explanations for many of the values defined in it.</para>
@@ -1311,7 +1328,7 @@ lock=/var/lock/HPCCSystems</programlisting>
           <para>The <emphasis role="bold">logfields</emphasis> setting
           <para>The <emphasis role="bold">logfields</emphasis> setting
           declares the fields to include in the component logs. You can
           declares the fields to include in the component logs. You can
           customize which fields appear in your logs based on your business
           customize which fields appear in your logs based on your business
-          needs. </para>
+          needs.</para>
 
 
           <para>The syntax to use for logfields is to include the desired
           <para>The syntax to use for logfields is to include the desired
           columns with a plus (+) sign, and use the minus (-) to specify any
           columns with a plus (+) sign, and use the minus (-) to specify any
@@ -1446,7 +1463,8 @@ lock=/var/lock/HPCCSystems</programlisting>
           <para>The following are logfield macros which provide a bundled
           <para>The following are logfield macros which provide a bundled
           group of columns:</para>
           group of columns:</para>
 
 
-          <para><informaltable>
+          <para>
+            <informaltable>
               <tgroup cols="2">
               <tgroup cols="2">
                 <tbody>
                 <tbody>
                   <row>
                   <row>
@@ -1463,7 +1481,8 @@ lock=/var/lock/HPCCSystems</programlisting>
                   </row>
                   </row>
                 </tbody>
                 </tbody>
               </tgroup>
               </tgroup>
-            </informaltable></para>
+            </informaltable>
+          </para>
         </sect3>
         </sect3>
       </sect2>
       </sect2>
 
 
@@ -1734,8 +1753,7 @@ dfsSSLPrivateKeyFile=/keyfilepath/keyfile</programlisting>Set the <emphasis
     <xi:include href="HPCCSystemAdmin/SA-Mods/WUTool.xml"
     <xi:include href="HPCCSystemAdmin/SA-Mods/WUTool.xml"
                 xpointer="xpointer(//*[@id='wutool'])"
                 xpointer="xpointer(//*[@id='wutool'])"
                 xmlns:xi="http://www.w3.org/2001/XInclude" />
                 xmlns:xi="http://www.w3.org/2001/XInclude" />
-				
-				
+
     <sect1 id="Redefining_Thor_Nodes">
     <sect1 id="Redefining_Thor_Nodes">
       <title>Redefining nodes in a Thor Cluster</title>
       <title>Redefining nodes in a Thor Cluster</title>
 
 

BIN
docs/EN_US/images/ImageSource/SA004.snag


BIN
docs/EN_US/images/SA004.jpg


BIN
docs/EN_US/images/gs-ht02.jpg


+ 3 - 0
ecl/hql/hqlexpr.cpp

@@ -4663,6 +4663,9 @@ switch (op)
     case no_countdict:
     case no_countdict:
         assertex(queryChild(0)->isDictionary());
         assertex(queryChild(0)->isDictionary());
         break;
         break;
+    case no_newusertable:
+        assertex(queryChild(2)->getOperator() == no_newtransform);
+        break;
     }
     }
 
 
 #ifdef _DEBUG
 #ifdef _DEBUG

+ 10 - 0
ecl/hql/hqlgram2.cpp

@@ -7115,7 +7115,17 @@ IHqlExpression * HqlGram::createBuildIndexFromIndex(attribute & indexAttr, attri
     }
     }
 
 
     if (sourceDataset)
     if (sourceDataset)
+    {
         transform.setown(createDefaultAssignTransform(record, sourceDataset->queryNormalizedSelector(), indexAttr));
         transform.setown(createDefaultAssignTransform(record, sourceDataset->queryNormalizedSelector(), indexAttr));
+        //The transform operator must be changed to no_newtransform since it will be an argument to no_newusertable
+        if (transform->getOperator() == no_transform)
+        {
+            HqlExprArray args;
+            unwindChildren(args, transform);
+            OwnedHqlExpr newTransform = createValue(no_newtransform, transform->getType(), args);
+            transform.swap(newTransform);
+        }
+    }
 
 
     //need to tag record scope in this case so it generates no_activetable as top selector
     //need to tag record scope in this case so it generates no_activetable as top selector
     OwnedHqlExpr distribution, hash;
     OwnedHqlExpr distribution, hash;

+ 5 - 5
ecl/hql/hqlutil.cpp

@@ -4005,13 +4005,13 @@ IHqlExpression * convertRecordToTransform(IHqlExpression * record, bool canOmit)
 }
 }
 
 
 
 
-IHqlExpression * createTransformForField(IHqlExpression * field, IHqlExpression * value)
+IHqlExpression * createTransformForField(node_operator op, IHqlExpression * field, IHqlExpression * value)
 {
 {
     OwnedHqlExpr record = createRecord(field);
     OwnedHqlExpr record = createRecord(field);
     OwnedHqlExpr self = getSelf(record);
     OwnedHqlExpr self = getSelf(record);
     OwnedHqlExpr target = createSelectExpr(LINK(self), LINK(field));
     OwnedHqlExpr target = createSelectExpr(LINK(self), LINK(field));
     OwnedHqlExpr assign = createAssign(LINK(target), LINK(value));
     OwnedHqlExpr assign = createAssign(LINK(target), LINK(value));
-    return createValue(no_transform, makeTransformType(record->getType()), assign.getClear());
+    return createValue(op, makeTransformType(record->getType()), assign.getClear());
 }
 }
 
 
 IHqlExpression * convertScalarToRow(IHqlExpression * value, ITypeInfo * fieldType)
 IHqlExpression * convertScalarToRow(IHqlExpression * value, ITypeInfo * fieldType)
@@ -4025,12 +4025,12 @@ IHqlExpression * convertScalarToRow(IHqlExpression * value, ITypeInfo * fieldTyp
     OwnedHqlExpr attribute;
     OwnedHqlExpr attribute;
     if (splitResultValue(dataset, attribute, value))
     if (splitResultValue(dataset, attribute, value))
     {
     {
-        OwnedHqlExpr transform = createTransformForField(field, attribute);
+        OwnedHqlExpr transform = createTransformForField(no_newtransform, field, attribute);
         OwnedHqlExpr ds = createDataset(no_newusertable, LINK(dataset), createComma(LINK(record), LINK(transform)));
         OwnedHqlExpr ds = createDataset(no_newusertable, LINK(dataset), createComma(LINK(record), LINK(transform)));
         return createRow(no_selectnth, LINK(ds), getSizetConstant(1));
         return createRow(no_selectnth, LINK(ds), getSizetConstant(1));
     }
     }
 
 
-    OwnedHqlExpr transform = createTransformForField(field, value);
+    OwnedHqlExpr transform = createTransformForField(no_transform, field, value);
     return createRow(no_createrow, transform.getClear());
     return createRow(no_createrow, transform.getClear());
 }
 }
 
 
@@ -5775,7 +5775,7 @@ bool SplitDatasetAttributeTransformer::split(SharedHqlExpr & dataset, SharedHqlE
     case 2:
     case 2:
         {
         {
             OwnedHqlExpr field = createField(unnamedId, value->getType(), NULL);
             OwnedHqlExpr field = createField(unnamedId, value->getType(), NULL);
-            OwnedHqlExpr transform = createTransformForField(field, value);
+            OwnedHqlExpr transform = createTransformForField(no_transform, field, value);
             OwnedHqlExpr combine = createDatasetF(no_combine, LINK(&newDatasets.item(0)), LINK(&newDatasets.item(1)), LINK(transform), LINK(selSeq), NULL);
             OwnedHqlExpr combine = createDatasetF(no_combine, LINK(&newDatasets.item(0)), LINK(&newDatasets.item(1)), LINK(transform), LINK(selSeq), NULL);
             OwnedHqlExpr first = createRowF(no_selectnth, LINK(combine), getSizetConstant(1), createAttribute(noBoundCheckAtom), NULL);
             OwnedHqlExpr first = createRowF(no_selectnth, LINK(combine), getSizetConstant(1), createAttribute(noBoundCheckAtom), NULL);
             dataset.setown(createDatasetFromRow(first.getClear()));
             dataset.setown(createDatasetFromRow(first.getClear()));

+ 1 - 1
ecl/hqlcpp/hqlttcpp.cpp

@@ -9822,7 +9822,7 @@ IHqlExpression * HqlLinkedChildRowTransformer::ensureInputSerialized(IHqlExpress
     //so create a mapping <unserialized> := f(serialized)
     //so create a mapping <unserialized> := f(serialized)
     //and then use it to expand references to the unserialized format
     //and then use it to expand references to the unserialized format
     IHqlExpression * selector = dataset->queryNormalizedSelector();
     IHqlExpression * selector = dataset->queryNormalizedSelector();
-    OwnedHqlExpr mapTransform = createRecordMappingTransform(no_transform, serializedRecord, selector);
+    OwnedHqlExpr mapTransform = createRecordMappingTransform(no_newtransform, serializedRecord, selector);
     OwnedHqlExpr newDataset = createDatasetF(no_newusertable, LINK(dataset), LINK(serializedRecord), LINK(mapTransform), LINK(selSeq), NULL);
     OwnedHqlExpr newDataset = createDatasetF(no_newusertable, LINK(dataset), LINK(serializedRecord), LINK(mapTransform), LINK(selSeq), NULL);
 
 
     NewProjectMapper2 mapper;
     NewProjectMapper2 mapper;

+ 4 - 0
ecl/hthor/hthorkey.cpp

@@ -699,6 +699,8 @@ const IDynamicTransform * CHThorIndexReadActivityBase::getLayoutTranslator(IDist
 
 
             //MORE: We could introduce a more efficient way of checking this that does not create a translator
             //MORE: We could introduce a more efficient way of checking this that does not create a translator
             Owned<const IDynamicTransform> actualTranslator = createRecordTranslator(expectedFormat->queryRecordAccessor(true), actualFormat->queryRecordAccessor(true));
             Owned<const IDynamicTransform> actualTranslator = createRecordTranslator(expectedFormat->queryRecordAccessor(true), actualFormat->queryRecordAccessor(true));
+            DBGLOG("Record layout translator created for %s",  f->queryLogicalName());
+            actualTranslator->describe();
             if (actualTranslator->keyedTranslated())
             if (actualTranslator->keyedTranslated())
                 throw MakeStringException(0, "Untranslatable key layout mismatch reading index %s - keyed fields do not match", f->queryLogicalName());
                 throw MakeStringException(0, "Untranslatable key layout mismatch reading index %s - keyed fields do not match", f->queryLogicalName());
 
 
@@ -2540,6 +2542,8 @@ protected:
                 if (actualDiskMeta)
                 if (actualDiskMeta)
                 {
                 {
                     translator.setown(createRecordTranslator(helper.queryProjectedDiskRecordSize()->queryRecordAccessor(true), actualDiskMeta->queryRecordAccessor(true)));
                     translator.setown(createRecordTranslator(helper.queryProjectedDiskRecordSize()->queryRecordAccessor(true), actualDiskMeta->queryRecordAccessor(true)));
+                    DBGLOG("Record layout translator created for %s",  f->queryLogicalName());
+                    translator->describe();
                     if (translator->canTranslate())
                     if (translator->canTranslate())
                     {
                     {
                         if (getLayoutTranslationMode()==RecordTranslationMode::None)
                         if (getLayoutTranslationMode()==RecordTranslationMode::None)

+ 40 - 73
esp/src/eclwatch/HexViewWidget.js

@@ -4,26 +4,23 @@ define([
     "dojo/i18n",
     "dojo/i18n",
     "dojo/i18n!./nls/hpcc",
     "dojo/i18n!./nls/hpcc",
     "dojo/_base/array",
     "dojo/_base/array",
-    "dojo/store/Memory",
-    "dojo/store/Observable",
-    "dojo/request/iframe",
 
 
     "dijit/registry",
     "dijit/registry",
 
 
     "hpcc/_Widget",
     "hpcc/_Widget",
-    "src/ESPWorkunit",
-    "hpcc/ECLSourceWidget",
+    "@hpcc-js/comms",
 
 
     "dojo/text!../templates/HexViewWidget.html",
     "dojo/text!../templates/HexViewWidget.html",
 
 
+    "hpcc/ECLSourceWidget",
     "dijit/form/NumberSpinner",
     "dijit/form/NumberSpinner",
     "dijit/form/Button",
     "dijit/form/Button",
     "dijit/form/ToggleButton",
     "dijit/form/ToggleButton",
     "dijit/form/CheckBox"
     "dijit/form/CheckBox"
 ],
 ],
-    function (declare, lang, i18n, nlsHPCC, arrayUtil, Memory, Observable, iframe,
+    function (declare, lang, i18n, nlsHPCC, arrayUtil,
         registry,
         registry,
-        _Widget, ESPWorkunit, ECLSourceWidget,
+        _Widget, hpccComms,
         template) {
         template) {
         return declare("HexViewWidget", [_Widget], {
         return declare("HexViewWidget", [_Widget], {
             templateString: template,
             templateString: template,
@@ -87,74 +84,44 @@ define([
                     sourceMode: ""
                     sourceMode: ""
                 });
                 });
                 var context = this;
                 var context = this;
-                this.wu = ESPWorkunit.Create({
-                    onCreate: function () {
-                        context.wu.update({
-                            QueryText: context.getQuery()
-                        });
-                        context.watchWU();
-                    },
-                    onUpdate: function () {
-                        context.wu.submit();
-                    },
-                    onSubmit: function () {
-                    }
-                });
-            },
-
-            watchWU: function () {
-                if (this.watchHandle) {
-                    this.watchHandle.unwatch();
-                }
-                var context = this;
-                this.watchHandle = this.wu.watch(function (name, oldValue, newValue) {
-                    switch (name) {
-                        case "hasCompleted":
-                            if (newValue === true) {
-                                this.wu.getInfo({
-                                    onGetWUExceptions: function (exceptions) {
-                                        if (exceptions.length) {
-                                            var msg = "";
-                                            arrayUtil.forEach(exceptions, function (exception) {
-                                                if (exception.Severity === "Error") {
-                                                    if (msg) {
-                                                        msg += "\n";
-                                                    }
-                                                    msg += exception.Message;
-                                                }
-                                            });
-                                            if (msg) {
-                                                dojo.publish("hpcc/brToaster", {
-                                                    Severity: "Error",
-                                                    Source: "HexViewWidget.remoteRead",
-                                                    Exceptions: [{ Source: context.wu.Wuid, Message: msg }]
-                                                });
-                                            }
-                                        }
-                                    }
-                                });
-                                context.wu.fetchResults(function (results) {
-                                    context.cachedResponse = "";
-                                    arrayUtil.forEach(results, function (result, idx) {
-                                        var store = result.getStore();
-                                        var result = store.query({
-                                        }, {
-                                                start: 0,
-                                                count: context.bufferLength
-                                            }).then(function (response) {
-                                                context.watchHandle.unwatch();
-                                                context.cachedResponse = response;
-                                                context.displayHex();
-                                                context.wu.doDelete();
-                                            });
-                                    });
-                                });
+                this.wu = hpccComms.Workunit.submit({ baseUrl: "" }, "hthor", context.getQuery()).then(function (wu) {
+                    wu.on("changed", function () {
+                        if (!wu.isComplete()) {
+                            context.hexView.setText("..." + wu.State + "...");
+                        }
+                    });
+                    return wu.watchUntilComplete();
+                }).then(function (wu) {
+                    return wu.fetchECLExceptions().then(function () { return wu; });
+                }).then(function (wu) {
+                    var exceptions = wu.Exceptions && wu.Exceptions.ECLException ? wu.Exceptions.ECLException : [];
+                    if (exceptions.length) {
+                        var msg = "";
+                        arrayUtil.forEach(exceptions, function (exception) {
+                            if (exception.Severity === "Error") {
+                                if (msg) {
+                                    msg += "\n";
+                                }
+                                msg += exception.Message;
                             }
                             }
-                            break;
-                        case "State":
-                            context.hexView.setText("..." + (context.wu.isComplete() ? context.i18n.fetchingresults : newValue) + "...");
-                            break;
+                        });
+                        if (msg) {
+                            dojo.publish("hpcc/brToaster", {
+                                Severity: "Error",
+                                Source: "HexViewWidget.remoteRead",
+                                Exceptions: [{ Source: context.wu.Wuid, Message: msg }]
+                            });
+                        }
                     }
                     }
+                    return wu.fetchResults().then(function (results) {
+                        return results.length ? results[0].fetchRows() : [];
+                    }).then(function (rows) {
+                        context.cachedResponse = rows;
+                        context.displayHex();
+                        return wu;
+                    });
+                }).then(function (wu) {
+                    return wu.delete();
                 });
                 });
             },
             },
 
 

+ 7 - 7
esp/src/eclwatch/templates/DFUQueryWidget.html

@@ -35,7 +35,7 @@
                                         <input title="${i18n.NoSplit}:" name="nosplit" data-dojo-type="dijit.form.CheckBox" />
                                         <input title="${i18n.NoSplit}:" name="nosplit" data-dojo-type="dijit.form.CheckBox" />
                                         <input title="${i18n.Compress}:" name="compress" data-dojo-type="dijit.form.CheckBox" />
                                         <input title="${i18n.Compress}:" name="compress" data-dojo-type="dijit.form.CheckBox" />
                                         <input title="${i18n.Wrap}:" name="Wrap" data-dojo-type="dijit.form.CheckBox" />
                                         <input title="${i18n.Wrap}:" name="Wrap" data-dojo-type="dijit.form.CheckBox" />
-                                        <input id="${id}RemoteCopyReplicate"title="${i18n.Replicate}:" name="replicate" data-dojo-type="dijit.form.CheckBox" />
+                                        <input id="${id}RemoteCopyReplicate" title="${i18n.Replicate}:" name="replicate" data-dojo-type="dijit.form.CheckBox" />
                                         <input title="${i18n.RetainSuperfileStructure}:" name="superCopy" data-dojo-type="dijit.form.CheckBox" />
                                         <input title="${i18n.RetainSuperfileStructure}:" name="superCopy" data-dojo-type="dijit.form.CheckBox" />
                                     </div>
                                     </div>
                                 </div>
                                 </div>
@@ -53,7 +53,7 @@
                                 <div data-dojo-type="dijit.Fieldset">
                                 <div data-dojo-type="dijit.Fieldset">
                                     <legend>${i18n.Target}</legend>
                                     <legend>${i18n.Target}</legend>
                                     <div data-dojo-type="hpcc.TableContainer">
                                     <div data-dojo-type="hpcc.TableContainer">
-                                        <input id="${id}CopyTargetSelect" title="${i18n.Group}:" name="destGroup" style="width:100%;" data-dojo-type="TargetSelectWidget" style="display: inline-block; vertical-align: middle" />
+                                        <input id="${id}CopyTargetSelect" title="${i18n.Group}:" name="destGroup" style="width:100%;display: inline-block; vertical-align: middle" data-dojo-type="TargetSelectWidget" />
                                     </div>
                                     </div>
                                     <div id="${id}CopyGrid" data-dojo-type="SelectionGridWidget">
                                     <div id="${id}CopyGrid" data-dojo-type="SelectionGridWidget">
                                     </div>
                                     </div>
@@ -101,13 +101,13 @@
                     <div id="${id}AddtoDropDown" data-dojo-type="dijit.form.DropDownButton">
                     <div id="${id}AddtoDropDown" data-dojo-type="dijit.form.DropDownButton">
                         <span>${i18n.AddToSuperfile}</span>
                         <span>${i18n.AddToSuperfile}</span>
                         <div data-dojo-type="dijit.TooltipDialog">
                         <div data-dojo-type="dijit.TooltipDialog">
-                            <div id="${id}AddToSuperfileForm" style="width:680px" onsubmit="return false;" data-dojo-type="dijit.form.Form" >
+                            <div id="${id}AddToSuperfileForm" style="width:680px" onsubmit="return false;" data-dojo-type="dijit.form.Form">
                                 <div data-dojo-type="dijit.Fieldset">
                                 <div data-dojo-type="dijit.Fieldset">
                                     <legend>${i18n.Target}</legend>
                                     <legend>${i18n.Target}</legend>
                                     <div class="dijitDialogPaneContentArea" data-dojo-props="cols:2" data-dojo-type="hpcc.TableContainer">
                                     <div class="dijitDialogPaneContentArea" data-dojo-props="cols:2" data-dojo-type="hpcc.TableContainer">
-                                        <input id="${id}CreateNewSuperRadio" title="${i18n.CreateANewFile}" checked="true" data-dojo-type="dijit.form.RadioButton"></input>
+                                        <input id="${id}CreateNewSuperRadio" title="${i18n.CreateANewFile}" checked="true" data-dojo-type="dijit.form.RadioButton" />
                                         <input id="${id}AddToSuperfileTargetName" style="width:100%;" name="Superfile" required="true" data-dojo-props="trim: true" data-dojo-type="dijit.form.ValidationTextBox" />
                                         <input id="${id}AddToSuperfileTargetName" style="width:100%;" name="Superfile" required="true" data-dojo-props="trim: true" data-dojo-type="dijit.form.ValidationTextBox" />
-                                        <input id="${id}AddToSuperfileTargetAppend" name="ExistingFile" title="${i18n.AddToExistingSuperfile}" data-dojo-type="dijit.form.RadioButton"></input>
+                                        <input id="${id}AddToSuperfileTargetAppend" name="ExistingFile" title="${i18n.AddToExistingSuperfile}" data-dojo-type="dijit.form.RadioButton" />
                                     </div>
                                     </div>
                                     <div id="${id}AddToSuperfileGrid" data-dojo-type="SelectionGridWidget"></div>
                                     <div id="${id}AddToSuperfileGrid" data-dojo-type="SelectionGridWidget"></div>
                                 </div>
                                 </div>
@@ -177,10 +177,10 @@
                     <span data-dojo-type="dijit.ToolbarSeparator"></span>
                     <span data-dojo-type="dijit.ToolbarSeparator"></span>
                     <img src="${dojoConfig.urlInfo.resourcePath}/img/person.png" style="vertical-align: middle" alt="${i18n.Mine}">
                     <img src="${dojoConfig.urlInfo.resourcePath}/img/person.png" style="vertical-align: middle" alt="${i18n.Mine}">
                     <label for="Mine" class="bold" style="vertical-align: middle;">${i18n.Mine}</label>
                     <label for="Mine" class="bold" style="vertical-align: middle;">${i18n.Mine}</label>
-                    <input id="${id}Mine" name="Owner" title="${i18n.Mine}" data-dojo-attach-event="onChange:_onMine" data-dojo-type="dijit.form.CheckBox"/>
+                    <input id="${id}Mine" name="Owner" title="${i18n.Mine}" data-dojo-attach-event="onChange:_onMine" data-dojo-type="dijit.form.CheckBox" />
                     <div class="right" data-dojo-attach-event="onChange:_onMaximize" data-dojo-props="iconClass:'iconMaximize', showLabel:false" checked=false data-dojo-type="dijit.form.ToggleButton">${i18n.MaximizeRestore}</div>
                     <div class="right" data-dojo-attach-event="onChange:_onMaximize" data-dojo-props="iconClass:'iconMaximize', showLabel:false" checked=false data-dojo-type="dijit.form.ToggleButton">${i18n.MaximizeRestore}</div>
                     <div id="${id}NewPage" class="right" data-dojo-attach-event="onClick:_onNewPage" data-dojo-props="iconClass:'iconNewPage', showLabel:false" data-dojo-type="dijit.form.Button">${i18n.OpenInNewPage}</div>
                     <div id="${id}NewPage" class="right" data-dojo-attach-event="onClick:_onNewPage" data-dojo-props="iconClass:'iconNewPage', showLabel:false" data-dojo-type="dijit.form.Button">${i18n.OpenInNewPage}</div>
-                     <div id="${id}DownloadToList" class="right" data-dojo-attach-event="onClick:_onDownloadToList" data-dojo-type="dijit.form.Button">
+                    <div id="${id}DownloadToList" class="right" data-dojo-attach-event="onClick:_onDownloadToList" data-dojo-type="dijit.form.Button">
                         <span>${i18n.DownloadToCSV}</span>
                         <span>${i18n.DownloadToCSV}</span>
                     </div>
                     </div>
                 </div>
                 </div>

+ 74 - 77
esp/src/eclwatch/templates/DFUSearchWidget.html

@@ -2,82 +2,79 @@
     <div id="${id}BorderContainer" class="${baseClass}BorderContainer" style="width: 100%; height: 100%" data-dojo-type="dijit.layout.BorderContainer">
     <div id="${id}BorderContainer" class="${baseClass}BorderContainer" style="width: 100%; height: 100%" data-dojo-type="dijit.layout.BorderContainer">
         <div id="${id}ContentPane" data-dojo-props="region: 'center', tabPosition: 'top'" style="width: 100%; height: 100%" data-dojo-type="dijit.layout.ContentPane">
         <div id="${id}ContentPane" data-dojo-props="region: 'center', tabPosition: 'top'" style="width: 100%; height: 100%" data-dojo-type="dijit.layout.ContentPane">
             <div style="width: 100%; height: 100%" data-dojo-type="dijit.layout.BorderContainer">
             <div style="width: 100%; height: 100%" data-dojo-type="dijit.layout.BorderContainer">
-                <div data-dojo-props="region: 'center'" data-dojo-type="dijit.layout.ContentPane">                	                    
+                <div data-dojo-props="region: 'center'" data-dojo-type="dijit.layout.ContentPane">
                     <form>
                     <form>
-                    	<ul>
-                    		<li>
-		                    	<h2>Open DFU Workunit</h2>
-			                    <label for="WorkUnitId" class="Prompt">Workunit ID:</label>
-			                    <div><input name="FindDfuWu" type="text" data-dojo-type="dijit.form.TextBox" placeholder="enter workunit id"
-			                    data-dojo-props="trim:true, propercase:true"/>
-								</div>
-							</li>
-							<li>
-								<div>
-							<button data-dojo-type="dijit.form.Button" type="button">Load Below
-			                </button>
-			                	</div>
-			                </li>
-						</ul>	
-						<ul>
-							<li>			
-						<h2>Search DFU Workunits</h2>
-						<label for="Type" class="Prompt">Type:</label>
-						<div>
-							<select name="SelectType" data-dojo-type="dijit.form.Select">
-    							<option value="NA">Non&ndash;Archived Workunits</option>
-    							<option value="A" selected="Selected">Archived Workunits</option>    
-							</select>
-						</div>
-						</li>
-						<li>
-						<label for="Username" class="Prompt">Username:</label>
-						<div>
-							<input id="Username" data-dojo-type="dijit.form.TextBox" placeholder="enter username"
-                                data-dojo-props="trim:true, propercase:true">
-                        </div>
-                        </li>
-                        <li>
-                        <label for="Cluster" class="Prompt">Cluster:</label>
-                        <div>
-                        	<select name="SelectCluster" data-dojo-type="TargetSelectWidget">    								  
-							</select>
-						</div>
-						</li>
-						<li>
-						<label for="State" class="Prompt">State:</label>
-						<div>
-							<select name="SelectState" data-dojo-type="dijit.form.Select">
-	                            	<option>unknown</option>
-									<option>scheduled</option>
-									<option>compiled</option>
-									<option>running</option>
-									<option>finished</option>
-									<option>failed</option>
-									<option>aborting</option>
-									<option>aborted</option>
-									<option>blocked</option>
-									<option>monitoring</option>
-							</select>
-						</div>
-					</li>
-					<li>
-						<label for="Jobname" class="Prompt">Jobname:</label>
-						<div>
-							<input id="FindJobName" data-dojo-type="dijit.form.TextBox" placeholder="enter jobname"
-                                data-dojo-props="trim:true, propercase:true">
-                        </div>
-                    </li>
-                     <li>
-                        <div>
-                        	<button data-dojo-type="dijit.form.Button" type="button">Search
-                            </button>
-                        </div>
-                       </li>
-					</form>
-				</div>
-             	<div id="${id}InfoContainer" style="height: 35%" data-dojo-props="region: 'bottom', splitter: true, minSize: 120" data-dojo-type="InfoGridWidget">  </div>
-     		
+                        <ul>
+                            <li>
+                                <h2>Open DFU Workunit</h2>
+                                <label for="WorkUnitId" class="Prompt">Workunit ID:</label>
+                                <div><input name="FindDfuWu" type="text" data-dojo-type="dijit.form.TextBox" placeholder="enter workunit id" data-dojo-props="trim:true, propercase:true" />
+                                </div>
+                            </li>
+                            <li>
+                                <div>
+                                    <button data-dojo-type="dijit.form.Button" type="button">Load Below
+                                    </button>
+                                </div>
+                            </li>
+                        </ul>
+                        <ul>
+                            <li>
+                                <h2>Search DFU Workunits</h2>
+                                <label for="Type" class="Prompt">Type:</label>
+                                <div>
+                                    <select name="SelectType" data-dojo-type="dijit.form.Select">
+                                        <option value="NA">Non&ndash;Archived Workunits</option>
+                                        <option value="A" selected="Selected">Archived Workunits</option>
+                                    </select>
+                                </div>
+                            </li>
+                            <li>
+                                <label for="Username" class="Prompt">Username:</label>
+                                <div>
+                                    <input id="Username" data-dojo-type="dijit.form.TextBox" placeholder="enter username" data-dojo-props="trim:true, propercase:true">
+                                </div>
+                            </li>
+                            <li>
+                                <label for="Cluster" class="Prompt">Cluster:</label>
+                                <div>
+                                    <select name="SelectCluster" data-dojo-type="TargetSelectWidget">
+                                    </select>
+                                </div>
+                            </li>
+                            <li>
+                                <label for="State" class="Prompt">State:</label>
+                                <div>
+                                    <select name="SelectState" data-dojo-type="dijit.form.Select">
+                                        <option>unknown</option>
+                                        <option>scheduled</option>
+                                        <option>compiled</option>
+                                        <option>running</option>
+                                        <option>finished</option>
+                                        <option>failed</option>
+                                        <option>aborting</option>
+                                        <option>aborted</option>
+                                        <option>blocked</option>
+                                        <option>monitoring</option>
+                                    </select>
+                                </div>
+                            </li>
+                            <li>
+                                <label for="Jobname" class="Prompt">Jobname:</label>
+                                <div>
+                                    <input id="FindJobName" data-dojo-type="dijit.form.TextBox" placeholder="enter jobname" data-dojo-props="trim:true, propercase:true">
+                                </div>
+                            </li>
+                            <li>
+                                <div>
+                                    <button data-dojo-type="dijit.form.Button" type="button">Search</button>
+                                </div>
+                            </li>
+                        </ul>
+                    </form>
+                </div>
+                <div id="${id}InfoContainer" style="height: 35%" data-dojo-props="region: 'bottom', splitter: true, minSize: 120" data-dojo-type="InfoGridWidget"></div>
+            </div>
         </div>
         </div>
-	</div>
-</div>
+    </div>
+</div>

+ 2 - 2
esp/src/eclwatch/templates/HPCCPlatformWidget.html

@@ -12,10 +12,10 @@
                 </form>
                 </form>
                 <div class="seperator grey"></div>
                 <div class="seperator grey"></div>
                 <div id="userAccount">
                 <div id="userAccount">
-                    <span class="navBarLoggedin">${i18n.LoggedInAs}:  </span>
+                    <span class="navBarLoggedin">${i18n.LoggedInAs}: </span>
                     <a id="${id}UserID" href="#" data-dojo-attach-event="onClick:_onUserID"></a>
                     <a id="${id}UserID" href="#" data-dojo-attach-event="onClick:_onUserID"></a>
                     <span id="UserDivider"></span>
                     <span id="UserDivider"></span>
-                    <a id="Lock" href="#" data-dojo-attach-event="onClick:_onLock"/></a>
+                    <a id="Lock" href="#" data-dojo-attach-event="onClick:_onLock"></a>
                 </div>
                 </div>
                 <div class="seperator grey"></div>
                 <div class="seperator grey"></div>
                 <div id="${id}More" class="left glow" data-dojo-props="iconClass:'iconAdvanced', showLabel:false" data-dojo-type="dijit.form.DropDownButton">
                 <div id="${id}More" class="left glow" data-dojo-props="iconClass:'iconAdvanced', showLabel:false" data-dojo-type="dijit.form.DropDownButton">

+ 4 - 4
esp/src/eclwatch/templates/LFDetailsWidget.html

@@ -15,7 +15,7 @@
                                 <div data-dojo-type="dijit.Fieldset">
                                 <div data-dojo-type="dijit.Fieldset">
                                     <legend>${i18n.Target}</legend>
                                     <legend>${i18n.Target}</legend>
                                     <div data-dojo-props="cols:2" data-dojo-type="hpcc.TableContainer">
                                     <div data-dojo-props="cols:2" data-dojo-type="hpcc.TableContainer">
-                                        <input id="${id}CopyTargetSelect" title="${i18n.Group}:" name="destGroup" colspan="2" style="width:100%;" data-dojo-type="TargetSelectWidget" style="display: inline-block; vertical-align: middle" />
+                                        <input id="${id}CopyTargetSelect" title="${i18n.Group}:" name="destGroup" colspan="2" style="width:100%;display: inline-block; vertical-align: middle" data-dojo-type="TargetSelectWidget" />
                                         <input id="${id}CopyTargetName" title="${i18n.TargetName}:" name="destLogicalName" colspan="2" style="width:100%;" required="true" data-dojo-props="trim: true" data-dojo-type="dijit.form.ValidationTextBox" />
                                         <input id="${id}CopyTargetName" title="${i18n.TargetName}:" name="destLogicalName" colspan="2" style="width:100%;" required="true" data-dojo-props="trim: true" data-dojo-type="dijit.form.ValidationTextBox" />
                                     </div>
                                     </div>
                                 </div>
                                 </div>
@@ -29,7 +29,7 @@
                                         <input id="${id}CopyTargetWrap" title="${i18n.Wrap}:" name="Wrap" data-dojo-type="dijit.form.CheckBox" />
                                         <input id="${id}CopyTargetWrap" title="${i18n.Wrap}:" name="Wrap" data-dojo-type="dijit.form.CheckBox" />
                                         <input id="${id}CopyTargetRetainSuperfileStructure" title="${i18n.RetainSuperfileStructure}:" name="superCopy" data-dojo-type="dijit.form.CheckBox" />
                                         <input id="${id}CopyTargetRetainSuperfileStructure" title="${i18n.RetainSuperfileStructure}:" name="superCopy" data-dojo-type="dijit.form.CheckBox" />
                                         <input id="${id}CopyPreserveCompression" title="${i18n.PreserveCompression}:" checked="true" name="preserveCompression" data-dojo-type="dijit.form.CheckBox" />
                                         <input id="${id}CopyPreserveCompression" title="${i18n.PreserveCompression}:" checked="true" name="preserveCompression" data-dojo-type="dijit.form.CheckBox" />
-                                        <input id="${id}CopyExpireDays" title="${i18n.ExpireDays}:" name="ExpireDays" data-dojo-type="dijit.form.NumberTextBox", />
+                                        <input id="${id}CopyExpireDays" title="${i18n.ExpireDays}:" name="ExpireDays" data-dojo-type="dijit.form.NumberTextBox" />
                                     </div>
                                     </div>
                                 </div>
                                 </div>
                                 <div class="dijitDialogPaneActionBar">
                                 <div class="dijitDialogPaneActionBar">
@@ -112,7 +112,7 @@
                 </div>
                 </div>
                 <div data-dojo-props="region: 'center'" data-dojo-type="dijit.layout.ContentPane">
                 <div data-dojo-props="region: 'center'" data-dojo-type="dijit.layout.ContentPane">
                     <h2>
                     <h2>
-                        <img id="${id}CompressedImage"/>&nbsp;
+                        <img id="${id}CompressedImage" />&nbsp;
                         <img id="${id}ProtectedImage" src="${dojoConfig.urlInfo.resourcePath}/img/unlocked.png" />&nbsp;<img id="${id}StateIdImage" class="iconLogicalFile" />&nbsp;<span id="${id}Name" class="bold"></span>
                         <img id="${id}ProtectedImage" src="${dojoConfig.urlInfo.resourcePath}/img/unlocked.png" />&nbsp;<img id="${id}StateIdImage" class="iconLogicalFile" />&nbsp;<span id="${id}Name" class="bold"></span>
                         <button id="${id}ClippyButton" class="clippy" data-clipboard-target="#${id}Name"><img src="${dojoConfig.urlInfo.resourcePath}/img/clippy.png" alt="${i18n.CopyToClipboard}"></button>
                         <button id="${id}ClippyButton" class="clippy" data-clipboard-target="#${id}Name"><img src="${dojoConfig.urlInfo.resourcePath}/img/clippy.png" alt="${i18n.CopyToClipboard}"></button>
                     </h2>
                     </h2>
@@ -144,7 +144,7 @@
                             </li>
                             </li>
                             <li>
                             <li>
                                 <label class="Prompt" for="${id}isProtected">${i18n.Protected}:</label>
                                 <label class="Prompt" for="${id}isProtected">${i18n.Protected}:</label>
-                                <div><input id="${id}isProtected" data-dojo-type="dijit.form.CheckBox"/></div>
+                                <div><input id="${id}isProtected" data-dojo-type="dijit.form.CheckBox" /></div>
                             </li>
                             </li>
                             <li>
                             <li>
                                 <label for="${id}ContentType">${i18n.ContentType}: </label>
                                 <label for="${id}ContentType">${i18n.ContentType}: </label>

+ 1 - 2
esp/src/eclwatch/templates/LogVisualizationWidget.html

@@ -8,8 +8,7 @@
                     <div class="right" data-dojo-attach-event="onChange:_onMaximize" data-dojo-props="iconClass:'iconMaximize', showLabel:false" checked=false data-dojo-type="dijit.form.ToggleButton">${i18n.MaximizeRestore}</div>
                     <div class="right" data-dojo-attach-event="onChange:_onMaximize" data-dojo-props="iconClass:'iconMaximize', showLabel:false" checked=false data-dojo-type="dijit.form.ToggleButton">${i18n.MaximizeRestore}</div>
                     <div id="${id}NewPage" class="right" data-dojo-attach-event="onClick:_onNewPage" data-dojo-props="iconClass:'iconNewPage', showLabel:false" data-dojo-type="dijit.form.Button">${i18n.OpenInNewPage}</div>
                     <div id="${id}NewPage" class="right" data-dojo-attach-event="onClick:_onNewPage" data-dojo-props="iconClass:'iconNewPage', showLabel:false" data-dojo-type="dijit.form.Button">${i18n.OpenInNewPage}</div>
                 </div>
                 </div>
-                </div>
             </div>
             </div>
         </div>
         </div>
     </div>
     </div>
-</div>
+</div>

+ 2 - 2
esp/src/eclwatch/templates/UserQueryWidget.html

@@ -120,7 +120,7 @@
                     <div id="${id}AdvancedPermissions" data-dojo-type="dijit.form.DropDownButton">
                     <div id="${id}AdvancedPermissions" data-dojo-type="dijit.form.DropDownButton">
                         <span>${i18n.Advanced}</span>
                         <span>${i18n.Advanced}</span>
                         <div data-dojo-type="dijit.DropDownMenu">
                         <div data-dojo-type="dijit.DropDownMenu">
-                            <div data-dojo-attach-event="onClick:_onEnableScopeScans "id="${id}EnableScopeScans" data-dojo-type="dijit.MenuItem">${i18n.EnableScopeScans}</div>
+                            <div data-dojo-attach-event="onClick:_onEnableScopeScans" id="${id}EnableScopeScans" data-dojo-type="dijit.MenuItem">${i18n.EnableScopeScans}</div>
                             <div data-dojo-attach-event="onClick:_onDisableScopeScans" id="${id}DisableScopeScans" data-dojo-type="dijit.MenuItem">${i18n.DisableScopeScans}</div>
                             <div data-dojo-attach-event="onClick:_onDisableScopeScans" id="${id}DisableScopeScans" data-dojo-type="dijit.MenuItem">${i18n.DisableScopeScans}</div>
                             <span data-dojo-type="dijit.MenuSeparator"></span>
                             <span data-dojo-type="dijit.MenuSeparator"></span>
                             <div data-dojo-attach-event="onClick:_onFileScopeDefaultPermissions" id="${id}FileScopeDefaultPermissions" data-dojo-type="dijit.MenuItem">${i18n.FileScopeDefaultPermissions}</div>
                             <div data-dojo-attach-event="onClick:_onFileScopeDefaultPermissions" id="${id}FileScopeDefaultPermissions" data-dojo-type="dijit.MenuItem">${i18n.FileScopeDefaultPermissions}</div>
@@ -145,7 +145,7 @@
         <div id="${id}FilePermissionForm" style="width:460px" data-dojo-type="dijit.form.Form">
         <div id="${id}FilePermissionForm" style="width:460px" data-dojo-type="dijit.form.Form">
             <div data-dojo-props="cols:2" data-dojo-type="hpcc.TableContainer">
             <div data-dojo-props="cols:2" data-dojo-type="hpcc.TableContainer">
                 <p>${i18n.PleaseSelectAUserOrGroup}</p>
                 <p>${i18n.PleaseSelectAUserOrGroup}</p>
-                <input id="${id}NameSelect" title="${i18n.Name}:" name="FileName" required="true" colspan="2" data-dojo-props="trim: true, required: true"  data-dojo-type="dijit.form.ValidationTextBox" />
+                <input id="${id}NameSelect" title="${i18n.Name}:" name="FileName" required="true" colspan="2" data-dojo-props="trim: true, required: true" data-dojo-type="dijit.form.ValidationTextBox" />
                 <input id="${id}UsersSelect" title="${i18n.Users}:" name="UserName" colspan="2" data-dojo-type="TargetSelectWidget" />
                 <input id="${id}UsersSelect" title="${i18n.Users}:" name="UserName" colspan="2" data-dojo-type="TargetSelectWidget" />
                 <input id="${id}GroupsSelect" title="${i18n.Groups}:" name="GroupName" colspan="2" data-dojo-type="TargetSelectWidget" />
                 <input id="${id}GroupsSelect" title="${i18n.Groups}:" name="GroupName" colspan="2" data-dojo-type="TargetSelectWidget" />
             </div>
             </div>

+ 39 - 39
esp/src/eclwatch/templates/WUDetailsWidget.html

@@ -28,11 +28,11 @@
                         <div data-dojo-type="dijit.TooltipDialog">
                         <div data-dojo-type="dijit.TooltipDialog">
                             <div id="${id}PublishForm" style="width:460px" onsubmit="return false;" data-dojo-type="dijit.form.Form">
                             <div id="${id}PublishForm" style="width:460px" onsubmit="return false;" data-dojo-type="dijit.form.Form">
                                 <div class="dijitDialogPaneContentArea" data-dojo-props="cols:2" data-dojo-type="hpcc.TableContainer">
                                 <div class="dijitDialogPaneContentArea" data-dojo-props="cols:2" data-dojo-type="hpcc.TableContainer">
-                                    <input id="${id}Jobname2" title="${i18n.JobName}:" colspan="2" style="width:100%" required="true" data-dojo-props="trim: true" data-dojo-type="dijit.form.ValidationTextBox"/>
-                                     <input id="${id}RemoteDali" title="${i18n.RemoteDali}:" colspan="2" style="width:100%" required="false" data-dojo-props="trim: true" data-dojo-type="dijit.form.ValidationTextBox"/>
-                                     <input id="${id}SourceProcess" title="${i18n.SourceProcess}:" colspan="2" style="width:100%" required="false" data-dojo-props="trim: true" data-dojo-type="dijit.form.ValidationTextBox"/>
-                                     <input id="${id}Comment" title="${i18n.Comment}:" colspan="2" style="width:100%" required="false" data-dojo-props="trim: true" data-dojo-type="dijit.form.ValidationTextBox"/>
-                                     <select id="${id}Priority" title="${i18n.Priority}:" colspan="2" data-dojo-type="dijit.form.Select">
+                                    <input id="${id}Jobname2" title="${i18n.JobName}:" colspan="2" style="width:100%" required="true" data-dojo-props="trim: true" data-dojo-type="dijit.form.ValidationTextBox" />
+                                    <input id="${id}RemoteDali" title="${i18n.RemoteDali}:" colspan="2" style="width:100%" required="false" data-dojo-props="trim: true" data-dojo-type="dijit.form.ValidationTextBox" />
+                                    <input id="${id}SourceProcess" title="${i18n.SourceProcess}:" colspan="2" style="width:100%" required="false" data-dojo-props="trim: true" data-dojo-type="dijit.form.ValidationTextBox" />
+                                    <input id="${id}Comment" title="${i18n.Comment}:" colspan="2" style="width:100%" required="false" data-dojo-props="trim: true" data-dojo-type="dijit.form.ValidationTextBox" />
+                                    <select id="${id}Priority" title="${i18n.Priority}:" colspan="2" data-dojo-type="dijit.form.Select">
                                         <option value="" selected="selected">${i18n.None}</option>
                                         <option value="" selected="selected">${i18n.None}</option>
                                         <option value="SLA">${i18n.SLA}</option>
                                         <option value="SLA">${i18n.SLA}</option>
                                         <option value="Low">${i18n.Low}</option>
                                         <option value="Low">${i18n.Low}</option>
@@ -48,29 +48,29 @@
                         </div>
                         </div>
                     </div>
                     </div>
                     <span data-dojo-type="dijit.ToolbarSeparator"></span>
                     <span data-dojo-type="dijit.ToolbarSeparator"></span>
-                    <div id="${id}ZapReport"  title="${i18n.ZippedAnalysisPackage}" data-dojo-attach-event="onClick:_onZapReport" data-dojo-props="iconClass:'iconZap'" data-dojo-type="dijit.form.Button">${i18n.ZAP}</div>
+                    <div id="${id}ZapReport" title="${i18n.ZippedAnalysisPackage}" data-dojo-attach-event="onClick:_onZapReport" data-dojo-props="iconClass:'iconZap'" data-dojo-type="dijit.form.Button">${i18n.ZAP}</div>
                     <span data-dojo-type="dijit.ToolbarSeparator"></span>
                     <span data-dojo-type="dijit.ToolbarSeparator"></span>
                     <div id="${id}SlaveLogs" data-dojo-type="dijit.form.DropDownButton">
                     <div id="${id}SlaveLogs" data-dojo-type="dijit.form.DropDownButton">
                         <span>${i18n.SlaveLogs}</span>
                         <span>${i18n.SlaveLogs}</span>
                         <div data-dojo-type="dijit.TooltipDialog">
                         <div data-dojo-type="dijit.TooltipDialog">
-                        <div id="${id}LogsForm" style="width:460px" onsubmit="return false;" data-dojo-type="dijit.form.Form">
-                            <div class="dijitDialogPaneContentArea" data-dojo-props="cols:2" data-dojo-type="hpcc.TableContainer">
-                                <select id="${id}ThorProcess" title="${i18n.ThorProcess}:" name="ThorProcess" colspan="2" data-dojo-type="dijit.form.Select" /></select>
-                                <input id="${id}SlaveNumber" maxlength="" title="${i18n.SlaveNumber}:" name="SlaveNumber" value="1" required="true" data-dojo-props="trim: true, placeHolder:'1'" data-dojo-type="dijit.form.NumberTextBox"/>
-                                <select id="${id}FileFormat" title="${i18n.File}:" name="ThorProcess" colspan="2" data-dojo-type="dijit.form.Select" />
-                                    <option value="1">${i18n.OriginalFile}</option>
-                                    <option value="2">${i18n.Zip}</option>
-                                    <option value="3">${i18n.GZip}</option>
-                                </select>
-                            </div>
-                            </br>
-                            <div><span id="SlavesMaxNumber" class="bold"></span></div>
-                            <div><span id="AllowOnlyNumber" class="boldRed"></span></div>
-                            <div class="dijitDialogPaneActionBar">
-                                <button type="submit" data-dojo-attach-event="onClick:_getDownload" data-dojo-type="dijit.form.Button">${i18n.Download}</button>
+                            <div id="${id}LogsForm" style="width:460px" onsubmit="return false;" data-dojo-type="dijit.form.Form">
+                                <div class="dijitDialogPaneContentArea" data-dojo-props="cols:2" data-dojo-type="hpcc.TableContainer">
+                                    <select id="${id}ThorProcess" title="${i18n.ThorProcess}:" name="ThorProcess" colspan="2" data-dojo-type="dijit.form.Select"></select>
+                                    <input id="${id}SlaveNumber" maxlength="" title="${i18n.SlaveNumber}:" name="SlaveNumber" value="1" required="true" data-dojo-props="trim: true, placeHolder:'1'" data-dojo-type="dijit.form.NumberTextBox" />
+                                    <select id="${id}FileFormat" title="${i18n.File}:" name="ThorProcess" colspan="2" data-dojo-type="dijit.form.Select">
+                                        <option value="1">${i18n.OriginalFile}</option>
+                                        <option value="2">${i18n.Zip}</option>
+                                        <option value="3">${i18n.GZip}</option>
+                                    </select>
+                                </div>
+                                <br />
+                                <div><span id="SlavesMaxNumber" class="bold"></span></div>
+                                <div><span id="AllowOnlyNumber" class="boldRed"></span></div>
+                                <div class="dijitDialogPaneActionBar">
+                                    <button type="submit" data-dojo-attach-event="onClick:_getDownload" data-dojo-type="dijit.form.Button">${i18n.Download}</button>
+                                </div>
                             </div>
                             </div>
                         </div>
                         </div>
-                        </div>
                     </div>
                     </div>
                     <span data-dojo-type="dijit.ToolbarSeparator"></span>
                     <span data-dojo-type="dijit.ToolbarSeparator"></span>
                     <div class="right" data-dojo-attach-event="onChange:_onMaximize" data-dojo-props="iconClass:'iconMaximize', showLabel:false" checked=false data-dojo-type="dijit.form.ToggleButton">${i18n.MaximizeRestore}</div>
                     <div class="right" data-dojo-attach-event="onChange:_onMaximize" data-dojo-props="iconClass:'iconMaximize', showLabel:false" checked=false data-dojo-type="dijit.form.ToggleButton">${i18n.MaximizeRestore}</div>
@@ -79,7 +79,7 @@
                 <div data-dojo-props="region: 'center'" data-dojo-type="dijit.layout.ContentPane">
                 <div data-dojo-props="region: 'center'" data-dojo-type="dijit.layout.ContentPane">
                     <div style="display:inline-block">
                     <div style="display:inline-block">
                         <h2>
                         <h2>
-                            <img id="${id}ProtectedImage" src="${dojoConfig.urlInfo.resourcePath}/img/locked.png" />&nbsp;<div id="${id}StateIdImage" class="iconWorkunit" ></div>&nbsp;<span id="${id}Wuid" class="bold">${i18n.WUID}</span>
+                            <img id="${id}ProtectedImage" src="${dojoConfig.urlInfo.resourcePath}/img/locked.png" />&nbsp;<div id="${id}StateIdImage" class="iconWorkunit"></div>&nbsp;<span id="${id}Wuid" class="bold">${i18n.WUID}</span>
                             <button id="${id}ClippyButton" class="clippy" data-clipboard-target="#${id}Wuid"><img src="${dojoConfig.urlInfo.resourcePath}/img/clippy.png" alt="${i18n.CopyToClipboard}"></button>
                             <button id="${id}ClippyButton" class="clippy" data-clipboard-target="#${id}Wuid"><img src="${dojoConfig.urlInfo.resourcePath}/img/clippy.png" alt="${i18n.CopyToClipboard}"></button>
                         </h2>
                         </h2>
                     </div>
                     </div>
@@ -101,24 +101,24 @@
                             </li>
                             </li>
                             <li id="scopeOptional" class="hidden">
                             <li id="scopeOptional" class="hidden">
                                 <label class="Prompt" for="${id}Scope">${i18n.Scope}:</label>
                                 <label class="Prompt" for="${id}Scope">${i18n.Scope}:</label>
-                                <div><input id="${id}Scope" data-dojo-props="trim:true" data-dojo-type="dijit.form.TextBox"/></div>
+                                <div><input id="${id}Scope" data-dojo-props="trim:true" data-dojo-type="dijit.form.TextBox" /></div>
                             </li>
                             </li>
                             <li>
                             <li>
                                 <label class="Prompt" for="${id}Jobname">${i18n.JobName}:</label>
                                 <label class="Prompt" for="${id}Jobname">${i18n.JobName}:</label>
-                                <div><input id="${id}Jobname" data-dojo-props="trim:true" data-dojo-type="dijit.form.TextBox"/></div>
+                                <div><input id="${id}Jobname" data-dojo-props="trim:true" data-dojo-type="dijit.form.TextBox" /></div>
                             </li>
                             </li>
                             <li>
                             <li>
                                 <label class="Prompt" for="${id}Description">${i18n.Description}:</label>
                                 <label class="Prompt" for="${id}Description">${i18n.Description}:</label>
-                                <div><input id="${id}Description" data-dojo-props="trim:true" data-dojo-type="dijit.form.TextBox"/></div>
+                                <div><input id="${id}Description" data-dojo-props="trim:true" data-dojo-type="dijit.form.TextBox" /></div>
                             </li>
                             </li>
                             <li>
                             <li>
                                 <label class="Prompt" for="${id}Protected">${i18n.Protected}:</label>
                                 <label class="Prompt" for="${id}Protected">${i18n.Protected}:</label>
-                                <div><input id="${id}Protected" data-dojo-type="dijit.form.CheckBox"/></div>
+                                <div><input id="${id}Protected" data-dojo-type="dijit.form.CheckBox" /></div>
                             </li>
                             </li>
                             <li>
                             <li>
                                 <label class="Prompt" for="${id}Cluster">${i18n.Cluster}:</label>
                                 <label class="Prompt" for="${id}Cluster">${i18n.Cluster}:</label>
                                 <div id="${id}Cluster"></div>
                                 <div id="${id}Cluster"></div>
-                                <div id="${id}AllowedClusters" data-dojo-type="dijit.form.Select"/></div>
+                                <div id="${id}AllowedClusters" data-dojo-type="dijit.form.Select"></div>
                             </li>
                             </li>
                             <li>
                             <li>
                                 <label class="Prompt" for="${id}TotalClusterTime">${i18n.TotalClusterTime}:</label>
                                 <label class="Prompt" for="${id}TotalClusterTime">${i18n.TotalClusterTime}:</label>
@@ -134,9 +134,9 @@
                             </li>
                             </li>
                         </ul>
                         </ul>
                     </form>
                     </form>
-            </div>
-            <div id="${id}InfoContainer" class="wrap" style="height: 33%" data-dojo-props="region: 'bottom', splitter: true, minSize: 120, showToolbar: true" data-dojo-type="InfoGridWidget">
-            </div>
+                </div>
+                <div id="${id}InfoContainer" class="wrap" style="height: 33%" data-dojo-props="region: 'bottom', splitter: true, minSize: 120, showToolbar: true" data-dojo-type="InfoGridWidget">
+                </div>
             </div>
             </div>
             <div id="${id}_Variables" title="${i18n.Variables}" data-dojo-props="delayWidget: 'VariablesWidget', disabled: true" data-dojo-type="DelayLoadWidget">
             <div id="${id}_Variables" title="${i18n.Variables}" data-dojo-props="delayWidget: 'VariablesWidget', disabled: true" data-dojo-type="DelayLoadWidget">
             </div>
             </div>
@@ -163,23 +163,23 @@
         </div>
         </div>
     </div>
     </div>
     <div id="${id}ZapDialog" data-dojo-type="dijit.Dialog" title="${i18n.ZippedAnalysisPackage}">
     <div id="${id}ZapDialog" data-dojo-type="dijit.Dialog" title="${i18n.ZippedAnalysisPackage}">
-        <div id="${id}ZapForm" style="width:460px;" method="post" encType="application/x-www-form-urlencoded" data-dojo-type="dijit.form.Form">
+        <div id="${id}ZapForm" style="width:460px;" method="post" enctype="application/x-www-form-urlencoded" data-dojo-type="dijit.form.Form">
             <div data-dojo-props="cols:2" data-dojo-type="hpcc.TableContainer">
             <div data-dojo-props="cols:2" data-dojo-type="hpcc.TableContainer">
                 <input id="${id}ZapName" title="${i18n.FileName}:" name="ZAPFileName" colspan="2" data-dojo-props="trim: true," data-dojo-type="dijit.form.TextBox" />
                 <input id="${id}ZapName" title="${i18n.FileName}:" name="ZAPFileName" colspan="2" data-dojo-props="trim: true," data-dojo-type="dijit.form.TextBox" />
                 <input id="${id}ZapWUID" title="${i18n.WUID}:" name="Wuid" colspan="2" data-dojo-props="trim: true, readonly: true," data-dojo-type="dijit.form.TextBox" />
                 <input id="${id}ZapWUID" title="${i18n.WUID}:" name="Wuid" colspan="2" data-dojo-props="trim: true, readonly: true," data-dojo-type="dijit.form.TextBox" />
                 <input id="${id}BuildVersion" title="${i18n.ESPBuildVersion}:" name="BuildVersion" colspan="2" data-dojo-props="trim: true, readonly: true," data-dojo-type="dijit.form.TextBox" />
                 <input id="${id}BuildVersion" title="${i18n.ESPBuildVersion}:" name="BuildVersion" colspan="2" data-dojo-props="trim: true, readonly: true," data-dojo-type="dijit.form.TextBox" />
                 <input id="${id}ESPIPAddress" title="${i18n.ESPNetworkAddress}:" name="ESPIPAddress" colspan="2" data-dojo-props="trim: true, readonly: true," data-dojo-type="dijit.form.TextBox" />
                 <input id="${id}ESPIPAddress" title="${i18n.ESPNetworkAddress}:" name="ESPIPAddress" colspan="2" data-dojo-props="trim: true, readonly: true," data-dojo-type="dijit.form.TextBox" />
                 <input id="${id}ThorIPAddress" title="${i18n.ThorNetworkAddress}:" name="ThorIPAddress" colspan="2" data-dojo-props="trim: true, readonly: true," data-dojo-type="dijit.form.TextBox" />
                 <input id="${id}ThorIPAddress" title="${i18n.ThorNetworkAddress}:" name="ThorIPAddress" colspan="2" data-dojo-props="trim: true, readonly: true," data-dojo-type="dijit.form.TextBox" />
-                <input id="${id}ZapDescription" title="${i18n.Description}:" name="ProblemDescription" cols="22" colspan="2" data-dojo-type="dijit.form.SimpleTextarea"/>
-                <input id="${id}WarnHistory" title="${i18n.History}:" name="WhatChanged" cols="22" colspan="2" data-dojo-type="dijit.form.SimpleTextarea"/>
-                <input id="${id}WarnTimings" title="${i18n.Timings}:" name="WhereSlow" cols="22" colspan="2" data-dojo-type="dijit.form.SimpleTextarea"/>
+                <input id="${id}ZapDescription" title="${i18n.Description}:" name="ProblemDescription" cols="22" colspan="2" data-dojo-type="dijit.form.SimpleTextarea" />
+                <input id="${id}WarnHistory" title="${i18n.History}:" name="WhatChanged" cols="22" colspan="2" data-dojo-type="dijit.form.SimpleTextarea" />
+                <input id="${id}WarnTimings" title="${i18n.Timings}:" name="WhereSlow" cols="22" colspan="2" data-dojo-type="dijit.form.SimpleTextarea" />
                 <input id="${id}Password" title="${i18n.PasswordOpenZAP}:" name="Password" cols="22" colspan="2" type="password" data-dojo-props="trim: true" data-dojo-type="dijit.form.ValidationTextBox" />
                 <input id="${id}Password" title="${i18n.PasswordOpenZAP}:" name="Password" cols="22" colspan="2" type="password" data-dojo-props="trim: true" data-dojo-type="dijit.form.ValidationTextBox" />
                 <input id="${id}IncludeSlaveLogsCheckbox" title="${i18n.IncludeSlaveLogs}:" name="IncludeThorSlaveLog" cols="22" colspan="2" type="checkbox" data-dojo-type="dijit.form.CheckBox" />
                 <input id="${id}IncludeSlaveLogsCheckbox" title="${i18n.IncludeSlaveLogs}:" name="IncludeThorSlaveLog" cols="22" colspan="2" type="checkbox" data-dojo-type="dijit.form.CheckBox" />
                 <input id="${id}EmailCheckbox" title="${i18n.SendEmail}:" name="SendEmail" cols="22" colspan="2" type="checkbox" data-dojo-type="dijit.form.CheckBox" />
                 <input id="${id}EmailCheckbox" title="${i18n.SendEmail}:" name="SendEmail" cols="22" colspan="2" type="checkbox" data-dojo-type="dijit.form.CheckBox" />
-                <input id="${id}EmailTo" title="${i18n.EmailTo}:" name="EmailTo" colspan="2" data-dojo-props="trim:true, readonly:true, placeHolder:'See Configuration Manager.'" data-dojo-type="dijit.form.TextBox"/>
-                <input id="${id}EmailFrom" title="${i18n.EmailFrom}:" name="EmailFrom" colspan="2" data-dojo-props="trim:true, placeHolder:'See Configuration Manager.'" data-dojo-type="dijit.form.TextBox"/>
-                <input id="${id}EmailSubject" title="${i18n.EmailSubject}:" name="EmailSubject" colspan="2" data-dojo-props="trim:true" data-dojo-type="dijit.form.ValidationTextBox" required="false"/>
-                <input id="${id}EmailBody" title="${i18n.EmailBody}:" name="EmailBody" cols="22" colspan="2" data-dojo-type="dijit.form.SimpleTextarea"/>
+                <input id="${id}EmailTo" title="${i18n.EmailTo}:" name="EmailTo" colspan="2" data-dojo-props="trim:true, readonly:true, placeHolder:'See Configuration Manager.'" data-dojo-type="dijit.form.TextBox" />
+                <input id="${id}EmailFrom" title="${i18n.EmailFrom}:" name="EmailFrom" colspan="2" data-dojo-props="trim:true, placeHolder:'See Configuration Manager.'" data-dojo-type="dijit.form.TextBox" />
+                <input id="${id}EmailSubject" title="${i18n.EmailSubject}:" name="EmailSubject" colspan="2" data-dojo-props="trim:true" data-dojo-type="dijit.form.ValidationTextBox" required="false" />
+                <input id="${id}EmailBody" title="${i18n.EmailBody}:" name="EmailBody" cols="22" colspan="2" data-dojo-type="dijit.form.SimpleTextarea" />
             </div>
             </div>
             <div class="dijitDialogPaneActionBar">
             <div class="dijitDialogPaneActionBar">
                 <button id="${id}onZapSubmit" data-dojo-attach-event="onClick:_onSubmitDialog" type="submit" data-dojo-type="dijit.form.Button">${i18n.Apply}</button>
                 <button id="${id}onZapSubmit" data-dojo-attach-event="onClick:_onSubmitDialog" type="submit" data-dojo-type="dijit.form.Button">${i18n.Apply}</button>

+ 1 - 1
esp/src/lws.config.js

@@ -16,7 +16,7 @@ let rewrite = [
     { from: "/esp/files/esp/logout", to: "http://" + debugServerIP + ":8010/esp/logout" },
     { from: "/esp/files/esp/logout", to: "http://" + debugServerIP + ":8010/esp/logout" },
     { from: "/ws_elk/*", to: "http://" + debugServerIP + ":8010/ws_elk/$1" },
     { from: "/ws_elk/*", to: "http://" + debugServerIP + ":8010/ws_elk/$1" },
     { from: "/esp/files/esp/reset_session_timeout", to: "http://" + debugServerIP + ":8010/esp/reset_session_timeout" },
     { from: "/esp/files/esp/reset_session_timeout", to: "http://" + debugServerIP + ":8010/esp/reset_session_timeout" },
-    { from: "/esp/files/node_modules/@hpcc-js/*/dist/index.min.js", to: "/node_modules/@hpcc-js/$1/dist/index.js" },
+    { from: "/esp/files/node_modules/@hpcc-js/*/dist/index.min.js", to: debugServerIP !== CLUSTER_GJS ? "/node_modules/@hpcc-js/$1/dist/index.js" : "/hpcc-js/$1/dist/index.js" },
     { from: "/esp/files/dist/*", to: "/build/dist/$1" },
     { from: "/esp/files/dist/*", to: "/build/dist/$1" },
     { from: "/esp/files/*", to: "/$1" },
     { from: "/esp/files/*", to: "/$1" },
     { from: "/ws_elk/*", to: "http://" + debugServerIP + ":8010/ws_elk/$1" },
     { from: "/ws_elk/*", to: "http://" + debugServerIP + ":8010/ws_elk/$1" },

File diff suppressed because it is too large
+ 611 - 560
esp/src/package-lock.json


+ 9 - 10
esp/src/package.json

@@ -30,13 +30,13 @@
   },
   },
   "main": "src/stub.js",
   "main": "src/stub.js",
   "dependencies": {
   "dependencies": {
-    "@hpcc-js/chart": "2.19.0",
+    "@hpcc-js/chart": "2.19.1",
     "@hpcc-js/comms": "2.9.6",
     "@hpcc-js/comms": "2.9.6",
-    "@hpcc-js/eclwatch": "2.5.18",
-    "@hpcc-js/html": "2.6.15",
-    "@hpcc-js/map": "2.9.1",
-    "@hpcc-js/other": "2.12.16",
-    "@hpcc-js/tree": "2.7.15",
+    "@hpcc-js/eclwatch": "2.5.20",
+    "@hpcc-js/html": "2.6.16",
+    "@hpcc-js/map": "2.9.3",
+    "@hpcc-js/other": "2.12.18",
+    "@hpcc-js/tree": "2.7.16",
     "clipboard": "2.0.4",
     "clipboard": "2.0.4",
     "codemirror": "5.46.0",
     "codemirror": "5.46.0",
     "crossfilter2": "1.4.7",
     "crossfilter2": "1.4.7",
@@ -60,16 +60,15 @@
     "file-loader": "3.0.1",
     "file-loader": "3.0.1",
     "jshint": "2.10.2",
     "jshint": "2.10.2",
     "local-web-server": "2.6.1",
     "local-web-server": "2.6.1",
-    "lodash": "4.17.11",
     "npm-run-all": "4.1.5",
     "npm-run-all": "4.1.5",
     "rimraf": "2.6.3",
     "rimraf": "2.6.3",
     "style-loader": "0.23.1",
     "style-loader": "0.23.1",
     "tslib": "1.9.3",
     "tslib": "1.9.3",
     "typescript": "3.4.5",
     "typescript": "3.4.5",
     "url-loader": "1.1.2",
     "url-loader": "1.1.2",
-    "webpack": "4.31.0",
-    "webpack-bundle-analyzer": "3.3.2",
-    "webpack-cli": "3.3.2"
+    "webpack": "4.39.1",
+    "webpack-bundle-analyzer": "3.4.1",
+    "webpack-cli": "3.3.6"
   },
   },
   "author": "HPCC Systems",
   "author": "HPCC Systems",
   "license": "Apache-2.0",
   "license": "Apache-2.0",

+ 3 - 0
initfiles/componentfiles/configschema/xsd/roxie.xsd

@@ -277,6 +277,9 @@
                     <xs:attribute name="soapTraceLevel" type="xs:nonNegativeInteger" hpcc:displayName="Soap trace Level"
                     <xs:attribute name="soapTraceLevel" type="xs:nonNegativeInteger" hpcc:displayName="Soap trace Level"
                                   hpcc:presetValue="1"
                                   hpcc:presetValue="1"
                                   hpcc:tooltip="Level of detail in reporting SOAPCALL information(set to 0 for none, 1 for normal, >1 or more for extended)"/>
                                   hpcc:tooltip="Level of detail in reporting SOAPCALL information(set to 0 for none, 1 for normal, >1 or more for extended)"/>
+                    <xs:attribute name="traceTranslations" type="xs:boolean" hpcc:displayName="Trace record layout translations"
+                                  hpcc:presetValue="true"
+                                  hpcc:tooltip="Trace record layout translations to log file"/>
                     <xs:attribute name="traceEnabled" type="xs:boolean" hpcc:displayName="Trace Enabled"
                     <xs:attribute name="traceEnabled" type="xs:boolean" hpcc:displayName="Trace Enabled"
                                   hpcc:presetValue="false"
                                   hpcc:presetValue="false"
                                   hpcc:tooltip="TRACE activity output enabled by default (can be overridden in workunit or query)"/>
                                   hpcc:tooltip="TRACE activity output enabled by default (can be overridden in workunit or query)"/>

+ 7 - 0
initfiles/componentfiles/configxml/roxie.xsd.in

@@ -1011,6 +1011,13 @@
         </xs:appinfo>
         </xs:appinfo>
       </xs:annotation>
       </xs:annotation>
     </xs:attribute>
     </xs:attribute>
+    <xs:attribute name="traceTranslations" type="xs:boolean" use="optional" default="true">
+      <xs:annotation>
+        <xs:appinfo>
+          <tooltip>Trace record layout translations to log file"</tooltip>
+        </xs:appinfo>
+      </xs:annotation>
+    </xs:attribute>
     <xs:attribute name="traceEnabled" type="xs:boolean" use="optional" default="false">
     <xs:attribute name="traceEnabled" type="xs:boolean" use="optional" default="false">
       <xs:annotation>
       <xs:annotation>
         <xs:appinfo>
         <xs:appinfo>

+ 1 - 0
roxie/ccd/ccd.hpp

@@ -272,6 +272,7 @@ extern unsigned preabortKeyedJoinsThreshold;
 extern unsigned preabortIndexReadsThreshold;
 extern unsigned preabortIndexReadsThreshold;
 extern bool traceStartStop;
 extern bool traceStartStop;
 extern bool traceServerSideCache;
 extern bool traceServerSideCache;
+extern bool traceTranslations;
 extern bool defaultTimeActivities;
 extern bool defaultTimeActivities;
 extern bool defaultTraceEnabled;
 extern bool defaultTraceEnabled;
 extern unsigned defaultTraceLimit;
 extern unsigned defaultTraceLimit;

+ 4 - 1
roxie/ccd/ccdfile.cpp

@@ -2141,8 +2141,11 @@ public:
                     else
                     else
                     {
                     {
                         translator.setown(createRecordTranslator(projected->queryRecordAccessor(true), actual->queryRecordAccessor(true)));
                         translator.setown(createRecordTranslator(projected->queryRecordAccessor(true), actual->queryRecordAccessor(true)));
-                        if (traceLevel > 5)
+                        if (traceLevel>0 && traceTranslations)
+                        {
+                            DBGLOG("Record layout translator created for %s", subname);
                             translator->describe();
                             translator->describe();
+                        }
                         if (!translator || !translator->canTranslate())
                         if (!translator || !translator->canTranslate())
                             throw MakeStringException(ROXIE_MISMATCH, "Untranslatable record layout mismatch detected for file %s", subname);
                             throw MakeStringException(ROXIE_MISMATCH, "Untranslatable record layout mismatch detected for file %s", subname);
                         else if (translator->needsTranslate())
                         else if (translator->needsTranslate())

+ 2 - 0
roxie/ccd/ccdmain.cpp

@@ -84,6 +84,7 @@ bool traceStartStop = false;
 bool traceServerSideCache = false;
 bool traceServerSideCache = false;
 bool defaultTimeActivities = true;
 bool defaultTimeActivities = true;
 bool defaultTraceEnabled = false;
 bool defaultTraceEnabled = false;
+bool traceTranslations = true;
 unsigned defaultTraceLimit = 10;
 unsigned defaultTraceLimit = 10;
 unsigned watchActivityId = 0;
 unsigned watchActivityId = 0;
 unsigned testSlaveFailure = 0;
 unsigned testSlaveFailure = 0;
@@ -1001,6 +1002,7 @@ int STARTQUERY_API start_query(int argc, const char *argv[])
 
 
         traceStartStop = topology->getPropBool("@traceStartStop", false);
         traceStartStop = topology->getPropBool("@traceStartStop", false);
         traceServerSideCache = topology->getPropBool("@traceServerSideCache", false);
         traceServerSideCache = topology->getPropBool("@traceServerSideCache", false);
+        traceTranslations = topology->getPropBool("@traceTranslations", true);
         defaultTimeActivities = topology->getPropBool("@timeActivities", true);
         defaultTimeActivities = topology->getPropBool("@timeActivities", true);
         defaultTraceEnabled = topology->getPropBool("@traceEnabled", false);
         defaultTraceEnabled = topology->getPropBool("@traceEnabled", false);
         defaultTraceLimit = topology->getPropInt("@traceLimit", 10);
         defaultTraceLimit = topology->getPropInt("@traceLimit", 10);

+ 41 - 12
rtl/eclrtl/rtldynfield.cpp

@@ -988,7 +988,7 @@ enum FieldMatchType {
     match_recurse     = 0x80,    // Use recursive translator for child records/datasets
     match_recurse     = 0x80,    // Use recursive translator for child records/datasets
     match_fail        = 0x100,   // no translation possible
     match_fail        = 0x100,   // no translation possible
     match_keychange   = 0x200,   // at least one affected field not marked as payload (set on translator)
     match_keychange   = 0x200,   // at least one affected field not marked as payload (set on translator)
-    match_virtual     = 0x800,   // at least one affected field not marked as payload (set on translator)
+    match_virtual     = 0x800,   // at least one affected field is a virtual field (set on translator)
 
 
     // This flag may be set in conjunction with the others
     // This flag may be set in conjunction with the others
     match_inifblock   = 0x400,   // matching to a field in an ifblock - may not be present
     match_inifblock   = 0x400,   // matching to a field in an ifblock - may not be present
@@ -1078,6 +1078,8 @@ public:
 private:
 private:
     void doDescribe(unsigned indent) const
     void doDescribe(unsigned indent) const
     {
     {
+        unsigned perfect=0;
+        unsigned reported=0;
         for (unsigned idx = 0; idx <  destRecInfo.getNumFields(); idx++)
         for (unsigned idx = 0; idx <  destRecInfo.getNumFields(); idx++)
         {
         {
             const char *source = destRecInfo.queryName(idx);
             const char *source = destRecInfo.queryName(idx);
@@ -1088,17 +1090,41 @@ private:
                 DBGLOG("%*sUse virtual value for field %s", indent, "", source);
                 DBGLOG("%*sUse virtual value for field %s", indent, "", source);
             else
             else
             {
             {
-                StringBuffer matchStr;
-                DBGLOG("%*sMatch (%s) to field %d for field %s (%x)", indent, "", describeFlags(matchStr, match.matchType).str(), match.matchIdx, source, destRecInfo.queryType(idx)->fieldType);
-                if (match.subTrans)
-                    match.subTrans->doDescribe(indent+2);
+                if (match.matchType != match_perfect)
+                {
+                    reported++;
+                    StringBuffer matchStr;
+                    DBGLOG("%*sMatch (%s) to field %d for field %s (typecode %x)", indent, "", describeFlags(matchStr, match.matchType).str(), match.matchIdx, source, destRecInfo.queryType(idx)->fieldType);
+                    if (match.subTrans)
+                        match.subTrans->doDescribe(indent+2);
+                }
+                else
+                    perfect++;
+            }
+        }
+        if (allUnmatched.ordinality())
+        {
+            VStringBuffer msg("%*sDropped field", indent, "");
+            if (allUnmatched.ordinality()>1)
+                msg.append('s');
+            for (unsigned idx = 0; idx < allUnmatched.ordinality() && idx < 5; idx++)
+            {
+
+                if (idx)
+                    msg.append(',');
+                msg.appendf(" %s", sourceRecInfo.queryName(allUnmatched.item(idx)));
             }
             }
+            if (allUnmatched.ordinality() > 5)
+                msg.appendf(" and %u other fields", allUnmatched.ordinality() - 5);
+            DBGLOG("%s", msg.str());
         }
         }
         if (!canTranslate())
         if (!canTranslate())
             DBGLOG("%*sTranslation is NOT possible", indent, "");
             DBGLOG("%*sTranslation is NOT possible", indent, "");
         else if (needsTranslate())
         else if (needsTranslate())
         {
         {
             StringBuffer matchStr;
             StringBuffer matchStr;
+            if (perfect)
+                DBGLOG("%u %sfield%s matched perfectly", perfect, reported ? "other " : "", perfect==1 ? "" : "s");
             DBGLOG("%*sTranslation is possible (%s)", indent, "", describeFlags(matchStr, matchFlags).str());
             DBGLOG("%*sTranslation is possible (%s)", indent, "", describeFlags(matchStr, matchFlags).str());
         }
         }
         else
         else
@@ -1432,7 +1458,8 @@ private:
     const RtlRecord &sourceRecInfo;
     const RtlRecord &sourceRecInfo;
     bool binarySource = true;
     bool binarySource = true;
     unsigned fixedDelta = 0;  // total size of all fixed-size source fields that are not matched
     unsigned fixedDelta = 0;  // total size of all fixed-size source fields that are not matched
-    UnsignedArray unmatched;  // List of all variable-size source fields that are unmatched
+    UnsignedArray allUnmatched;  // List of all source fields that are unmatched (so that we can trace them)
+    UnsignedArray variableUnmatched;  // List of all variable-size source fields that are unmatched
     FieldMatchType matchFlags = match_perfect;
     FieldMatchType matchFlags = match_perfect;
 
 
     struct MatchInfo
     struct MatchInfo
@@ -1506,6 +1533,7 @@ private:
     }
     }
     void createMatchInfo()
     void createMatchInfo()
     {
     {
+        unsigned defaulted = 0;
         for (unsigned idx = 0; idx < destRecInfo.getNumFields(); idx++)
         for (unsigned idx = 0; idx < destRecInfo.getNumFields(); idx++)
         {
         {
             const RtlFieldInfo *field = destRecInfo.queryField(idx);
             const RtlFieldInfo *field = destRecInfo.queryField(idx);
@@ -1520,6 +1548,7 @@ private:
                 fixedDelta -= defaultSize;
                 fixedDelta -= defaultSize;
                 if ((field->flags & RFTMispayloadfield) == 0)
                 if ((field->flags & RFTMispayloadfield) == 0)
                     matchFlags |= match_keychange;
                     matchFlags |= match_keychange;
+                defaulted++;
                 //DBGLOG("Decreasing fixedDelta size by %d to %d for defaulted field %d (%s)", defaultSize, fixedDelta, idx, destRecInfo.queryName(idx));
                 //DBGLOG("Decreasing fixedDelta size by %d to %d for defaulted field %d (%s)", defaultSize, fixedDelta, idx, destRecInfo.queryName(idx));
             }
             }
             else
             else
@@ -1669,10 +1698,9 @@ private:
             }
             }
             matchFlags |= info.matchType;
             matchFlags |= info.matchType;
         }
         }
-        if (sourceRecInfo.getNumFields() > destRecInfo.getNumFields())
-            matchFlags |= match_remove;
-        if (matchFlags && !destRecInfo.getFixedSize())
+        if (sourceRecInfo.getNumFields() > destRecInfo.getNumFields()-defaulted)
         {
         {
+            matchFlags |= match_remove;
             for (unsigned idx = 0; idx < sourceRecInfo.getNumFields(); idx++)
             for (unsigned idx = 0; idx < sourceRecInfo.getNumFields(); idx++)
             {
             {
                 const RtlFieldInfo *field = sourceRecInfo.queryField(idx);
                 const RtlFieldInfo *field = sourceRecInfo.queryField(idx);
@@ -1691,8 +1719,9 @@ private:
                             fixedDelta += type->getMinSize();
                             fixedDelta += type->getMinSize();
                         }
                         }
                         else
                         else
-                            unmatched.append(idx);
+                            variableUnmatched.append(idx);
                     }
                     }
+                    allUnmatched.append(idx);
                 }
                 }
             }
             }
             //DBGLOG("Source record contains %d bytes of omitted fixed size fields", fixedDelta);
             //DBGLOG("Source record contains %d bytes of omitted fixed size fields", fixedDelta);
@@ -1703,9 +1732,9 @@ private:
         //DBGLOG("Source record size is %d", (int) sourceRow.getRecordSize());
         //DBGLOG("Source record size is %d", (int) sourceRow.getRecordSize());
         size32_t expectedSize = sourceRow.getRecordSize() - fixedDelta;
         size32_t expectedSize = sourceRow.getRecordSize() - fixedDelta;
         //DBGLOG("Source record size without omitted fixed size fields is %d", expectedSize);
         //DBGLOG("Source record size without omitted fixed size fields is %d", expectedSize);
-        ForEachItemIn(i, unmatched)
+        ForEachItemIn(i, variableUnmatched)
         {
         {
-            unsigned fieldNo = unmatched.item(i);
+            unsigned fieldNo = variableUnmatched.item(i);
             expectedSize -= sourceRow.getSize(fieldNo);
             expectedSize -= sourceRow.getSize(fieldNo);
             //DBGLOG("Reducing estimated size by %d to %d for omitted field %d (%s)", (int) sourceRow.getSize(fieldNo), expectedSize, fieldNo, sourceRecInfo.queryName(fieldNo));
             //DBGLOG("Reducing estimated size by %d to %d for omitted field %d (%s)", (int) sourceRow.getSize(fieldNo), expectedSize, fieldNo, sourceRecInfo.queryName(fieldNo));
         }
         }

+ 5 - 4
thorlcr/activities/keyedjoin/thkeyedjoinslave.cpp

@@ -2149,8 +2149,8 @@ class CKeyedJoinSlave : public CSlaveActivity, implements IJoinProcessor
         if (partToSlaveMap.size())
         if (partToSlaveMap.size())
         {
         {
             slave = partToSlaveMap[partNo];
             slave = partToSlaveMap[partNo];
-            if (NotFound == slave) // part not local to cluster, part is handled locally. 'slave' only used for max (see below).
-                slave = 0;
+            if (NotFound == slave) // part not local to cluster, part is handled locally/directly.
+                slave = handlerCounts.size()-1; // last one reserved for out of cluster part handling.
         }
         }
         unsigned max = queryMaxHandlers(hType);
         unsigned max = queryMaxHandlers(hType);
         unsigned &handlerCount = handlerCounts[slave];
         unsigned &handlerCount = handlerCounts[slave];
@@ -2222,12 +2222,13 @@ class CKeyedJoinSlave : public CSlaveActivity, implements IJoinProcessor
             std::vector<unsigned> slaveHandlersRR;
             std::vector<unsigned> slaveHandlersRR;
             bool remoteLookup = partToSlaveMap.size()>0;
             bool remoteLookup = partToSlaveMap.size()>0;
             unsigned slaves = remoteLookup ? queryJob().querySlaves() : 1; // if no map, all parts are treated as if local
             unsigned slaves = remoteLookup ? queryJob().querySlaves() : 1; // if no map, all parts are treated as if local
-            for (unsigned s=0; s<slaves; s++)
+            unsigned numHandlers = slaves+1; // +1 is for off cluster parts, which will be handled by local/direct handlers
+            for (unsigned s=0; s<numHandlers; s++)
             {
             {
                 handlerCounts.push_back(0);
                 handlerCounts.push_back(0);
                 slaveHandlersRR.push_back(0);
                 slaveHandlersRR.push_back(0);
             }
             }
-            slaveHandlers.resize(slaves);
+            slaveHandlers.resize(numHandlers);
 
 
             unsigned currentPart = 0;
             unsigned currentPart = 0;
             unsigned p = 0;
             unsigned p = 0;

+ 1 - 1
thorlcr/activities/soapcall/thsoapcallslave.cpp

@@ -28,7 +28,7 @@ static StringBuffer &buildAuthToken(IUserDescriptor *userDesc, StringBuffer &aut
     userDesc->getUserName(uidpair);
     userDesc->getUserName(uidpair);
     uidpair.append(":");
     uidpair.append(":");
     userDesc->getPassword(uidpair);
     userDesc->getPassword(uidpair);
-    JBASE64_Encode(uidpair.str(), uidpair.length(), authToken);
+    JBASE64_Encode(uidpair.str(), uidpair.length(), authToken, false);
     return authToken;
     return authToken;
 }
 }
 
 

+ 2 - 0
thorlcr/slave/slavmain.cpp

@@ -360,6 +360,8 @@ class CKJService : public CSimpleInterfaceOf<IKJService>, implements IThreaded,
                     if (!translator->canTranslate())
                     if (!translator->canTranslate())
                         throw MakeStringException(0, "Untranslatable record layout mismatch detected for: %s", tracing);
                         throw MakeStringException(0, "Untranslatable record layout mismatch detected for: %s", tracing);
                 }
                 }
+                DBGLOG("Record layout translator created for %s", tracing);
+                translator->describe();
                 dbgassertex(translator->canTranslate());
                 dbgassertex(translator->canTranslate());
             }
             }
             return translator;
             return translator;