瀏覽代碼

Merge branch 'candidate-7.12.x'

Signed-off-by: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 4 年之前
父節點
當前提交
c64f9ed72b
共有 100 個文件被更改,包括 759 次插入514 次删除
  1. 3 0
      .gitmodules
  2. 6 0
      common/thorhelper/persistent.cpp
  3. 22 8
      dali/server/daldap.cpp
  4. 1 0
      dali/server/daldap.hpp
  5. 60 11
      dali/server/daserver.cpp
  6. 1 1
      dockerfiles/platform-core-debug/esp.xml
  7. 1 1
      dockerfiles/platform-core/esp.xml
  8. 12 3
      docs/EN_US/ECLLanguageReference/ECLR_mods/Basics-Constants.xml
  9. 22 3
      ecl/hqlcpp/hqlckey.cpp
  10. 2 1
      esp/applications/common/CMakeLists.txt
  11. 24 0
      esp/applications/common/ldap/CMakeLists.txt
  12. 26 0
      esp/applications/common/ldap/azure_ldap.yaml
  13. 0 0
      esp/applications/common/ldap/ldap.yaml
  14. 5 0
      esp/applications/eclservices/eclservices.yaml
  15. 5 0
      esp/applications/eclwatch/eclwatch.yaml
  16. 1 1
      esp/bindings/http/platform/httpbinding.cpp
  17. 55 15
      esp/bindings/http/platform/httpprot.cpp
  18. 10 1
      esp/bindings/http/platform/httpprot.hpp
  19. 7 0
      esp/bindings/http/platform/httpservice.hpp
  20. 4 0
      esp/bindings/http/platform/httptransport.ipp
  21. 113 146
      esp/files/Login.html
  22. 17 3
      esp/platform/application_config.cpp
  23. 1 1
      esp/platform/espp.cpp
  24. 9 3
      esp/platform/espthread.cpp
  25. 7 1
      esp/platform/espthread.hpp
  26. 4 35
      esp/services/ws_dfu/ws_dfuService.cpp
  27. 2 16
      esp/services/ws_fs/ws_fsService.cpp
  28. 1 0
      esp/services/ws_sql/CMakeLists.txt
  29. 1 0
      esp/services/ws_workunits/CMakeLists.txt
  30. 5 10
      esp/services/ws_workunits/ws_workunitsHelpers.cpp
  31. 3 18
      esp/services/ws_workunits/ws_workunitsService.cpp
  32. 0 1
      esp/services/ws_workunits/ws_workunitsService.hpp
  33. 26 0
      esp/smc/SMCLib/LogicFileWrapper.cpp
  34. 5 0
      esp/smc/SMCLib/LogicFileWrapper.hpp
  35. 1 0
      esp/src/.gitignore
  36. 1 2
      esp/src/CMakeLists.txt
  37. 4 3
      esp/src/eclwatch/ActivityWidget.js
  38. 4 3
      esp/src/eclwatch/ClusterProcessesQueryWidget.js
  39. 4 3
      esp/src/eclwatch/CurrentUserDetailsWidget.js
  40. 4 3
      esp/src/eclwatch/DFUQueryWidget.js
  41. 1 0
      esp/src/eclwatch/DFUSearchWidget.js
  42. 4 3
      esp/src/eclwatch/DFUWUDetailsWidget.js
  43. 1 0
      esp/src/eclwatch/DelayLoadWidget.js
  44. 4 3
      esp/src/eclwatch/DiskUsageDetails.js
  45. 4 3
      esp/src/eclwatch/DiskUsageWidget.js
  46. 4 3
      esp/src/eclwatch/DynamicESDLDefinitionDetailsWidget.js
  47. 4 3
      esp/src/eclwatch/DynamicESDLDefinitionQueryWidget.js
  48. 4 3
      esp/src/eclwatch/DynamicESDLDetailsWidget.js
  49. 4 3
      esp/src/eclwatch/DynamicESDLMethodWidget.js
  50. 4 3
      esp/src/eclwatch/DynamicESDLQueryWidget.js
  51. 1 0
      esp/src/eclwatch/ECLPlaygroundResultsWidget.js
  52. 4 3
      esp/src/eclwatch/ECLPlaygroundWidget.js
  53. 4 3
      esp/src/eclwatch/ECLSourceWidget.js
  54. 4 3
      esp/src/eclwatch/EventScheduleWorkunitWidget.js
  55. 4 3
      esp/src/eclwatch/FileBelongsToWidget.js
  56. 4 3
      esp/src/eclwatch/FileBloomsWidget.js
  57. 4 3
      esp/src/eclwatch/FileHistoryWidget.js
  58. 4 3
      esp/src/eclwatch/FilePartsWidget.js
  59. 4 3
      esp/src/eclwatch/FileProtectListWidget.js
  60. 5 4
      esp/src/eclwatch/FilterDropDownWidget.js
  61. 4 3
      esp/src/eclwatch/FullResultWidget.js
  62. 4 3
      esp/src/eclwatch/GetDFUWorkunitsWidget.js
  63. 4 3
      esp/src/eclwatch/GetNumberOfFilesToCopyWidget.js
  64. 4 3
      esp/src/eclwatch/GraphPageWidget.js
  65. 4 3
      esp/src/eclwatch/GraphWidget.js
  66. 1 0
      esp/src/eclwatch/GraphsLFWidget.js
  67. 1 0
      esp/src/eclwatch/GraphsQueryWidget.js
  68. 1 0
      esp/src/eclwatch/GraphsWUWidget.js
  69. 4 3
      esp/src/eclwatch/GraphsWidget.js
  70. 4 3
      esp/src/eclwatch/GridDetailsWidget.js
  71. 4 3
      esp/src/eclwatch/GroupDetailsWidget.js
  72. 4 3
      esp/src/eclwatch/HPCCPlatformECLWidget.js
  73. 4 3
      esp/src/eclwatch/HPCCPlatformFilesWidget.js
  74. 4 3
      esp/src/eclwatch/HPCCPlatformMainWidget.js
  75. 4 3
      esp/src/eclwatch/HPCCPlatformOpsWidget.js
  76. 4 3
      esp/src/eclwatch/HPCCPlatformRoxieWidget.js
  77. 4 3
      esp/src/eclwatch/HPCCPlatformServicesPluginWidget.js
  78. 64 64
      esp/src/eclwatch/HPCCPlatformWidget.js
  79. 4 3
      esp/src/eclwatch/HelpersWidget.js
  80. 4 3
      esp/src/eclwatch/HexViewWidget.js
  81. 4 3
      esp/src/eclwatch/IFrameWidget.js
  82. 4 3
      esp/src/eclwatch/InfoGridWidget.js
  83. 3 3
      esp/src/eclwatch/JSGraphWidget.js
  84. 4 3
      esp/src/eclwatch/LFDetailsWidget.js
  85. 4 3
      esp/src/eclwatch/LZBrowseWidget.js
  86. 4 3
      esp/src/eclwatch/LibrariesUsedWidget.js
  87. 4 3
      esp/src/eclwatch/LockDialogWidget.js
  88. 4 3
      esp/src/eclwatch/LogVisualizationWidget.js
  89. 4 3
      esp/src/eclwatch/LogWidget.js
  90. 4 3
      esp/src/eclwatch/MachineInformationWidget.js
  91. 4 3
      esp/src/eclwatch/MemberOfWidget.js
  92. 4 3
      esp/src/eclwatch/MembersWidget.js
  93. 4 3
      esp/src/eclwatch/MonitoringWidget.js
  94. 4 3
      esp/src/eclwatch/PackageMapDetailsWidget.js
  95. 4 3
      esp/src/eclwatch/PackageMapPartsWidget.js
  96. 4 3
      esp/src/eclwatch/PackageMapQueryWidget.js
  97. 4 3
      esp/src/eclwatch/PackageMapValidateContentWidget.js
  98. 6 4
      esp/src/eclwatch/PackageMapValidateWidget.js
  99. 4 2
      esp/src/eclwatch/PackageSourceWidget.js
  100. 0 0
      esp/src/eclwatch/PermissionsWidget.js

+ 3 - 0
.gitmodules

@@ -58,3 +58,6 @@
 [submodule "plugins/spark/spark-plugin-java-packages"]
 	path = plugins/spark/spark-plugin-java-packages
 	url = https://github.com/hpcc-systems/spark-plugin-java-packages.git
+[submodule "system/security/plugins/jwtSecurity/jwt-cpp"]
+	path = system/security/plugins/jwtSecurity/jwt-cpp
+	url = https://github.com/hpcc-systems/jwt-cpp.git

+ 6 - 0
common/thorhelper/persistent.cpp

@@ -368,6 +368,12 @@ public:
             if (!ignore)
                 m_notify->notifySelected(sock, selected, this, reachedQuota);
         }
+        else
+        {
+            PERSILOG(PersistentLogLevel::PLogNormal, "PERSISTENT: Unexpected data received on connection %d, so discard the connection.", sock->OShandle());
+            remove(sock);
+        }
+
         return false;
     }
 

+ 22 - 8
dali/server/daldap.cpp

@@ -32,6 +32,7 @@ using namespace cryptohelper;
 
 #ifndef _NO_LDAP
 #include "seclib.hpp"
+#include "secloader.hpp"
 #include "ldapsecurity.hpp"
 
 static void ignoreSigPipe()
@@ -73,7 +74,7 @@ class CDaliLdapConnection: implements IDaliLdapConnection, public CInterface
         catch (IException *e) {
             EXCLOG(e,"LDAP createDefaultScopes");
             throw;
-        }   
+        }
     }
 
 
@@ -115,7 +116,7 @@ public:
                 catch (IException *e) {
                     EXCLOG(e,"LDAP server");
                     throw;
-                }   
+                }
                 createDefaultScopes();
             }
         }
@@ -124,11 +125,11 @@ public:
 
     SecAccessFlags getPermissions(const char *key,const char *obj,IUserDescriptor *udesc,unsigned auditflags)
     {
-        if (!ldapsecurity||((getLDAPflags()&DLF_ENABLED)==0)) 
+        if (!ldapsecurity||((getLDAPflags()&DLF_ENABLED)==0))
             return SecAccess_Full;
         StringBuffer username;
         StringBuffer password;
-        if (udesc) 
+        if (udesc)
         {
             udesc->getUserName(username);
             udesc->getPassword(password);
@@ -163,16 +164,16 @@ public:
 
             unsigned taken = msTick()-start;
 #ifndef _DEBUG
-            if (taken>100) 
+            if (taken>100)
 #endif
             {
                 PROGLOG("LDAP: getPermissions(%s) scope=%s user=%s returns %d in %d ms",key?key:"NULL",obj?obj:"NULL",username.str(),perm,taken);
             }
             if (auditflags&DALI_LDAP_AUDIT_REPORT) {
                 StringBuffer auditstr;
-                if ((auditflags&DALI_LDAP_READ_WANTED)&&!HASREADPERMISSION(perm)) 
+                if ((auditflags&DALI_LDAP_READ_WANTED)&&!HASREADPERMISSION(perm))
                     auditstr.append("Lookup Access Denied");
-                else if ((auditflags&DALI_LDAP_WRITE_WANTED)&&!HASWRITEPERMISSION(perm)) 
+                else if ((auditflags&DALI_LDAP_WRITE_WANTED)&&!HASWRITEPERMISSION(perm))
                     auditstr.append("Create Access Denied");
                 if (auditstr.length()) {
                     auditstr.append(":\n\tProcess:\tdaserver");
@@ -262,7 +263,7 @@ public:
     {
         return ldapflags;
     }
-    
+
     void setLDAPflags(unsigned flags)
     {
         ldapflags = flags;
@@ -272,6 +273,19 @@ public:
 };
 
 
+IDaliLdapConnection *createDaliSecMgrPluginConnection(IPropertyTree *propTree)
+{
+    if (propTree && propTree->hasProp("@type"))
+    {
+        IPropertyTree* secMgrCfg = propTree->queryPropTree(propTree->queryProp("@type"));
+        return SecLoader::loadPluggableSecManager<IDaliLdapConnection>("dali", propTree, secMgrCfg);
+    }
+    else
+    {
+        return nullptr;
+    }
+}
+
 IDaliLdapConnection *createDaliLdapConnection(IPropertyTree *proptree)
 {
     return new CDaliLdapConnection(proptree);

+ 1 - 0
dali/server/daldap.hpp

@@ -34,6 +34,7 @@ interface IDaliLdapConnection: extends IInterface
     virtual bool enableScopeScans(IUserDescriptor *udesc, bool enable, int *err) = 0;
 };
 
+extern IDaliLdapConnection *createDaliSecMgrPluginConnection(IPropertyTree *proptree);
 extern IDaliLdapConnection *createDaliLdapConnection(IPropertyTree *proptree);
 
 

+ 60 - 11
dali/server/daserver.cpp

@@ -126,7 +126,7 @@ bool actionOnAbort()
 {
     stopServer();
     return true;
-} 
+}
 
 USE_JLIB_ALLOC_HOOK;
 
@@ -139,6 +139,46 @@ void usage(void)
     printf("--daemon|-d <instanceName>\t: run daemon as instance\n");
 }
 
+static IPropertyTree *getSecMgrPluginPropTree(const IPropertyTree *configTree)
+{
+    Owned<IPropertyTree> foundTree;
+
+#ifdef _CONTAINERIZED
+    // TODO
+#else
+    Owned<IRemoteConnection> conn = querySDS().connect("/Environment", 0, 0, INFINITE);
+
+    if (conn)
+    {
+        const IPropertyTree *proptree = conn->queryRoot()->queryPropTree("Software/DaliServerProcess[1]");
+
+        if (proptree)
+        {
+            const char* authMethod = proptree->queryProp("@authMethod");
+
+            if (strisame(authMethod, "secmgrPlugin"))
+            {
+                const char* authPluginType = proptree->queryProp("@authPluginType");
+
+                if (authPluginType)
+                {
+                    VStringBuffer xpath("SecurityManagers/SecurityManager[@name='%s']", authPluginType);
+
+                    foundTree.setown(configTree->getPropTree(xpath));
+
+                    if (!foundTree.get())
+                    {
+                        WARNLOG("secmgPlugin '%s' not defined in configuration", authPluginType);
+                    }
+                }
+            }
+        }
+    }
+#endif
+
+    return foundTree.getClear();
+}
+
 /* NB: Ideally this belongs within common/environment,
  * however, that would introduce a circular dependency.
  */
@@ -387,7 +427,7 @@ int main(int argc, const char* argv[])
         Owned<IFile> sentinelFile = createSentinelTarget();
         removeSentinelFile(sentinelFile);
 #ifndef _CONTAINERIZED
-	
+
         for (unsigned i=1;i<(unsigned)argc;i++) {
             if (streq(argv[i],"--daemon") || streq(argv[i],"-d")) {
                 if (daemon(1,0) || write_pidfile(argv[++i])) {
@@ -449,10 +489,10 @@ int main(int argc, const char* argv[])
             }
         }
         // JCSMORE remoteBackupLocation should not be a property of SDS section really.
-        if (!getConfigurationDirectory(serverConfig->queryPropTree("Directories"),"mirror","dali",serverConfig->queryProp("@name"),mirrorPath)) 
+        if (!getConfigurationDirectory(serverConfig->queryPropTree("Directories"),"mirror","dali",serverConfig->queryProp("@name"),mirrorPath))
             serverConfig->getProp("SDS/@remoteBackupLocation",mirrorPath);
 
-#endif            
+#endif
         if (dataPath.length())
         {
             addPathSepChar(dataPath); // ensures trailing path separator
@@ -508,8 +548,8 @@ int main(int argc, const char* argv[])
                         if (mirrorPath.length()<=2 || !isPathSepChar(mirrorPath.charAt(0)) || !isPathSepChar(mirrorPath.charAt(1)))
                             rfn.setLocalPath(mirrorPath.str());
                         else
-                            rfn.setRemotePath(mirrorPath.str());                
-                        
+                            rfn.setRemotePath(mirrorPath.str());
+
                         if (!rfn.getPort() && !rfn.isLocal())
                         {
                             StringBuffer mountPoint;
@@ -545,7 +585,7 @@ int main(int argc, const char* argv[])
                         OwnedIFile iFileBackup = createIFile(backupCheck.str());
                         if (iFileBackup->exists())
                         {
-                            PROGLOG("remoteBackupLocation and dali data path point to same location! : %s", mirrorPath.str()); 
+                            PROGLOG("remoteBackupLocation and dali data path point to same location! : %s", mirrorPath.str());
                             iFileDataDir->remove();
                             return 0;
                         }
@@ -619,10 +659,10 @@ int main(int argc, const char* argv[])
 #ifndef _CONTAINERIZED
         setMsgLevel(fileMsgHandler, serverConfig->getPropInt("SDS/@msgLevel", 100));
 #endif
-        startLogMsgChildReceiver(); 
+        startLogMsgChildReceiver();
         startLogMsgParentReceiver();
 
-        IGroup *group = createIGroup(epa); 
+        IGroup *group = createIGroup(epa);
         initCoven(group,serverConfig);
         group->Release();
         epa.kill();
@@ -641,7 +681,7 @@ int main(int argc, const char* argv[])
             auditDir.set(lf->queryLogDir());
         }
 
-// SNMP logging     
+// SNMP logging
         bool enableSNMP = serverConfig->getPropBool("SDS/@enableSNMP");
         if (serverConfig->getPropBool("SDS/@enableSysLog",true))
             UseSysLogForOperatorMessages();
@@ -675,7 +715,16 @@ int main(int argc, const char* argv[])
         }
         try {
 #ifndef _NO_LDAP
-            setLDAPconnection(createDaliLdapConnection(serverConfig->getPropTree("Coven/ldapSecurity")));
+            Owned<IPropertyTree> secMgrPropTree = getSecMgrPluginPropTree(serverConfig);
+
+            if (secMgrPropTree.get())
+            {
+                setLDAPconnection(createDaliSecMgrPluginConnection(secMgrPropTree));
+            }
+            else
+            {
+                setLDAPconnection(createDaliLdapConnection(serverConfig->getPropTree("Coven/ldapSecurity")));
+            }
 #endif
         }
         catch (IException *e) {

+ 1 - 1
dockerfiles/platform-core-debug/esp.xml

@@ -62,7 +62,7 @@
       <EspBinding name="ws_esdlconfig_myespsmc_myesp" service="ws_esdlconfig_EclWatch_myesp" protocol="http" type="ws_esdlconfigSoapBinding" plugin="ws_esdlconfig" netAddress="0.0.0.0" port="8010" wsdlServiceAddress="" defaultServiceVersion=""/>
       <EspService name="ws_elk_EclWatch_myesp" type="ws_elk" plugin="ws_elk"><ELKIntegration><Kibana/><ElasticSearch/><LogStash/></ELKIntegration></EspService>
       <EspBinding name="ws_elk_myespsmc_myesp" service="ws_elk_EclWatch_myesp" protocol="http" type="ws_elkSoapBinding" plugin="ws_elk" netAddress="0.0.0.0" port="8010" wsdlServiceAddress="" defaultServiceVersion=""/>
-      <EspService name="ws_store_EclWatch_myesp" type="ws_store" plugin="ws_store"><StoreProvider lib="dalistorelib"/><Stores><Store description="Generic KeyVal store for HPCC Applications" name="HPCCApps" default="true"/></Stores></EspService>
+      <EspService name="ws_store_EclWatch_myesp" type="ws_store" plugin="ws_store"><StoreProvider lib="dalistorelib"/><Stores><Store description="Generic KeyVal store for HPCC Applications" name="HPCCApps" default="true"/><Store description="JWT token cache" name="JWTAuth" default="false" maxValSize="32768"/></Stores></EspService>
       <EspBinding name="ws_store_myespsmc_myesp" service="ws_store_EclWatch_myesp" protocol="http" type="ws_storeSoapBinding" plugin="ws_store" netAddress="0.0.0.0" port="8010" wsdlServiceAddress="" defaultServiceVersion=""/>
       <EspService name="ws_codesign_EclWatch_myesp" type="ws_codesign" plugin="ws_codesign"/>
       <EspBinding name="ws_codesign_myespsmc_myesp" service="ws_codesign_EclWatch_myesp" protocol="http" type="ws_codesignSoapBinding" plugin="ws_codesign" netAddress="0.0.0.0" port="8010" wsdlServiceAddress="" defaultServiceVersion=""/>

+ 1 - 1
dockerfiles/platform-core/esp.xml

@@ -62,7 +62,7 @@
       <EspBinding name="ws_esdlconfig_myespsmc_myesp" service="ws_esdlconfig_EclWatch_myesp" protocol="http" type="ws_esdlconfigSoapBinding" plugin="ws_esdlconfig" netAddress="0.0.0.0" port="8010" wsdlServiceAddress="" defaultServiceVersion=""/>
       <EspService name="ws_elk_EclWatch_myesp" type="ws_elk" plugin="ws_elk"><ELKIntegration><Kibana/><ElasticSearch/><LogStash/></ELKIntegration></EspService>
       <EspBinding name="ws_elk_myespsmc_myesp" service="ws_elk_EclWatch_myesp" protocol="http" type="ws_elkSoapBinding" plugin="ws_elk" netAddress="0.0.0.0" port="8010" wsdlServiceAddress="" defaultServiceVersion=""/>
-      <EspService name="ws_store_EclWatch_myesp" type="ws_store" plugin="ws_store"><StoreProvider lib="dalistorelib"/><Stores><Store description="Generic KeyVal store for HPCC Applications" name="HPCCApps" default="true"/></Stores></EspService>
+      <EspService name="ws_store_EclWatch_myesp" type="ws_store" plugin="ws_store"><StoreProvider lib="dalistorelib"/><Stores><Store description="Generic KeyVal store for HPCC Applications" name="HPCCApps" default="true"/><Store description="JWT token cache" name="JWTAuth" default="false" maxValSize="32768"/></Stores></EspService>
       <EspBinding name="ws_store_myespsmc_myesp" service="ws_store_EclWatch_myesp" protocol="http" type="ws_storeSoapBinding" plugin="ws_store" netAddress="0.0.0.0" port="8010" wsdlServiceAddress="" defaultServiceVersion=""/>
       <EspService name="ws_codesign_EclWatch_myesp" type="ws_codesign" plugin="ws_codesign"/>
       <EspBinding name="ws_codesign_myespsmc_myesp" service="ws_codesign_EclWatch_myesp" protocol="http" type="ws_codesignSoapBinding" plugin="ws_codesign" netAddress="0.0.0.0" port="8010" wsdlServiceAddress="" defaultServiceVersion=""/>

+ 12 - 3
docs/EN_US/ECLLanguageReference/ECLR_mods/Basics-Constants.xml

@@ -134,23 +134,32 @@ MyUnicodeString3 := U'abcd\u00EB'; // becomes 'abcdë'«'</programlisting>
     INTEGER<indexterm>
         <primary>INTEGER</primary>
       </indexterm> (see <emphasis role="bold">Value Types</emphasis>). Integer
-    constants may be decimal, hexadecimal, or binary values.
+    constants may be decimal, unsigned, hexadecimal, or binary values.
     Hexadecimal<indexterm>
         <primary>Hexadecimal</primary>
       </indexterm> values are specified with either a leading "0x" or a
     trailing "x" character. Binary values<indexterm>
         <primary>Binary values</primary>
       </indexterm> are specified with either a leading "0b" or a trailing "b"
-    character.</para>
+    character. Decimal values <indexterm>
+        <primary>Decimal values</primary>
+      </indexterm>are specified with trailing "d" character. Unsigned values
+    <indexterm>
+        <primary>Unsigned values</primary>
+      </indexterm>are specified with a trailing "u" character.</para>
 
     <programlisting>MyInt1  := 10;     // value of MyInt1 is the INTEGER value 10
 MyInt2  := 0x0A;   // value of MyInt2 is the INTEGER value 10
 MyInt3  := 0Ax;    // value of MyInt3 is the INTEGER value 10
 MyInt4  := 0b1010; // value of MyInt4 is the INTEGER value 10
 MyInt5  := 1010b;  // value of MyInt5 is the INTEGER value 10
+MyUint  := 10u     // value of MyUint is the UNSIGNED value 10
 MyReal1 := 10.0;   // value of MyReal1 is the REAL value 10.0
 MyReal2 := 1.0e1;  // value of MyReal2 is the REAL value 10.0
-</programlisting>
+MyDec1  := 10d     // value of MyDec1 is the DECIMAL value 10
+MyDec2  := 3.14159265358979323846d // value of MyDec2 is the DECIMAL
+                                   // value 3.14159265358979323846
+                                   // a REAL type would lose precision </programlisting>
   </sect2>
 
   <sect2 id="CompileTimeConstants" role="brk">

+ 22 - 3
ecl/hqlcpp/hqlckey.cpp

@@ -171,6 +171,7 @@ protected:
     IHqlExpression * createKeyFromComplexKey(IHqlExpression * expr);
     IHqlExpression * expandDatasetReferences(IHqlExpression * expr, IHqlExpression * ds);
     IHqlExpression * optimizeTransfer(HqlExprArray & fields, HqlExprArray & values, IHqlExpression * expr, IHqlExpression * leftSelector);
+    IHqlExpression * doOptimizeTransfer(HqlExprArray & fields, HqlExprArray & values, IHqlExpression * expr, IHqlExpression * leftSelector);
     void optimizeExtractJoinFields();
     void optimizeTransfer(SharedHqlExpr & targetDataset, SharedHqlExpr & targetTransform, SharedHqlExpr & keyedFilter, OwnedHqlExpr * extraFilter);
     IHqlExpression * querySimplifiedKey(IHqlExpression * expr);
@@ -677,6 +678,20 @@ static bool fieldNameAlreadyExists(const HqlExprArray & fields, IAtom * name)
 
 IHqlExpression * KeyedJoinInfo::optimizeTransfer(HqlExprArray & fields, HqlExprArray & values, IHqlExpression * filter, IHqlExpression * leftSelector)
 {
+    TransformMutexBlock block;
+    return doOptimizeTransfer(fields, values, filter, leftSelector);
+}
+
+IHqlExpression * KeyedJoinInfo::doOptimizeTransfer(HqlExprArray & fields, HqlExprArray & values, IHqlExpression * filter, IHqlExpression * leftSelector)
+{
+    IHqlExpression * prev = static_cast<IHqlExpression *>(filter->queryTransformExtra());
+    if (prev)
+        return LINK(prev);
+
+    //MORE: We could also check if already transformed..., but that imposes an additional cost on simple filters, so on balance it is better without it
+    //if (!filter->usesSelector(leftSelector))
+    //    return LINK(filter);
+
     switch (filter->getOperator())
     {
     case no_join:
@@ -723,7 +738,9 @@ IHqlExpression * KeyedJoinInfo::optimizeTransfer(HqlExprArray & fields, HqlExprA
                 IHqlExpression * matchField = &fields.item(match);
                 OwnedHqlExpr serializedField = getSerializedForm(matchField, diskAtom);
                 OwnedHqlExpr result = createSelectExpr(getActiveTableSelector(), LINK(serializedField));
-                return ensureDeserialized(result, matchField->queryType(), diskAtom);
+                OwnedHqlExpr deserialized = ensureDeserialized(result, matchField->queryType(), diskAtom);
+                filter->setTransformExtra(deserialized);
+                return deserialized.getClear();
             }
             break;
         }
@@ -736,11 +753,13 @@ IHqlExpression * KeyedJoinInfo::optimizeTransfer(HqlExprArray & fields, HqlExprA
     HqlExprArray children;
     ForEachChild(i, filter)
     {
-        IHqlExpression * next = optimizeTransfer(fields, values, filter->queryChild(i), leftSelector);
+        IHqlExpression * next = doOptimizeTransfer(fields, values, filter->queryChild(i), leftSelector);
         if (!next) return NULL;
         children.append(*next);
     }
-    return cloneOrLink(filter, children);
+    OwnedHqlExpr ret = cloneOrLink(filter, children);
+    filter->setTransformExtra(ret);
+    return ret.getClear();
 }
 
 

+ 2 - 1
esp/applications/common/CMakeLists.txt

@@ -15,10 +15,11 @@
 ################################################################################
 
 set ( ESP_APPLICATION_FILES
-    ${CMAKE_CURRENT_SOURCE_DIR}/ldap.yaml
     ${CMAKE_CURRENT_SOURCE_DIR}/directories.yaml
 )
 
 FOREACH( iFile ${ESP_APPLICATION_FILES} )
     Install( FILES ${iFile} DESTINATION componentfiles/applications/common COMPONENT Runtime )
 ENDFOREACH ( iFile )
+
+HPCC_ADD_SUBDIRECTORY (ldap)

+ 24 - 0
esp/applications/common/ldap/CMakeLists.txt

@@ -0,0 +1,24 @@
+################################################################################
+#    HPCC SYSTEMS software Copyright (C) 2020 HPCC Systems®.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+################################################################################
+
+set ( ESP_LDAP_FILES
+    ${CMAKE_CURRENT_SOURCE_DIR}/ldap.yaml
+    ${CMAKE_CURRENT_SOURCE_DIR}/azure_ldap.yaml
+)
+
+FOREACH( iFile ${ESP_LDAP_FILES} )
+    Install( FILES ${iFile} DESTINATION componentfiles/applications/common/ldap COMPONENT Runtime )
+ENDFOREACH ( iFile )

+ 26 - 0
esp/applications/common/ldap/azure_ldap.yaml

@@ -0,0 +1,26 @@
+ldap:
+  objname: ldapserver
+  serverType: AzureActiveDirectory
+  description: LDAP server process
+  ldapProtocol: ldap
+  authMethod: kerberos
+  localDomain: localdomain
+  ldapPort: 389
+  ldapSecurePort: 636
+  systemCommonName: hpcc_admin2
+  systemPassword: ""
+  systemUser: hpcc_admin2
+  adminGroupName:
+  maxConnections: 10
+  passwordExpirationWarningDays: 10
+  cacheTimeout: 5
+  ldapTimeoutSecs: 131
+  sharedCache: true
+  checkViewPermissions: ''
+  filesBasedn: ou=files,ou=ecl
+  groupsBasedn: ou=AADDC Users
+  sudoersBasedn: ou=SUDOers
+  systemBasedn: ou=AADDC Users
+  usersBasedn: ou=AADDC Users
+  resourcesBasedn: ou=WsEcl,ou=EspServices,ou=ecl
+  workunitsBasedn: ou=workunits,ou=ecl

esp/applications/common/ldap.yaml → esp/applications/common/ldap/ldap.yaml


+ 5 - 0
esp/applications/eclservices/eclservices.yaml

@@ -60,6 +60,11 @@ eclservices:
          -  name: HPCCApps
             description: Generic KeyVal store for HPCC Applications
             default: true
+         Store:
+         -  name: JWTAuth
+            description: JWT token cache
+            default: false
+            maxValSize: 32768
    ws_machine:
       excludePartitions: "/dev*,/sys*,/proc*,/run*,/boot"
       monitorDaliFileServer: false

+ 5 - 0
esp/applications/eclwatch/eclwatch.yaml

@@ -58,6 +58,11 @@ eclwatch:
          -  name: HPCCApps
             description: Generic KeyVal store for HPCC Applications
             default: true
+         Store:
+         -  name: JWTAuth
+            description: JWT token cache
+            default: false
+            maxValSize: 32768
    ws_machine:
       excludePartitions: "/dev*,/sys*,/proc*,/run*,/boot"
       monitorDaliFileServer: false

+ 1 - 1
esp/bindings/http/platform/httpbinding.cpp

@@ -197,7 +197,7 @@ EspHttpBinding::EspHttpBinding(IPropertyTree* tree, const char *bindname, const
                 if (secMgrCfg)
                 {
                     //This is a Pluggable Security Manager
-                    m_secmgr.setown(SecLoader::loadPluggableSecManager(bindname, bnd_cfg, secMgrCfg));
+                    m_secmgr.setown(SecLoader::loadPluggableSecManager<ISecManager>(bindname, bnd_cfg, secMgrCfg));
                     m_authmap.setown(m_secmgr->createAuthMap(authcfg));
                     m_feature_authmap.setown(m_secmgr->createFeatureMap(authcfg));
                     m_setting_authmap.setown(m_secmgr->createSettingMap(authcfg));

+ 55 - 15
esp/bindings/http/platform/httpprot.cpp

@@ -475,10 +475,25 @@ bool CHttpThread::onRequest()
     time_t t = time(NULL);  
     initThreadLocal(sizeof(t), &t);
 
+    m_httpserver = httpserver;
+    httpserver->setSocketReturner(this);
     httpserver->setIsSSL(m_is_ssl);
     httpserver->setShouldClose(m_shouldClose);
     httpserver->processRequest();
 
+    returnSocket(false);
+
+    clearThreadLocal();
+
+    return false;
+}
+
+void CHttpThread::returnSocket(bool cascade)
+{
+    if (m_httpSocketReturned)
+        return;
+    m_httpSocketReturned = true;
+    CEspHttpServer* httpserver = dynamic_cast<CEspHttpServer*>(m_httpserver);
     if (m_persistentHandler == nullptr)
     {
         keepAlive = !m_shouldClose && m_apport->queryProtocol()->persistentEnabled() && httpserver->persistentEligible();
@@ -490,11 +505,15 @@ bool CHttpThread::onRequest()
         keepAlive = !m_shouldClose && httpserver->persistentEligible();
         m_persistentHandler->doneUsing(m_socket, keepAlive);
     }
-    clearThreadLocal();
 
-    return false;
+    if (cascade)
+        CEspProtocolThread::returnSocket();
 }
 
+void CHttpThread::returnSocket()
+{
+    returnSocket(true);
+}
 /**************************************************************************
  *  CPooledHttpThread Implementation                                      *
  **************************************************************************/
@@ -507,6 +526,9 @@ void CPooledHttpThread::init(void *param)
     m_ssctx = (ISecureSocketContext*)(((void**)param)[4]);
     m_persistentHandler = (IPersistentHandler*)(((void**)param)[5]);
     m_shouldClose = *(bool*)(((void**)param)[6]);
+    m_httpserver = nullptr;
+    m_processAborted = false;
+    m_socketReturned = false;
 }
 
 CPooledHttpThread::~CPooledHttpThread()
@@ -549,38 +571,57 @@ void CPooledHttpThread::threadmain()
     {
         httpserver.setown(new CEspHttpServer(*m_socket, m_apport, false, getMaxRequestEntityLength()));
     }
+    m_httpserver = httpserver;
     httpserver->setShouldClose(m_shouldClose);
+    httpserver->setSocketReturner(this);
     time_t t = time(NULL);  
     initThreadLocal(sizeof(t), &t);
-    bool keepAlive = false;
     try
     {
         ESP_TIME_SECTION("CPooledHttpThread::threadmain: httpserver->processRequest()");
         httpserver->processRequest();
-        if (m_persistentHandler == nullptr)
-        {
-            keepAlive = !m_shouldClose && m_apport->queryProtocol()->persistentEnabled() && httpserver->persistentEligible();
-            if (keepAlive)
-                m_apport->queryProtocol()->addPersistent(m_socket.get());
-        }
-        else
-        {
-            keepAlive = !m_shouldClose && httpserver->persistentEligible();
-            m_persistentHandler->doneUsing(m_socket, keepAlive);
-        }
     }
     catch (IException *e) 
     {
+        m_processAborted = true;
         StringBuffer estr;
         IERRLOG("Exception(%d, %s) in CPooledHttpThread::threadmain().", e->errorCode(), e->errorMessage(estr).str());
         e->Release();
     }
     catch(...)
     {
+        m_processAborted = true;
         IERRLOG("General Exception - in CPooledHttpThread::threadmain().");
     }
+
+    returnSocket();
+
     clearThreadLocal();
 
+}
+
+void CPooledHttpThread::returnSocket()
+{
+    if (m_socketReturned)
+        return;
+    m_socketReturned = true;
+    CEspHttpServer* httpserver = dynamic_cast<CEspHttpServer*>(m_httpserver);
+    bool keepAlive = false;
+    if (!m_processAborted)
+    {
+        if (m_persistentHandler == nullptr)
+        {
+            keepAlive = !m_shouldClose && m_apport->queryProtocol()->persistentEnabled() && httpserver->persistentEligible();
+            if (keepAlive)
+                m_apport->queryProtocol()->addPersistent(m_socket.get());
+        }
+        else
+        {
+            keepAlive = !m_shouldClose && httpserver->persistentEligible();
+            m_persistentHandler->doneUsing(m_socket, keepAlive);
+        }
+    }
+
     try
     {
         if (m_socket != nullptr)
@@ -600,5 +641,4 @@ void CPooledHttpThread::threadmain()
     {
         IERRLOG("General Exception - CPooledHttpThread::threadmain(), closing socket.");
     }
-
 }

+ 10 - 1
esp/bindings/http/platform/httpprot.hpp

@@ -38,7 +38,7 @@
 #include <map>
 using namespace std;
 
-class CPooledHttpThread : public CInterface, implements IPooledThread
+class CPooledHttpThread : public CInterface, implements IPooledThread, implements ISocketReturner
 {
 private:
     Owned<ISocket> m_socket;
@@ -49,6 +49,9 @@ private:
     ISecureSocketContext* m_ssctx;
     IPersistentHandler* m_persistentHandler = nullptr;
     bool m_shouldClose = false;
+    IHttpServerService* m_httpserver = nullptr;
+    bool m_socketReturned = false;
+    bool m_processAborted = false;
 public:
     IMPLEMENT_IINTERFACE;
 
@@ -63,6 +66,7 @@ public:
 
     virtual void setMaxRequestEntityLength(int len) {m_MaxRequestEntityLength = len;}
     virtual int getMaxRequestEntityLength() { return m_MaxRequestEntityLength; }
+    virtual void returnSocket();
 };
 
 class CHttpThreadPoolFactory : public CInterface, implements IThreadFactory
@@ -90,6 +94,10 @@ private:
     ISecureSocketContext* m_ssctx;
     IPersistentHandler* m_persistentHandler = nullptr;
     bool m_shouldClose = false;
+    IHttpServerService* m_httpserver = nullptr;
+    bool m_httpSocketReturned = false;
+    void returnSocket(bool cascade);
+
 public:
     CHttpThread(ISocket *sock, CEspApplicationPort* apport, bool viewConfig, bool isSSL = false, ISecureSocketContext* ssctx = NULL, IPersistentHandler* persistentHandler = NULL);
     
@@ -100,6 +108,7 @@ public:
     virtual int getMaxRequestEntityLength() { return m_MaxRequestEntityLength; }
 
     void setShouldClose(bool should) {m_shouldClose = should;}
+    virtual void returnSocket();
 };
 
 class esp_http_decl CHttpProtocol : public CEspProtocol

+ 7 - 0
esp/bindings/http/platform/httpservice.hpp

@@ -70,6 +70,7 @@ class CEspHttpServer : implements IHttpServerService, public CInterface
     bool isSSL = false;
     bool shouldClose = false;
     CriticalSection critDaliSession;
+    ISocketReturner* m_socketReturner = nullptr;
 protected:
     ISocket&                m_socket;
     Owned<CHttpRequest>     m_request;
@@ -160,6 +161,12 @@ public:
     bool persistentEligible();
     void setIsSSL(bool _isSSL) { isSSL = _isSSL; };
     void setShouldClose(bool should) { shouldClose = should; }
+    void setSocketReturner(ISocketReturner* returner)
+    {
+        m_socketReturner = returner;
+        m_request->setSocketReturner(returner);
+        m_response->setSocketReturner(returner);
+    }
 };
 
 

+ 4 - 0
esp/bindings/http/platform/httptransport.ipp

@@ -19,6 +19,7 @@
 #define _HTTPTRANSPORT_IPP__
 
 #include "esphttp.hpp"
+#include "espthread.hpp"
 
 //Jlib
 #include "jsocket.hpp"
@@ -87,6 +88,7 @@ protected:
     IArrayOf<CEspCookie> m_cookies;
 
     Owned<CMimeMultiPart> m_multipart;
+    ISocketReturner* m_socketReturner = nullptr;
 
     int parseOneHeader(char* oneline);
     virtual void parseCookieHeader(char* cookiestr);
@@ -275,6 +277,8 @@ public:
     virtual bool compressContent(StringBuffer* originalContent, int compressType) { return false; }
     virtual bool shouldDecompress(int& compressType) { return false; }
     virtual bool decompressContent(StringBuffer* originalContent, int compressType) { return false; }
+    virtual void setSocketReturner(ISocketReturner* returner) { m_socketReturner = returner; }
+    virtual ISocketReturner* querySocketReturner() { return m_socketReturner; }
 };
 
 

+ 113 - 146
esp/files/Login.html

@@ -1,153 +1,120 @@
 <!DOCTYPE html>
 <html>
-    <head>
-        <meta http-equiv="X-UA-Compatible" content="IE=edge"> 
-        <meta charset="UTF-8">
-        <title class="loginStr"></title>
-        <style type="text/css">
-            body {
-                font-family: Lucida Sans, Lucida Grande, Arial !important;
-                font-size: 15px !important;
-                background-color: #1A9BD7;
-            }
-
-            .container {
-                width: 99%;
-                position: absolute;
-                top: 50%;
-                transform: translateY(-50%);
-            }
-
-            .formContainer {
-                width: 500px;
-                padding: 20px 0 20px 0;
-                border-radius: 5px;
-                background-color: #fff;
-                margin: auto;
-            }
-
-            .login {
-                width: 400px;
-                margin: auto;
-            }
 
-            .login input {
-                margin-bottom: 20px;
-                width: 300px;
-                padding: 8px;
-                border: 1px solid #bfbfbf;
-            }
-
-            #hidden_msg{
-                display: none;
-                text-align: center;
-                margin-bottom: 20px;
-                width: 300px;
-		color:red;
-            }
-
-            .login form {
-                margin: auto;
-                width: 300px;
-            }
-
-            img {
-                display: block;
-                margin: auto;
-            }
-
-            p {
-                text-align: center
-            }
-
-            #button {
-                background-color: #1A9BD7;
-                border: none;
-                color: white;
-                padding: 15px 32px;
-                text-align: center;
-                text-decoration: none;
-                display: inline-block;
-                font-size: 16px;
-                border-radius: 4px;
-                cursor: pointer;
-                -webkit-transition-duration: 0.4s;
-                /* Safari */
-                transition-duration: 0.4s;
-                margin: auto;
-                display: block;
-            }
-
-            .button:hover {
-                background-color: #13b1f9;
-                color: white;
-            }
-
-            .visible {
-                display: none;
-            }
-        </style>
-        <script src="/esp/files/dist/dojoLib.eclwatch.js"></script>
-    </head>
-    <body>
-        <div id="container" class="container visible">
-            <div class="formContainer">
-                <img id="logo" src="eclwatch/img/Loginlogo.png" />
-                <p id="loginStr" class="loginStr"></p>
-                <div class="login">
-                    <form method="POST" action="/esp/login">
-                        <input id="username" type="text" name="username" placeholder="username" class="loginStr" autofocus></input>
-                        <input id="password" type="password" name="password" placeholder="password" class="loginStr"></input>
-                        <p id="hidden_msg" class="loginStr"></p>
-                        <button class="loginStr" id="button" type="submit"></button>
-                    </form>
-                </div>
+<head>
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta charset="UTF-8">
+    <title class="loginStr"></title>
+    <style type="text/css">
+        body {
+            font-family: Lucida Sans, Lucida Grande, Arial !important;
+            font-size: 15px !important;
+            background-color: #1A9BD7;
+        }
+
+        .container {
+            width: 99%;
+            position: absolute;
+            top: 50%;
+            transform: translateY(-50%);
+        }
+
+        .formContainer {
+            width: 500px;
+            padding: 20px 0 20px 0;
+            border-radius: 5px;
+            background-color: #fff;
+            margin: auto;
+        }
+
+        .login {
+            width: 400px;
+            margin: auto;
+        }
+
+        .login input {
+            margin-bottom: 20px;
+            width: 300px;
+            padding: 8px;
+            border: 1px solid #bfbfbf;
+        }
+
+        #hidden_msg {
+            display: none;
+            text-align: center;
+            margin-bottom: 20px;
+            width: 300px;
+            color: red;
+        }
+
+        .login form {
+            margin: auto;
+            width: 300px;
+        }
+
+        img {
+            display: block;
+            margin: auto;
+        }
+
+        p {
+            text-align: center
+        }
+
+        #button {
+            background-color: #1A9BD7;
+            border: none;
+            color: white;
+            padding: 15px 32px;
+            text-align: center;
+            text-decoration: none;
+            display: inline-block;
+            font-size: 16px;
+            border-radius: 4px;
+            cursor: pointer;
+            -webkit-transition-duration: 0.4s;
+            /* Safari */
+            transition-duration: 0.4s;
+            margin: auto;
+            display: block;
+        }
+
+        .button:hover {
+            background-color: #13b1f9;
+            color: white;
+        }
+
+        .visible {
+            display: none;
+        }
+    </style>
+    <script src="/esp/files/dist/dojoLib.eclwatch.js"></script>
+</head>
+
+<body>
+    <div id="container" class="container visible">
+        <div class="formContainer">
+            <img id="logo" src="eclwatch/img/Loginlogo.png" />
+            <p id="loginStr" class="loginStr"></p>
+            <div class="login">
+                <form method="POST" action="/esp/login">
+                    <input id="username" type="text" name="username" placeholder="username" class="loginStr"
+                        autofocus></input>
+                    <input id="password" type="password" name="password" placeholder="password"
+                        class="loginStr"></input>
+                    <p id="hidden_msg" class="loginStr"></p>
+                    <button class="loginStr" id="button" type="submit"></button>
+                </form>
             </div>
         </div>
-        <script type="text/javascript">
-            require(["dojo/ready", "dojo/i18n", "dojo/i18n!hpcc/nls/hpcc"],
-                function(ready, i18n, nlsHPCC){
-                    ready(function(){
-                        var loginStr = document.getElementById("loginStr");
-                        var error = document.getElementById("hidden_msg");
-                        var username = document.getElementById("username");
-                        var password = document.getElementById("password");
-                        var button = document.getElementById("button");
-                        var enableCookies = "";
-                        var HPCCSystems = document.getElementById("logo");
-
-                        loginStr.innerHTML = nlsHPCC.PleaseLogIntoECLWatch;
-                        error.innerHTML = nlsHPCC.InvalidUsernamePassword;
-                        username.innerHTML = nlsHPCC.Username;
-                        password.innerHTML = nlsHPCC.Password;
-                        button.innerHTML = nlsHPCC.Login;
-                        enableCookies = nlsHPCC.PleaseEnableCookies;
-                        HPCCSystems.setAttribute("alt", nlsHPCC.HPCCSystems);
-
-                        var element = document.getElementById('container');
-
-                        if (navigator.cookieEnabled) {
-                            var element = document.getElementById("container");
-                            element.classList.remove("visible");
-                        } else {
-                            alert(enableCookies);
-                        }
-
-                        function deleteCookie(cname, cvalue, exMins) {
-                            var d = new Date();
-                            d.setTime(d.getTime() + (exMins*60*1000));
-                            var expires = "expires="+d.toUTCString();
-                            document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
-                        }
+    </div>
+    <script type="text/javascript">
+        require([init],
+            function (init) {
+                init();
+            }
+        );
+    </script>
+</body>
 
-                        if (document.cookie.indexOf("ESPAuthenticationMSG") > -1){
-                            var element = document.getElementById('hidden_msg');
-                            element.style.display = "inline-block";
-                            deleteCookie('ESPAuthenticationMSG','',0);
-                        }
-                    });
-                }
-            );
-        </script>
-    </body>
 </html>

+ 17 - 3
esp/platform/application_config.cpp

@@ -29,6 +29,8 @@
 #include "espcontext.hpp"
 #include "build-config.h"
 
+enum class LdapType { LegacyAD, AzureAD };
+
 static void appendPTreeFromYamlFile(IPropertyTree *tree, const char *file)
 {
     Owned<IPropertyTree> appendTree = createPTreeFromYAMLFile(file);
@@ -88,11 +90,21 @@ static void copyDirectories(IPropertyTree *target, IPropertyTree *src)
     }
 }
 
-bool addLdapSecurity(IPropertyTree *legacyEsp, IPropertyTree *appEsp, StringBuffer &bindAuth)
+bool addLdapSecurity(IPropertyTree *legacyEsp, IPropertyTree *appEsp, StringBuffer &bindAuth, LdapType ldapType)
 {
     const char *ldapAddress = appEsp->queryProp("@ldapAddress");
     if (isEmptyString(ldapAddress))
         throw MakeStringException(-1, "LDAP not configured.  To run without security set auth=none");
+
+    StringBuffer path(COMPONENTFILES_DIR);
+    char sepchar = getPathSepChar(COMPONENTFILES_DIR);
+    addPathSepChar(path, sepchar).append("applications").append(sepchar).append("common").append(sepchar).append("ldap").append(sepchar);
+    if (ldapType == LdapType::LegacyAD)
+        path.append("ldap.yaml");
+    else
+        path.append("azure_ldap.yaml");
+    if (checkFileExists(path))
+        appendPTreeFromYamlFile(appEsp, path.str());
     IPropertyTree *appLdap = appEsp->queryPropTree("ldap");
     if (!appLdap)
         throw MakeStringException(-1, "Can't find application LDAP settings.  To run without security set auth=none");
@@ -155,14 +167,16 @@ bool addSecurity(IPropertyTree *legacyEsp, IPropertyTree *appEsp, StringBuffer &
     if (streq(auth, "none"))
         return false;
     if (streq(auth, "ldap"))
-        return addLdapSecurity(legacyEsp, appEsp, bindAuth);
+        return addLdapSecurity(legacyEsp, appEsp, bindAuth, LdapType::LegacyAD);
+    if (streq(auth, "azure_ldap"))
+        return addLdapSecurity(legacyEsp, appEsp, bindAuth, LdapType::AzureAD);
     return addAuthNZSecurity(auth, legacyEsp, appEsp, bindAuth);
 }
 
 void bindAuthResources(IPropertyTree *legacyAuthenticate, IPropertyTree *app, const char *service, const char *auth)
 {
     IPropertyTree *appAuth = nullptr;
-    if (isEmptyString(auth) || streq(auth, "ldap"))
+    if (isEmptyString(auth) || streq(auth, "ldap") || streq(auth, "azure_ldap"))
         appAuth = app->queryPropTree("ldap");
     else if (streq(auth, "none"))
         return;

+ 1 - 1
esp/platform/espp.cpp

@@ -331,7 +331,7 @@ static void usage()
     puts("  -?/-h: show this help page");
     puts("  --daliServers=<address>: set DALI address (defaults to dali)");
     puts("  --tls=<on/off>: enable using TLS secure communication (defaults to on)");
-    puts("  --auth=<ldap/none>: select authorization protocol (defaults to ldap)");
+    puts("  --auth=<ldap/azure_ldap/none>: select authorization protocol (defaults to ldap)");
     puts("  --ldapAddress=<address>: set LDAP server address");
     puts("  --config=<file.yaml>: specify a YAML config file, use to override default config values");
     puts("  --logDir=<file>: specify a file to write trace file information to, default is stderr");

+ 9 - 3
esp/platform/espthread.cpp

@@ -190,7 +190,16 @@ int CEspProtocolThread::run()
     {
         IERRLOG("Unknown Exception in CEspProtocolThread::run while processing request.");
     }
+    returnSocket();
+    Release();
+    return 0;
+}
 
+void CEspProtocolThread::returnSocket()
+{
+    if (m_socketReturned)
+        return;
+    m_socketReturned = true;
     if(!keepAlive)
     {
         try
@@ -209,7 +218,4 @@ int CEspProtocolThread::run()
             DBGLOG("General Exception - in CEspProtocolThread::run while closing socket.");
         }
     }
-    Release();
-    return 0;
 }
-

+ 7 - 1
esp/platform/espthread.hpp

@@ -20,8 +20,12 @@
 
 #define TERMINATE_EXITCODE -99 // the working process use it to tell the monitor to exit too.
 
+interface ISocketReturner
+{
+    virtual void returnSocket() = 0;
+};
 
-class CEspProtocolThread: public Thread
+class CEspProtocolThread: public Thread, implements ISocketReturner
 {
 protected:
    bool terminating;
@@ -36,6 +40,7 @@ protected:
 
     int run();
     bool keepAlive = false;
+    bool m_socketReturned = false;
 public:
     IMPLEMENT_IINTERFACE;
     
@@ -49,6 +54,7 @@ public:
    
    virtual const char *getServiceName();
    virtual bool onRequest();
+   virtual void returnSocket();
 };
 
 

+ 4 - 35
esp/services/ws_dfu/ws_dfuService.cpp

@@ -1823,14 +1823,7 @@ bool CWsDfuEx::onDFURecordTypeInfo(IEspContext &context, IEspDFURecordTypeInfoRe
             throw MakeStringException(ECLWATCH_MISSING_PARAMS, "File name required");
         PROGLOG("DFURecordTypeInfo file: %s", fileName);
 
-        const char* userId = context.queryUserId();
-        Owned<IUserDescriptor> userdesc;
-        if (userId && *userId)
-        {
-            userdesc.setown(createUserDescriptor());
-            userdesc->set(userId, context.queryPassword(), context.querySignature());
-        }
-        Owned<IDistributedFile> df = queryDistributedFileDirectory().lookup(fileName, userdesc, false, false, false, nullptr, defaultPrivilegedUser);
+        Owned<IDistributedFile> df = lookupLogicalName(context, fileName, false, false, false, nullptr, defaultPrivilegedUser);
         if (!df)
             throw MakeStringException(ECLWATCH_FILE_NOT_EXIST,"Cannot find file %s.",fileName);
 
@@ -5035,22 +5028,13 @@ bool CWsDfuEx::onListHistory(IEspContext &context, IEspListHistoryRequest &req,
 {
     try
     {
-        StringBuffer username;
-        context.getUserID(username);
-        Owned<IUserDescriptor> userdesc;
-        if (username.length() > 0)
-        {
-            userdesc.setown(createUserDescriptor());
-            userdesc->set(username.str(), context.queryPassword(), context.querySignature());
-        }
-
         if (!req.getName() || !*req.getName())
             throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Name required");
         PROGLOG("onListHistory: %s", req.getName());
 
         MemoryBuffer xmlmap;
         IArrayOf<IEspHistory> arrHistory;
-        Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(req.getName(),userdesc.get(), false, false, false, nullptr, defaultPrivilegedUser);
+        Owned<IDistributedFile> file = lookupLogicalName(context, req.getName(), false, false, false, nullptr, defaultPrivilegedUser);
         if (file)
         {
             IPropertyTree *history = file->queryHistory();
@@ -5083,22 +5067,13 @@ bool CWsDfuEx::onEraseHistory(IEspContext &context, IEspEraseHistoryRequest &req
     {
         context.ensureFeatureAccess(FEATURE_URL, SecAccess_Full, ECLWATCH_DFU_ACCESS_DENIED, "WsDfu::EraseHistory: Permission denied.");
 
-        StringBuffer username;
-        context.getUserID(username);
-        Owned<IUserDescriptor> userdesc;
-        if (username.length() > 0)
-        {
-            userdesc.setown(createUserDescriptor());
-            userdesc->set(username.str(), context.queryPassword(), context.querySignature());
-        }
-
         if (!req.getName() || !*req.getName())
             throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Name required");
         PROGLOG("onEraseHistory: %s", req.getName());
 
         MemoryBuffer xmlmap;
         IArrayOf<IEspHistory> arrHistory;
-        Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(req.getName(),userdesc.get(),false,false,false,nullptr,defaultPrivilegedUser);
+        Owned<IDistributedFile> file = lookupLogicalName(context, req.getName(), false, false, false, nullptr, defaultPrivilegedUser);
         if (file)
         {
             IPropertyTree *history = file->queryHistory();
@@ -5694,18 +5669,12 @@ int CWsDfuEx::GetIndexData(IEspContext &context, bool bSchemaOnly, const char* i
 
     double version = context.getClientVersion();
 
-    StringBuffer username;
-    context.getUserID(username);
-
     StringBuffer cluster;
-    Owned<IUserDescriptor> userdesc;
     bool disableUppercaseTranslation = false;
     Owned<IDistributedFile> df;
     try
     {
-        userdesc.setown(createUserDescriptor());
-        userdesc->set(username.str(), context.queryPassword(), context.querySignature());
-        df.setown(queryDistributedFileDirectory().lookup(indexName, userdesc, false, false, false, nullptr, defaultPrivilegedUser));
+        df.setown(lookupLogicalName(context, indexName, false, false, false, nullptr, defaultPrivilegedUser));
         if(!df)
             throw MakeStringException(ECLWATCH_FILE_NOT_EXIST,"Could not find file %s.", indexName);
 

+ 2 - 16
esp/services/ws_fs/ws_fsService.cpp

@@ -39,6 +39,7 @@
 #include "portlist.h"
 #include "sacmd.hpp"
 #include "exception_util.hpp"
+#include "LogicFileWrapper.hpp"
 
 #define DFU_WU_URL          "DfuWorkunitsAccess"
 #define DFU_EX_URL          "DfuExceptionsAccess"
@@ -636,21 +637,6 @@ void setRoxieClusterPartDiskMapping(const char *clusterName, const char *default
     wuOptions->setReplicate(replicate);
 }
 
-StringBuffer& getNodeGroupFromLFN(StringBuffer& nodeGroup, const char* lfn, const char* username, const char* passwd)
-{
-    Owned<IUserDescriptor> udesc;
-    if(username != NULL && *username != '\0')
-    {
-        udesc.setown(createUserDescriptor());
-        udesc->set(username, passwd);
-    }
-
-    Owned<IDistributedFile> df = queryDistributedFileDirectory().lookup(lfn, udesc, false, false, false, nullptr, defaultPrivilegedUser);
-    if (!df)
-        throw MakeStringException(ECLWATCH_FILE_NOT_EXIST, "Failed to find file: %s", lfn);
-    return df->getClusterGroupName(0, nodeGroup);
-}
-
 StringBuffer& constructFileMask(const char* filename, StringBuffer& filemask)
 {
     filemask.clear().append(filename).toLowerCase().append("._$P$_of_$N$");
@@ -2476,7 +2462,7 @@ bool CFileSprayEx::onCopy(IEspContext &context, IEspCopy &req, IEspCopyResponse
         const char* destNodeGroupReq = req.getDestGroup();
         if(!destNodeGroupReq || !*destNodeGroupReq)
         {
-            getNodeGroupFromLFN(destNodeGroup, srcname, context.queryUserId(), context.queryPassword());
+            getNodeGroupFromLFN(context, srcname, destNodeGroup);
             DBGLOG("Destination node group not specified, using source node group %s", destNodeGroup.str());
         }
         else

+ 1 - 0
esp/services/ws_sql/CMakeLists.txt

@@ -83,6 +83,7 @@ if(WSSQL_SERVICE)
         ${HPCC_SOURCE_DIR}/dali/dfu
         ${HPCC_SOURCE_DIR}/dali/base/
         ${HPCC_SOURCE_DIR}/dali/sasha
+        ${HPCC_SOURCE_DIR}/dali/ft
         ${HPCC_SOURCE_DIR}/common/workunit
         ${HPCC_SOURCE_DIR}/common/remote
         ${HPCC_SOURCE_DIR}/common/environment

+ 1 - 0
esp/services/ws_workunits/CMakeLists.txt

@@ -89,6 +89,7 @@ include_directories (
          ./../../smc/SMCLib
          ./../../bindings/SOAP/xpp
          ${HPCC_SOURCE_DIR}/dali/dfu
+         ${HPCC_SOURCE_DIR}/dali/ft
          ./../../../testing/unittests
     )
 

+ 5 - 10
esp/services/ws_workunits/ws_workunitsHelpers.cpp

@@ -30,6 +30,7 @@
 #include "wujobq.hpp"
 #include "hqlexpr.hpp"
 #include "rmtsmtp.hpp"
+#include "LogicFileWrapper.hpp"
 
 #ifndef _NO_LDAP
 #include "ldapsecurity.ipp"
@@ -135,11 +136,9 @@ void ensureWsCreateWorkunitAccess(IEspContext& ctx)
 
 StringBuffer &getWuidFromLogicalFileName(IEspContext &context, const char *logicalName, StringBuffer &wuid)
 {
-    Owned<IUserDescriptor> userdesc = createUserDescriptor();
-    userdesc->set(context.queryUserId(), context.queryPassword(), context.querySignature());
-    Owned<IDistributedFile> df = queryDistributedFileDirectory().lookup(logicalName, userdesc, false, false, false, nullptr, defaultPrivilegedUser);
+    Owned<IDistributedFile> df = lookupLogicalName(context, logicalName, false, false, false, nullptr, defaultPrivilegedUser);
     if (!df)
-        throw MakeStringException(ECLWATCH_FILE_NOT_EXIST,"Cannot find file %s.",logicalName);
+        throw makeStringExceptionV(ECLWATCH_FILE_NOT_EXIST, "Cannot find file %s.", logicalName);
     return wuid.append(df->queryAttributes().queryProp("@workunit"));
 }
 
@@ -1360,13 +1359,9 @@ void WsWuInfo::getWorkflow(IEspECLWorkunit &info, unsigned long flags)
 
 IDistributedFile* WsWuInfo::getLogicalFileData(IEspContext& context, const char* logicalName, bool& showFileContent)
 {
-    StringBuffer username;
-    context.getUserID(username);
-    Owned<IUserDescriptor> userdesc(createUserDescriptor());
-    userdesc->set(username.str(), context.queryPassword(), context.querySignature());
-    Owned<IDistributedFile> df = queryDistributedFileDirectory().lookup(logicalName, userdesc, false, false, false, nullptr, defaultPrivilegedUser);
+    Owned<IDistributedFile> df = lookupLogicalName(context, logicalName, false, false, false, nullptr, defaultPrivilegedUser);
     if (!df)
-        return NULL;
+        return nullptr;
 
     bool blocked;
     if (df->isCompressed(&blocked) && !blocked)

+ 3 - 18
esp/services/ws_workunits/ws_workunitsService.cpp

@@ -48,6 +48,7 @@
 #include "ws_wudetails.hpp"
 #include "wuerror.hpp"
 #include "TpWrapper.hpp"
+#include "LogicFileWrapper.hpp"
 
 #include "rtlformat.hpp"
 
@@ -2912,7 +2913,7 @@ void CWsWorkunitsEx::getWsWuResult(IEspContext &context, const char *wuid, const
             result->getResultFilename(logicalName);
         if (logicalName.length())
         {
-            Owned<IDistributedFile> df = lookupLogicalName(context, logicalName.str());
+            Owned<IDistributedFile> df = lookupLogicalName(context, logicalName.str(), false, false, false, nullptr, defaultPrivilegedUser);
             if (!df)
                 throw makeStringExceptionV(ECLWATCH_FILE_NOT_EXIST, "Cannot find file %s.", logicalName.str());
             resultSz = df->getDiskSize(true, false);
@@ -3244,26 +3245,10 @@ void getWorkunitCluster(IEspContext &context, const char *wuid, SCMStringBuffer
     }
 }
 
-IDistributedFile *CWsWorkunitsEx::lookupLogicalName(IEspContext &context, const char *logicalName)
-{
-    StringBuffer userID;
-    context.getUserID(userID);
-    Owned<IUserDescriptor> userDesc;
-    if (!userID.isEmpty())
-    {
-        userDesc.setown(createUserDescriptor());
-        userDesc->set(userID, context.queryPassword(), context.querySignature());
-    }
-
-    Owned<IDistributedFile> df = queryDistributedFileDirectory().lookup(logicalName, userDesc, false,
-        false, false, nullptr, defaultPrivilegedUser);
-    return df.getClear();
-}
-
 void CWsWorkunitsEx::getFileResults(IEspContext &context, const char *logicalName, const char *cluster, __int64 start, unsigned &count, __int64 &total,
     IStringVal &resname, bool bin, IArrayOf<IConstNamedValue> *filterBy, MemoryBuffer &buf, bool xsd)
 {
-    Owned<IDistributedFile> df = lookupLogicalName(context, logicalName);
+    Owned<IDistributedFile> df = lookupLogicalName(context, logicalName, false, false, false, nullptr, defaultPrivilegedUser);
     if (!df)
         throw makeStringExceptionV(ECLWATCH_FILE_NOT_EXIST, "Cannot find file %s.", logicalName);
 

+ 0 - 1
esp/services/ws_workunits/ws_workunitsService.hpp

@@ -392,7 +392,6 @@ private:
         WUState &wuState, bool xsd=true);
     void getFileResults(IEspContext &context, const char *logicalName, const char *cluster, __int64 start, unsigned &count, __int64 &total,
         IStringVal &resname, bool bin, IArrayOf<IConstNamedValue> *filterBy, MemoryBuffer &buf, bool xsd);
-    IDistributedFile *lookupLogicalName(IEspContext &contcontext, const char *logicalName);
     void getSuspendedQueriesByCluster(MapStringTo<bool> &suspendedByCluster, const char *querySet, const char *queryID, bool checkAllNodes);
     void addSuspendedQueryIDs(MapStringTo<bool> &suspendedQueryIDs, IPropertyTree *queriesOnCluster, const char *target);
     void getWUQueryDetails(IEspContext &context, CWUQueryDetailsReq &req, IEspWUQueryDetailsResponse &resp);

+ 26 - 0
esp/smc/SMCLib/LogicFileWrapper.cpp

@@ -21,6 +21,7 @@
 
 #include "LogicFileWrapper.hpp"
 #include "dautils.hpp"
+#include "exception_util.hpp"
 
 //////////////////////////////////////////////////////////////////////
 // Construction/Destruction
@@ -126,3 +127,28 @@ bool LogicFileWrapper::doCompressFile(const char* name,StringBuffer& returnStr,
 
     return true; 
 }
+
+IDistributedFile* lookupLogicalName(IEspContext& context, const char* logicalName, bool writeattr, bool hold,
+    bool lockSuperOwner, IDistributedFileTransaction* transaction, bool privilegedUser, unsigned timeout)
+{
+    StringBuffer userID;
+    context.getUserID(userID);
+    Owned<IUserDescriptor> userDesc;
+    if (!userID.isEmpty())
+    {
+        userDesc.setown(createUserDescriptor());
+        userDesc->set(userID, context.queryPassword(), context.querySignature());
+    }
+
+    Owned<IDistributedFile> df = queryDistributedFileDirectory().lookup(logicalName, userDesc, writeattr,
+        hold, lockSuperOwner, transaction, privilegedUser, timeout);
+    return df.getClear();
+}
+
+void getNodeGroupFromLFN(IEspContext& context, const char* lfn, StringBuffer& nodeGroup)
+{
+    Owned<IDistributedFile> df = lookupLogicalName(context, lfn, false, false, false, nullptr, defaultPrivilegedUser);
+    if (!df)
+        throw makeStringExceptionV(ECLWATCH_FILE_NOT_EXIST, "Failed to find file: %s", lfn);
+    df->getClusterGroupName(0, nodeGroup);
+}

+ 5 - 0
esp/smc/SMCLib/LogicFileWrapper.hpp

@@ -35,6 +35,7 @@
 #include "daft.hpp"
 #include "dalienv.hpp"
 #include "jpqueue.hpp"
+#include "esp.hpp"
 
 class LFWRAPPER_API LogicFileWrapper : public CInterface  
 {
@@ -159,4 +160,8 @@ struct CompressTask: public CInterface, implements ITask
     Linked<IDistributedFilePart> part;
 };
 
+extern LFWRAPPER_API IDistributedFile* lookupLogicalName(IEspContext& contcontext, const char* logicalName, bool writeattr,
+    bool hold, bool lockSuperOwner, IDistributedFileTransaction* transaction, bool privilegedUser, unsigned timeout=INFINITE);
+extern LFWRAPPER_API void getNodeGroupFromLFN(IEspContext& context, const char* lfn, StringBuffer& nodeGroup);
+
 #endif //__DFUWrapper_HPP__

+ 1 - 0
esp/src/.gitignore

@@ -3,4 +3,5 @@ hpcc-js/
 lib/
 node_modules/
 src/nlsHPCCType.ts
+types/
 lws.target.txt

+ 1 - 2
esp/src/CMakeLists.txt

@@ -31,13 +31,11 @@ file(COPY
     ${CMAKE_CURRENT_SOURCE_DIR}/tsconfig.json
     ${CMAKE_CURRENT_SOURCE_DIR}/webpack.config.js
     ${CMAKE_CURRENT_SOURCE_DIR}/xstyle
-    ${CMAKE_CURRENT_SOURCE_DIR}/util
     DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
 
 set ( SRCS
     ${CMAKE_CURRENT_BINARY_DIR}/eclwatch/css/ecl.css
     ${CMAKE_CURRENT_BINARY_DIR}/eclwatch/css/hpcc.css
-    ${CMAKE_CURRENT_BINARY_DIR}/eclwatch/nls/hpcc.js
     ${CMAKE_CURRENT_BINARY_DIR}/eclwatch/templates/ActivityPageWidget.html
     ${CMAKE_CURRENT_BINARY_DIR}/eclwatch/templates/CurrentUserDetailsWidget.html
     ${CMAKE_CURRENT_BINARY_DIR}/eclwatch/templates/DataPatternsWidget.html
@@ -218,6 +216,7 @@ set ( SRCS
     ${CMAKE_CURRENT_BINARY_DIR}/eclwatch/XrefLostFilesWidget.js
     ${CMAKE_CURRENT_BINARY_DIR}/eclwatch/XrefOrphanFilesWidget.js
     ${CMAKE_CURRENT_BINARY_DIR}/eclwatch/XrefQueryWidget.js
+    ${CMAKE_CURRENT_BINARY_DIR}/src/nls/hpcc.ts
     ${CMAKE_CURRENT_BINARY_DIR}/src/DataPatterns/AttributeDesc.ts
     ${CMAKE_CURRENT_BINARY_DIR}/src/DataPatterns/Cardinality.ts
     ${CMAKE_CURRENT_BINARY_DIR}/src/DataPatterns/config.ts

+ 4 - 3
esp/src/eclwatch/ActivityWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
     "dojo/dom-attr",
 
@@ -31,12 +30,13 @@ define([
     "dijit/ToolbarSeparator",
     "dijit/layout/ContentPane"
 
-], function (declare, lang, i18n, nlsHPCC, arrayUtil, domAttr,
+], function (declare, lang, nlsHPCCMod, arrayUtil, domAttr,
     registry, Button, ToolbarSeparator, Tooltip,
     selector, tree,
     GridDetailsWidget, ESPActivity, DelayLoadWidget, ESPUtil, Utility, DiskUsage, Clippy,
     template
 ) {
+
     var DelayedRefresh = declare("DelayedRefresh", [], {
         _activityWidget: null,
         _promises: null,
@@ -63,6 +63,7 @@ define([
         }
     });
 
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("ActivityWidget", [GridDetailsWidget], {
         templateString: template,
         i18n: nlsHPCC,

+ 4 - 3
esp/src/eclwatch/ClusterProcessesQueryWidget.js

@@ -1,7 +1,6 @@
 define([
     "dojo/_base/declare",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/topic",
 
     "dijit/registry",
@@ -19,10 +18,12 @@ define([
     "hpcc/PreflightDetailsWidget",
     "hpcc/MachineInformationWidget",
     "hpcc/IFrameWidget"
-], function (declare, i18n, nlsHPCC, topic,
+], function (declare, nlsHPCCMod, topic,
     registry,
     tree, selector,
     GridDetailsWidget, ESPPreflight, ESPRequest, WsTopology, Utility, ESPUtil, DelayLoadWidget, PreflightDetailsWidget, MachineInformationWidget, IFrameWidget) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("CluserProcessesQueryWidget", [GridDetailsWidget, ESPUtil.FormHelper], {
         i18n: nlsHPCC,
 

+ 4 - 3
esp/src/eclwatch/CurrentUserDetailsWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/dom",
     "dojo/dom-form",
     "dojo/_base/array",
@@ -26,10 +25,12 @@ define([
     "dojox/form/PasswordValidator"
 
 ],
-function (declare, lang, i18n, nlsHPCC, dom, domForm, arrayUtil,
+    function (declare, lang, nlsHPCCMod, dom, domForm, arrayUtil,
     registry,
     _Widget, WsAccount,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("CurrentUserDetailsWidget", [_Widget], {
         templateString: template,
         baseClass: "CurrentUserDetailsWidget",

+ 4 - 3
esp/src/eclwatch/DFUQueryWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
     "dojo/dom-class",
     "dojo/dom-form",
@@ -59,12 +58,14 @@ define([
 
     "hpcc/TableContainer"
 
-], function (declare, lang, i18n, nlsHPCC, arrayUtil, domClass, domForm, topic,
+], function (declare, lang, nlsHPCCMod, arrayUtil, domClass, domForm, topic,
     registry, Dialog, Menu, MenuItem, MenuSeparator, PopupMenuItem,
     editor, selector, tree,
     _TabContainerWidget, WsDfu, FileSpray, ESPUtil, ESPLogicalFile, ESPDFUWorkunit, DelayLoadWidget, WsTopology, Utility,
     put,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("DFUQueryWidget", [_TabContainerWidget, ESPUtil.FormHelper], {
         templateString: template,
         baseClass: "DFUQueryWidget",

+ 1 - 0
esp/src/eclwatch/DFUSearchWidget.js

@@ -22,6 +22,7 @@ define([
     registry,
     _Widget, Workunit,
     template) {
+
     return declare("DFUSearchWidget", [_Widget], {
         templateString: template,
         baseClass: "DFUSearchWidget",

+ 4 - 3
esp/src/eclwatch/DFUWUDetailsWidget.js

@@ -1,8 +1,7 @@
 define([
     "exports",
     "dojo/_base/declare",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
     "dojo/dom",
     "dojo/dom-class",
@@ -31,10 +30,12 @@ define([
     "dijit/form/CheckBox",
     "dijit/ToolbarSeparator"
 
-], function (exports, declare, i18n, nlsHPCC, arrayUtil, dom, domClass, query,
+], function (exports, declare, nlsHPCCMod, arrayUtil, dom, domClass, query,
     registry,
     _TabContainerWidget, Clippy, FileSpray, ESPDFUWorkunit, DelayLoadWidget,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     exports.fixCircularDependency = declare("DFUWUDetailsWidget", [_TabContainerWidget], {
         templateString: template,
         baseClass: "DFUWUDetailsWidget",

+ 1 - 0
esp/src/eclwatch/DelayLoadWidget.js

@@ -10,6 +10,7 @@ define([
 ], function (declare, lang, dom, domStyle,
     ContentPane,
     Utility) {
+
     return declare("DelayLoadWidget", [ContentPane], {
         __ensurePromise: undefined,
         __initPromise: undefined,

+ 4 - 3
esp/src/eclwatch/DiskUsageDetails.js

@@ -1,7 +1,6 @@
 define([
     "dojo/_base/declare",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
 
     "dijit/registry",
 
@@ -23,10 +22,12 @@ define([
     "dijit/form/DateTextBox",
     "dijit/form/TimeTextBox"
 
-], function (declare, i18n, nlsHPCC,
+], function (declare, nlsHPCCMod,
     registry,
     _Widget, ESPUtil, DiskUsage,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("DiskUsageDetails", [_Widget, ESPUtil.FormHelper], {
         templateString: template,
         baseClass: "DiskUsageDetails",

+ 4 - 3
esp/src/eclwatch/DiskUsageWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/dom-class",
 
     "dijit/registry",
@@ -26,10 +25,12 @@ define([
     "dijit/form/DateTextBox",
     "dijit/form/TimeTextBox"
 
-], function (declare, lang, i18n, nlsHPCC, domClass,
+], function (declare, lang, nlsHPCCMod, domClass,
     registry,
     _Widget, WsDfu, ESPUtil,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("DiskUsageWidget", [_Widget, ESPUtil.FormHelper], {
         templateString: template,
         baseClass: "DiskUsageWidget",

+ 4 - 3
esp/src/eclwatch/DynamicESDLDefinitionDetailsWidget.js

@@ -1,7 +1,6 @@
 define([
     "dojo/_base/declare",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
 
     "hpcc/_TabContainerWidget",
     "src/WsESDLConfig",
@@ -12,9 +11,11 @@ define([
     "dijit/layout/BorderContainer",
     "dijit/layout/TabContainer",
     "dijit/layout/ContentPane"
-], function (declare, i18n, nlsHPCC,
+], function (declare, nlsHPCCMod,
     _TabContainerWidget, WsESDLConfig,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("DynamicESDLDefinitionDetailsWidget", [_TabContainerWidget], {
         templateString: template,
         baseClass: "DynamicESDLDefinitionDetailsWidget",

+ 4 - 3
esp/src/eclwatch/DynamicESDLDefinitionQueryWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
     "dojo/dom",
 
@@ -22,10 +21,12 @@ define([
     "hpcc/DynamicESDLDefinitionDetailsWidget",
     "src/Utility"
 
-], function (declare, lang, i18n, nlsHPCC, arrayUtil, dom,
+], function (declare, lang, nlsHPCCMod, arrayUtil, dom,
     registry, MenuSeparator, Dialog, ToolbarSeparator, Button, TextBox,
     selector,
     GridDetailsWidget, TargetSelectWidget, WsESDLConfig, ESPUtil, DynamicESDLDefinitionDetailsWidget, Utility) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("DynamicESDLWidget", [GridDetailsWidget], {
         i18n: nlsHPCC,
 

+ 4 - 3
esp/src/eclwatch/DynamicESDLDetailsWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/dom",
     "dojo/dom-attr",
 
@@ -36,11 +35,13 @@ define([
 
     "hpcc/TableContainer"
 ],
-    function (declare, lang, i18n, nlsHPCC, dom, domAttr,
+    function (declare, lang, nlsHPCCMod, dom, domAttr,
         registry,
         Clippy,
         _TabContainerWidget, WsESDLConfig,
         template) {
+
+        var nlsHPCC = nlsHPCCMod.default;
         return declare("DynamicESDLDetailsWidget", [_TabContainerWidget], {
             templateString: template,
             baseClass: "DynamicESDLDetailsWidget",

+ 4 - 3
esp/src/eclwatch/DynamicESDLMethodWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
 
     "dijit/registry",
@@ -15,11 +14,13 @@ define([
     "dgrid/editor",
     "dgrid/tree"
 
-], function (declare, lang, i18n, nlsHPCC, arrayUtil,
+], function (declare, lang, nlsHPCCMod, arrayUtil,
     registry, Button,
     GridDetailsWidget, ESPUtil, WsESDLConfig,
     editor, tree
 ) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("DynamicESDLMethodWidget", [GridDetailsWidget], {
         i18n: nlsHPCC,
 

+ 4 - 3
esp/src/eclwatch/DynamicESDLQueryWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
     "dojo/dom",
 
@@ -22,10 +21,12 @@ define([
     "src/ESPUtil",
     "hpcc/DynamicESDLDefinitionQueryWidget",
     "hpcc/TargetSelectWidget"
-], function (declare, lang, i18n, nlsHPCC, arrayUtil, dom,
+], function (declare, lang, nlsHPCCMod, arrayUtil, dom,
     registry, Button, ToolbarSeparator, Dialog, TextBox,
     tree, selector,
     GridDetailsWidget, WsESDLConfig, Utility, DelayLoadWidget, ESPUtil, DynamicESDLDefinitionQueryWidget, TargetSelectWidget) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("DynamicESDLQueryWidget", [GridDetailsWidget, ESPUtil.FormHelper], {
         i18n: nlsHPCC,
 

+ 1 - 0
esp/src/eclwatch/ECLPlaygroundResultsWidget.js

@@ -17,6 +17,7 @@ define([
     registry,
     _TabContainerWidget, ESPWorkunit, ESPQuery, ResultWidget, FullResultWidget,
     template) {
+
     return declare("ECLPlaygroundResultsWidget", [_TabContainerWidget], {
         templateString: template,
         baseClass: "ECLPlaygroundResultsWidget",

+ 4 - 3
esp/src/eclwatch/ECLPlaygroundWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/dom",
     "dojo/query",
 
@@ -25,10 +24,12 @@ define([
     "hpcc/InfoGridWidget",
     "hpcc/VizWidget"
 
-], function (declare, lang, i18n, nlsHPCC, dom, query,
+], function (declare, lang, nlsHPCCMod, dom, query,
     registry,
     _Widget, ESPWorkunit, ESPQuery,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("ECLPlaygroundWidget", [_Widget], {
         templateString: template,
         baseClass: "ECLPlaygroundWidget",

+ 4 - 3
esp/src/eclwatch/ECLSourceWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/dom",
     "dojo/request/xhr",
     "dojo/topic",
@@ -22,11 +21,13 @@ define([
     "dijit/ToolbarSeparator",
     "dijit/form/Button"
 
-], function (declare, lang, i18n, nlsHPCC, dom, xhr, topic,
+], function (declare, lang, nlsHPCCMod, dom, xhr, topic,
     registry,
     CodeMirror,
     _Widget, ESPWorkunit,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("ECLSourceWidget", [_Widget], {
         templateString: template,
         baseClass: "ECLSourceWidget",

+ 4 - 3
esp/src/eclwatch/EventScheduleWorkunitWidget.js

@@ -1,7 +1,6 @@
 define([
     "dojo/_base/declare",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/dom-form",
     "dojo/_base/array",
 
@@ -33,11 +32,13 @@ define([
     "dijit/TooltipDialog",
 
     "dojox/layout/TableContainer"
-], function (declare, i18n, nlsHPCC, domForm, arrayUtil,
+], function (declare, nlsHPCCMod, domForm, arrayUtil,
     registry, Menu, MenuItem,
     selector,
     _TabContainerWidget, WUDetailsWidget, WsWorkunits, ESPUtil,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("EventScheduleWorkunitWidget", [_TabContainerWidget], {
         i18n: nlsHPCC,
         templateString: template,

+ 4 - 3
esp/src/eclwatch/FileBelongsToWidget.js

@@ -1,7 +1,6 @@
 define([
     "dojo/_base/declare",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
 
     "dgrid/selector",
 
@@ -10,9 +9,11 @@ define([
     "src/ESPLogicalFile",
     "src/ESPUtil",
 
-], function (declare, i18n, nlsHPCC,
+], function (declare, nlsHPCCMod,
     selector,
     DelayLoadWidget, GridDetailsWidget, ESPLogicalFile, ESPUtil) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("FileBelongsToWidget", [GridDetailsWidget], {
         i18n: nlsHPCC,
         logicalFile: null,

+ 4 - 3
esp/src/eclwatch/FileBloomsWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
 
     "dijit/registry",
@@ -12,9 +11,11 @@ define([
     "hpcc/GridDetailsWidget",
     "src/WsDfu",
     "src/ESPUtil"
-], function (declare, lang, i18n, nlsHPCC, arrayUtil,
+], function (declare, lang, nlsHPCCMod, arrayUtil,
     registry, selector,
     GridDetailsWidget, WsDfu, ESPUtil) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("FileBloomsWidget", [GridDetailsWidget, ESPUtil.FormHelper], {
         i18n: nlsHPCC,
 

+ 4 - 3
esp/src/eclwatch/FileHistoryWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
 
     "dijit/registry",
@@ -12,9 +11,11 @@ define([
     "hpcc/GridDetailsWidget",
     "src/WsDfu",
     "src/ESPUtil"
-], function (declare, lang, i18n, nlsHPCC, arrayUtil,
+], function (declare, lang, nlsHPCCMod, arrayUtil,
     registry, Button,
     GridDetailsWidget, WsDfu, ESPUtil) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("FileHistoryWidget", [GridDetailsWidget], {
         i18n: nlsHPCC,
         gridTitle: nlsHPCC.History,

+ 4 - 3
esp/src/eclwatch/FilePartsWidget.js

@@ -1,7 +1,6 @@
 define([
     "dojo/_base/declare",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/store/Memory",
     "dojo/store/Observable",
 
@@ -16,10 +15,12 @@ define([
 
     "dijit/layout/ContentPane"
 ],
-    function (declare, i18n, nlsHPCC, Memory, Observable,
+    function (declare, nlsHPCCMod, Memory, Observable,
         OnDemandGrid, Keyboard, ColumnResizer, DijitRegistry,
         _Widget,
         template) {
+
+        var nlsHPCC = nlsHPCCMod.default;
         return declare("FilePartsWidget", [_Widget], {
             templateString: template,
             baseClass: "FilePartsWidget",

+ 4 - 3
esp/src/eclwatch/FileProtectListWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
 
     "dijit/registry",
@@ -12,9 +11,11 @@ define([
     "hpcc/GridDetailsWidget",
     "src/WsDfu",
     "src/ESPUtil"
-], function (declare, lang, i18n, nlsHPCC, arrayUtil,
+], function (declare, lang, nlsHPCCMod, arrayUtil,
     registry, selector,
     GridDetailsWidget, WsDfu, ESPUtil) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("FileProtectListWidget", [GridDetailsWidget, ESPUtil.FormHelper], {
         i18n: nlsHPCC,
 

+ 5 - 4
esp/src/eclwatch/FilterDropDownWidget.js

@@ -1,7 +1,6 @@
 define([
     "dojo/_base/declare",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
     "dojo/dom",
     "dojo/dom-style",
@@ -24,10 +23,12 @@ define([
 
     "hpcc/TableContainer"
 
-], function (declare, i18n, nlsHPCC, arrayUtil, dom, domStyle,
+], function (declare, nlsHPCCMod, arrayUtil, dom, domStyle,
     registry, Select,
     _Widget, Utility, srcReact, Recent,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("FilterDropDownWidget", [_Widget], {
         templateString: template,
         baseClass: "FilterDropDownWidget",
@@ -177,7 +178,7 @@ define([
             var context = this;
             if (this.userName !== null) {
                 if (!Utility.isObjectEmpty(retVal)) {
-                    Recent.addToStack(this.params.ws_key, retVal, 5, true).then(function(val){
+                    Recent.addToStack(this.params.ws_key, retVal, 5, true).then(function (val) {
                         context.loadRecentFilters(retVal);
                     });
                 }

+ 4 - 3
esp/src/eclwatch/FullResultWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
     "dojo/request/iframe",
     "dojo/store/Memory",
@@ -25,11 +24,13 @@ define([
     "dijit/form/Button",
     "dijit/form/ToggleButton",
     "dijit/ToolbarSeparator"
-], function (declare, lang, i18n, nlsHPCC, arrayUtil, iframe, Memory, Observable,
+], function (declare, lang, nlsHPCCMod, arrayUtil, iframe, Memory, Observable,
     registry,
     Grid, DijitRegistry,
     _Widget, ESPBaseMod, ESPUtil,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("FullResultWidget", [_Widget], {
         templateString: template,
         baseClass: "FullResultWidget",

+ 4 - 3
esp/src/eclwatch/GetDFUWorkunitsWidget.js

@@ -1,7 +1,6 @@
 define([
     "dojo/_base/declare",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
     "dojo/dom-class",
     "dojo/topic",
@@ -41,11 +40,13 @@ define([
     "dijit/ToolbarSeparator",
     "dijit/TooltipDialog"
 
-], function (declare, i18n, nlsHPCC, arrayUtil, domClass, topic,
+], function (declare, nlsHPCCMod, arrayUtil, domClass, topic,
     registry, Menu, MenuItem, MenuSeparator, PopupMenuItem,
     selector,
     _TabContainerWidget, ESPUtil, ESPDFUWorkunit, FileSpray, DelayLoadWidget, Utility,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("GetDFUWorkunitsWidget", [_TabContainerWidget], {
         templateString: template,
         baseClass: "GetDFUWorkunitsWidget",

+ 4 - 3
esp/src/eclwatch/GetNumberOfFilesToCopyWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
 
     "hpcc/GridDetailsWidget",
@@ -10,8 +9,10 @@ define([
     "src/ESPUtil",
     "src/WsWorkunits"
 
-], function (declare, lang, i18n, nlsHPCC, arrayUtil,
+], function (declare, lang, nlsHPCCMod, arrayUtil,
     GridDetailsWidget, ESPUtil, WsWorkunits) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("GetNumberOfFilesToCopyWidget", [GridDetailsWidget], {
         i18n: nlsHPCC,
 

+ 4 - 3
esp/src/eclwatch/GraphPageWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/Deferred",
     "dojo/dom",
     "dojo/on",
@@ -36,11 +35,13 @@ define([
     "dijit/form/SimpleTextarea",
     "dijit/form/NumberSpinner",
     "dijit/form/DropDownButton"
-], function (declare, lang, i18n, nlsHPCC, Deferred, dom, on, html,
+], function (declare, lang, nlsHPCCMod, Deferred, dom, on, html,
     registry,
     entities,
     _Widget, ESPUtil, ESPWorkunit, WsWorkunits, Utility,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("GraphPageWidget", [_Widget], {
         templateString: template,
         baseClass: "GraphPageWidget",

+ 4 - 3
esp/src/eclwatch/GraphWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
     "dojo/_base/Deferred",
     "dojo/has",
@@ -39,11 +38,13 @@ define([
     "dijit/Fieldset",
 
     "hpcc/TableContainer"
-], function (declare, lang, i18n, nlsHPCC, arrayUtil, Deferred, has, dom, domConstruct, domClass, domStyle, Observable, Evented,
+], function (declare, lang, nlsHPCCMod, arrayUtil, Deferred, has, dom, domConstruct, domClass, domStyle, Observable, Evented,
     registry,
     parser,
     _Widget, ESPUtil, GraphStore, Utility,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     var GraphView = declare("GraphView", null, {
         sourceGraphWidget: null,
         rootGlobalIDs: null,

+ 1 - 0
esp/src/eclwatch/GraphsLFWidget.js

@@ -10,6 +10,7 @@ define([
 ], function (declare, lang, arrayUtil,
     selector,
     GraphsWidget, ESPLogicalFile) {
+
     return declare("GraphsLFWidget", [GraphsWidget], {
 
         init: function (params) {

+ 1 - 0
esp/src/eclwatch/GraphsQueryWidget.js

@@ -10,6 +10,7 @@ define([
 ], function (declare, lang, arrayUtil,
     selector,
     GraphsWidget, ESPQuery) {
+
     return declare("GraphsQueryWidget", [GraphsWidget], {
         query: null,
 

+ 1 - 0
esp/src/eclwatch/GraphsWUWidget.js

@@ -14,6 +14,7 @@ define([
     selector,
     GraphsWidget, ESPWorkunit,
     srcTimings) {
+
     return declare("GraphsWUWidget", [GraphsWidget], {
         wu: null,
         _graphsData: null,

+ 4 - 3
esp/src/eclwatch/GraphsWidget.js

@@ -1,7 +1,6 @@
 define([
     "dojo/_base/declare",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
 
     "dijit/form/Button",
@@ -10,9 +9,11 @@ define([
     "hpcc/DelayLoadWidget",
     "src/ESPUtil",
     "src/Utility"
-], function (declare, i18n, nlsHPCC, arrayUtil,
+], function (declare, nlsHPCCMod, arrayUtil,
     Button,
     GridDetailsWidget, DelayLoadWidget, ESPUtil, Utility) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("GraphsWidget", [GridDetailsWidget], {
         i18n: nlsHPCC,
 

+ 4 - 3
esp/src/eclwatch/GridDetailsWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/store/Memory",
     "dojo/store/Observable",
 
@@ -25,10 +24,12 @@ define([
     "dijit/ToolbarSeparator",
     "dijit/layout/ContentPane"
 
-], function (declare, lang, i18n, nlsHPCC, Memory, Observable,
+], function (declare, lang, nlsHPCCMod, Memory, Observable,
     registry, Menu, MenuItem, MenuSeparator,
     _TabContainerWidget, Utility, ESPUtil,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("GridDetailsWidget", [_TabContainerWidget], {
         templateString: template,
         baseClass: "GridDetailsWidget",

+ 4 - 3
esp/src/eclwatch/GroupDetailsWidget.js

@@ -1,7 +1,6 @@
 define([
     "dojo/_base/declare",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
 
     "dijit/registry",
 
@@ -19,10 +18,12 @@ define([
     "dijit/TitlePane",
     "dijit/Dialog"
 
-], function (declare, i18n, nlsHPCC,
+], function (declare, nlsHPCCMod,
     registry,
     _TabContainerWidget,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("GroupDetailsWidget", [_TabContainerWidget], {
         templateString: template,
         baseClass: "GroupDetailsWidget",

+ 4 - 3
esp/src/eclwatch/HPCCPlatformECLWidget.js

@@ -1,7 +1,6 @@
 define([
     "dojo/_base/declare",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
 
     "hpcc/_TabContainerWidget",
 
@@ -13,9 +12,11 @@ define([
 
     "hpcc/DelayLoadWidget"
 
-], function (declare, i18n, nlsHPCC,
+], function (declare, nlsHPCCMod,
     _TabContainerWidget,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("HPCCPlatformECLWidget", [_TabContainerWidget], {
         templateString: template,
         baseClass: "HPCCPlatformECLWidget",

+ 4 - 3
esp/src/eclwatch/HPCCPlatformFilesWidget.js

@@ -1,7 +1,6 @@
 define([
     "dojo/_base/declare",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
 
     "hpcc/_TabContainerWidget",
     "src/ESPRequest",
@@ -14,9 +13,11 @@ define([
 
     "hpcc/DelayLoadWidget"
 
-], function (declare, i18n, nlsHPCC,
+], function (declare, nlsHPCCMod,
     _TabContainerWidget, ESPRequest,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("HPCCPlatformFilesWidget", [_TabContainerWidget], {
         templateString: template,
         baseClass: "HPCCPlatformFilesWidget",

+ 4 - 3
esp/src/eclwatch/HPCCPlatformMainWidget.js

@@ -1,7 +1,6 @@
 define([
     "dojo/_base/declare",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
 
     "hpcc/_TabContainerWidget",
 
@@ -13,9 +12,11 @@ define([
 
     "hpcc/DelayLoadWidget"
 
-], function (declare, i18n, nlsHPCC,
+], function (declare, nlsHPCCMod,
     _TabContainerWidget,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("HPCCPlatformMainWidget", [_TabContainerWidget], {
         templateString: template,
         baseClass: "HPCCPlatformMainWidget",

+ 4 - 3
esp/src/eclwatch/HPCCPlatformOpsWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
 
     "dijit/registry",
 
@@ -19,10 +18,12 @@ define([
 
     "hpcc/DelayLoadWidget"
 
-], function (declare, lang, i18n, nlsHPCC,
+], function (declare, lang, nlsHPCCMod,
     registry,
     _TabContainerWidget, ESPRequest, WsELK,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("HPCCPlatformOpsWidget", [_TabContainerWidget], {
         templateString: template,
         baseClass: "HPCCPlatformOpsWidget",

+ 4 - 3
esp/src/eclwatch/HPCCPlatformRoxieWidget.js

@@ -1,7 +1,6 @@
 define([
     "dojo/_base/declare",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
 
     "hpcc/_TabContainerWidget",
 
@@ -13,9 +12,11 @@ define([
 
     "hpcc/DelayLoadWidget"
 
-], function (declare, i18n, nlsHPCC,
+], function (declare, nlsHPCCMod,
     _TabContainerWidget,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("HPCCPlatformRoxieWidget", [_TabContainerWidget], {
         templateString: template,
         baseClass: "HPCCPlatformRoxieWidget",

+ 4 - 3
esp/src/eclwatch/HPCCPlatformServicesPluginWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
 
     "hpcc/_TabContainerWidget",
@@ -15,9 +14,11 @@ define([
     "dijit/layout/TabContainer",
     "dijit/layout/ContentPane"
 
-], function (declare, lang, i18n, nlsHPCC, arrayUtil,
+], function (declare, lang, nlsHPCCMod, arrayUtil,
     _TabContainerWidget, DelayLoadWidget, WsTopology,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("HPCCPlatformServicesPluginWidget", [_TabContainerWidget], {
         templateString: template,
         baseClass: "HPCCPlatformServicesPluginWidget",

+ 64 - 64
esp/src/eclwatch/HPCCPlatformWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
     "dojo/dom",
     "dojo/dom-construct",
@@ -58,7 +57,7 @@ define([
     "hpcc/TableContainer",
     "hpcc/InfoGridWidget"
 
-], function(declare, lang, i18n, nlsHPCC, arrayUtil, dom, domConstruct, domClass, domForm, domStyle, domGeo, cookie, query, topic, xhr,
+], function (declare, lang, nlsHPCCMod, arrayUtil, dom, domConstruct, domClass, domForm, domStyle, domGeo, cookie, query, topic, xhr,
     registry, Tooltip,
     UpgradeBar, ColorPicker,
     CodeMirror, srcReact,
@@ -73,6 +72,7 @@ define([
         _huePickerPointerAlly: "/esp/files/eclwatch/img/hueHandleA11y.png"
     });
 
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("HPCCPlatformWidget", [_TabContainerWidget], {
         templateString: template,
         baseClass: "HPCCPlatformWidget",
@@ -82,7 +82,7 @@ define([
         upgradeBar: null,
         storage: null,
 
-        postCreate: function(args) {
+        postCreate: function (args) {
             this.inherited(arguments);
             this.searchText = registry.byId(this.id + "FindText");
             this.logoutBtn = registry.byId(this.id + "Logout");
@@ -112,7 +112,7 @@ define([
             });
         },
 
-        startup: function(args) {
+        startup: function (args) {
             this.inherited(arguments);
             domStyle.set(dom.byId(this.id + "StackController_stub_Plugins").parentNode.parentNode, {
                 visibility: "hidden"
@@ -126,7 +126,7 @@ define([
         },
 
         //  Implementation  ---
-        refreshBanner: function(activity) {
+        refreshBanner: function (activity) {
             if (this.showBanner !== activity.ShowBanner ||
                 this.bannerContent !== activity.BannerContent ||
                 this.bannerScroll !== activity.BannerScroll ||
@@ -152,7 +152,7 @@ define([
             }
         },
 
-        refreshUserName: function() {
+        refreshUserName: function () {
             if (this.userName) {
                 dom.byId(this.id + "UserID").textContent = this.userName;
             } else if (cookie("ESPUserName")) {
@@ -163,7 +163,7 @@ define([
             }
         },
 
-        init: function(params) {
+        init: function (params) {
             if (this.inherited(arguments))
                 return;
 
@@ -171,7 +171,7 @@ define([
 
             WsMachine.GetComponentStatus({
                 request: {}
-            }).then(function(response) {
+            }).then(function (response) {
                 if (lang.exists("GetComponentStatusResponse.ComponentStatus", response)) {
                     dojoConfig.monitoringEnabled = true;
                     var status = response.GetComponentStatusResponse.ComponentStatus
@@ -181,7 +181,7 @@ define([
                 }
             });
 
-            WsAccount.MyAccount({}).then(function(response) {
+            WsAccount.MyAccount({}).then(function (response) {
                 if (lang.exists("MyAccountResponse.username", response)) {
                     context.userName = response.MyAccountResponse.username;
                     dojoConfig.username = response.MyAccountResponse.username;
@@ -215,7 +215,7 @@ define([
 
             WsTopology.TpGetServicePlugins({
                 request: {}
-            }).then(function(response) {
+            }).then(function (response) {
                 if (lang.exists("TpGetServicePluginsResponse.Plugins.Plugin", response) && response.TpGetServicePluginsResponse.Plugins.Plugin.length) {
                     domStyle.set(dom.byId(context.id + "StackController_stub_Plugins").parentNode.parentNode, {
                         visibility: "visible"
@@ -223,12 +223,12 @@ define([
                 }
             });
 
-            WsTopology.TpGetServerVersion().then(function(buildVersion) {
+            WsTopology.TpGetServerVersion().then(function (buildVersion) {
                 context.build = WsSMC.parseBuildString(buildVersion);
             });
 
             this.activity = ESPActivity.Get();
-            this.activity.watch("__hpcc_changedCount", function(name, oldValue, newValue) {
+            this.activity.watch("__hpcc_changedCount", function (name, oldValue, newValue) {
                 context.refreshBanner(context.activity);
             });
 
@@ -241,19 +241,19 @@ define([
             this.initTab();
             this.checkIfSessionsAreActive();
 
-            topic.subscribe("hpcc/monitoring_component_update", function(topic) {
+            topic.subscribe("hpcc/monitoring_component_update", function (topic) {
                 context.checkMonitoring(topic.status);
             });
             this.storage = new ESPUtil.LocalStorage();
 
-            this.storage.on("storageUpdate", function(msg) {
+            this.storage.on("storageUpdate", function (msg) {
                 context._onUpdateFromStorage(msg)
             });
             this.storage.setItem("Status", "Unlocked");
 
             EnvironmentTheme.checkCurrentState(this.id, this);
 
-            this.environmentTextCB.on("change", function(state) {
+            this.environmentTextCB.on("change", function (state) {
                 if (state) {
                     context.environmentText.set("disabled", false);
                 } else {
@@ -262,7 +262,7 @@ define([
             });
         },
 
-        _onUpdateFromStorage: function(msg) {
+        _onUpdateFromStorage: function (msg) {
             var context = this;
             if (msg.event.newValue === "logged_out") {
                 window.location.reload();
@@ -273,7 +273,7 @@ define([
             }
         },
 
-        initTab: function() {
+        initTab: function () {
             var currSel = this.getSelectedChild();
             if (currSel && !currSel.initalized) {
                 if (currSel.init) {
@@ -282,18 +282,18 @@ define([
             }
         },
 
-        getTitle: function() {
+        getTitle: function () {
             return "ECL Watch";
         },
 
-        checkMonitoring: function(status) {
+        checkMonitoring: function (status) {
             if (status) {
                 domClass.remove("MonitorStatus");
                 domClass.add("MonitorStatus", status);
             }
         },
 
-        checkIfAdmin: function(user) {
+        checkIfAdmin: function (user) {
             var context = this;
             if (user == null) {
                 registry.byId(context.id + "SetBanner").set("disabled", false);
@@ -305,7 +305,7 @@ define([
                     request: {
                         username: user
                     }
-                }).then(function(response) {
+                }).then(function (response) {
                     if (lang.exists("UserEditResponse.isLDAPAdmin", response)) {
                         if (response.UserEditResponse.isLDAPAdmin === true) {
                             dojoConfig.isAdmin = true;
@@ -318,7 +318,7 @@ define([
                         }
                     } else {
                         if (lang.exists("UserEditResponse.Groups.Group", response)) {
-                            arrayUtil.some(response.UserEditResponse.Groups.Group, function(item, idx) {
+                            arrayUtil.some(response.UserEditResponse.Groups.Group, function (item, idx) {
                                 if (item.name === "Administrators" || item.name === "Directory Administrators") {
                                     dojoConfig.isAdmin = true;
                                     registry.byId(context.id + "SetBanner").set("disabled", false);
@@ -335,7 +335,7 @@ define([
             }
         },
 
-        checkIfSessionsAreActive: function() {
+        checkIfSessionsAreActive: function () {
             if (cookie("ESPSessionTimeoutSeconds")) {
                 this.logoutBtn.set("disabled", false);
                 this.lockBtn.set("disabled", false);
@@ -344,12 +344,12 @@ define([
             }
         },
 
-        setEnvironmentTheme: function() {
+        setEnvironmentTheme: function () {
             EnvironmentTheme.setEnvironmentTheme(this.id, this);
         },
 
         //  Hitched actions  ---
-        _onUserID: function(evt) {
+        _onUserID: function (evt) {
             var userDialog = registry.byId(this.id + "UserDialog");
             var userInfo = registry.byId(this.id + "UserInfo");
             if (!userInfo.init({
@@ -361,53 +361,53 @@ define([
             userDialog.show();
         },
 
-        _onFind: function(evt) {
+        _onFind: function (evt) {
             var context = this;
             this.stackContainer.selectChild(this.mainPage);
-            this.mainPage.ensureWidget().then(function(mainPage) {
+            this.mainPage.ensureWidget().then(function (mainPage) {
                 mainPage.widget.TabContainer.selectChild(mainPage.widget._Search);
-                mainPage.widget._Search.ensureWidget().then(function(searchPage) {
+                mainPage.widget._Search.ensureWidget().then(function (searchPage) {
                     searchPage.doSearch(context.searchText.get("value"));
                 });
             });
         },
 
-        _openNewTab: function(url) {
+        _openNewTab: function (url) {
             var win = window.open(url, "_blank");
             if (win && win.focus) {
                 win.focus();
             }
         },
 
-        _onOpenResources: function(evt) {
+        _onOpenResources: function (evt) {
             this._openNewTab("https://hpccsystems.com/download");
         },
 
-        _onOpenDocuments: function(evt) {
+        _onOpenDocuments: function (evt) {
             this._openNewTab("https://hpccsystems.com/training/documentation");
         },
 
-        _onOpenJira: function(evt) {
+        _onOpenJira: function (evt) {
             this._openNewTab("https://track.hpccsystems.com/issues");
         },
 
-        _onOpenForums: function(evt) {
+        _onOpenForums: function (evt) {
             this._openNewTab("https://hpccsystems.com/bb/");
         },
 
-        _onOpenRedBook: function(evt) {
+        _onOpenRedBook: function (evt) {
             this._openNewTab("https://wiki.hpccsystems.com/x/fYAb");
         },
 
-        _onOpenReleaseNotes: function(evt) {
+        _onOpenReleaseNotes: function (evt) {
             this._openNewTab("https://hpccsystems.com/download/release-notes");
         },
 
-        _onOpenTransitionGuide: function(evt) {
+        _onOpenTransitionGuide: function (evt) {
             this._openNewTab("https://wiki.hpccsystems.com/display/hpcc/HPCC+ECL+Watch+5.0+Transition+Guide");
         },
 
-        _onOpenConfiguration: function(evt) {
+        _onOpenConfiguration: function (evt) {
             var context = this;
             if (!this.configText) {
                 ESPRequest.send("main", "", {
@@ -416,7 +416,7 @@ define([
                         PlainText: "yes"
                     },
                     handleAs: "text"
-                }).then(function(response) {
+                }).then(function (response) {
                     context.configText = context.formatXml(response);
                     context.configSourceCM = CodeMirror.fromTextArea(dom.byId(context.id + "ConfigTextArea"), {
                         tabMode: "indent",
@@ -434,24 +434,24 @@ define([
             this.stackContainer.selectChild(this.widget._Config);
         },
 
-        _onOpenErrWarn: function(evt) {
+        _onOpenErrWarn: function (evt) {
             this.stackContainer.selectChild(this.errWarnPage);
         },
 
-        _ondebugLanguageFiles: function() {
+        _ondebugLanguageFiles: function () {
             var context = this;
-            require(["hpcc/nls/hpcc"], function(lang) {
+            require(["src/nls/hpcc"], function (lang) {
                 var languageID = [];
                 var languageRequire = [];
                 for (var key in lang) {
                     if (key !== "root") {
                         languageID.push(key);
-                        languageRequire.push("hpcc/nls/" + key + "/hpcc");
+                        languageRequire.push("src/nls/" + key + "/hpcc");
                     }
                 }
-                require(languageRequire, function() {
+                require(languageRequire, function () {
                     var errWarnGrid = registry.byId(context.id + "ErrWarnGrid");
-                    arrayUtil.forEach(arguments, function(otherLang, idx) {
+                    arrayUtil.forEach(arguments, function (otherLang, idx) {
                         var langID = languageID[idx];
                         for (var key in lang.root) {
                             if (!otherLang[key]) {
@@ -486,39 +486,39 @@ define([
         },
 
         _onAboutLoaded: false,
-        _onAbout: function(evt) {
+        _onAbout: function (evt) {
             var aboutNode = dom.byId(this.id + "AboutDialog");
             srcReact.render(srcReact.AboutDialog, {
                 version: this.build.orig,
-                handleClose: function() {
+                handleClose: function () {
                     srcReact.unrender(aboutNode);
                 }
             }, aboutNode);
         },
 
-        _onShowLock: function(evt) {
+        _onShowLock: function (evt) {
             var LockDialog = new LockDialogWidget({});
             LockDialog.show()
         },
 
-        _onLock: function(evt) {
+        _onLock: function (evt) {
             var LockDialog = new LockDialogWidget({});
             LockDialog._onLock();
         },
 
-        _onHideLock: function(evt) {
+        _onHideLock: function (evt) {
             var LockDialog = new LockDialogWidget({});
             LockDialog.hide();
         },
 
-        _onLogout: function(evt) {
+        _onLogout: function (evt) {
             var context = this;
             this.logoutConfirm.show();
             query(".dijitDialogUnderlay").style("opacity", "0.5");
-            this.logoutConfirm.on("execute", function() {
+            this.logoutConfirm.on("execute", function () {
                 xhr("esp/logout", {
                     method: "post"
-                }).then(function(data) {
+                }).then(function (data) {
                     if (data) {
                         cookie("ECLWatchUser", "", { expires: -1 });
                         cookie("ESPSessionID" + location.port + " = '' ", "", { expires: -1 });
@@ -531,16 +531,16 @@ define([
             });
         },
 
-        _onMonitoring: function(evt) {
+        _onMonitoring: function (evt) {
             this.stackContainer.selectChild(this.operationsPage);
-            this.operationsPage.ensureWidget().then(function(operationsPage) {
-                operationsPage.widget._Topology.ensureWidget().then(function(topologyPage) { //  This is needed otherwise topology will steal focus the first time it is delay loaded
+            this.operationsPage.ensureWidget().then(function (operationsPage) {
+                operationsPage.widget._Topology.ensureWidget().then(function (topologyPage) { //  This is needed otherwise topology will steal focus the first time it is delay loaded
                     operationsPage.selectChild(operationsPage.widget._Monitoring);
                 });
             });
         },
 
-        _onSetBanner: function(evt) {
+        _onSetBanner: function (evt) {
             registry.byId(this.id + "ShowBanner").set("value", this.activity.ShowBanner);
             dom.byId(this.id + "BannerContent").value = this.activity.BannerContent;
             dom.byId(this.id + "BannerColor").value = this.activity.BannerColor;
@@ -549,35 +549,35 @@ define([
             this.setBannerDialog.show();
         },
 
-        _onSetBannerOk: function(evt) {
+        _onSetBannerOk: function (evt) {
             this.activity.setBanner(domForm.toObject(this.id + "SetBannerForm"));
             this.setBannerDialog.hide();
         },
 
-        _onSetBannerCancel: function(evt) {
+        _onSetBannerCancel: function (evt) {
             this.setBannerDialog.hide();
         },
 
-        _onSetToolbar: function(evt) {
+        _onSetToolbar: function (evt) {
             this.setToolbarDialog.show();
         },
 
-        _onSetToolbarOk: function(evt) {
+        _onSetToolbarOk: function (evt) {
             this.setEnvironmentTheme();
         },
 
-        _onSetToolbarCancel: function(evt) {
+        _onSetToolbarCancel: function (evt) {
             this.setToolbarDialog.hide();
         },
 
-        _onSetToolbarReset: function(evt) {
+        _onSetToolbarReset: function (evt) {
             if (confirm(this.i18n.AreYouSureYouWantToResetTheme)) {
                 EnvironmentTheme._onResetDefaultTheme(this.id, this);
                 this._onSetToolbarCancel();
             }
         },
 
-        createStackControllerTooltip: function(widgetID, text) {
+        createStackControllerTooltip: function (widgetID, text) {
             return new Tooltip({
                 connectId: [this.id + "StackController_" + widgetID],
                 label: text,

+ 4 - 3
esp/src/eclwatch/HelpersWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
     "dojo/dom-construct",
     "dojo/dom-class",
@@ -20,10 +19,12 @@ define([
     "src/Utility",
     "hpcc/DelayLoadWidget"
 
-], function (declare, lang, i18n, nlsHPCC, arrayUtil, domConstruct, domClass,
+], function (declare, lang, nlsHPCCMod, arrayUtil, domConstruct, domClass,
     registry, Button, ToolbarSeparator,
     selector,
     GridDetailsWidget, ESPUtil, ESPRequest, ESPWorkunit, Utility, DelayLoadWidget) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("LogsWidget", [GridDetailsWidget], {
         baseClass: "LogsWidget",
         i18n: nlsHPCC,

+ 4 - 3
esp/src/eclwatch/HexViewWidget.js

@@ -1,7 +1,6 @@
 define([
     "dojo/_base/declare",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
 
     "dijit/registry",
@@ -17,10 +16,12 @@ define([
     "dijit/form/ToggleButton",
     "dijit/form/CheckBox"
 ],
-    function (declare, i18n, nlsHPCC, arrayUtil,
+    function (declare, nlsHPCCMod, arrayUtil,
         registry,
         _Widget, hpccComms,
         template) {
+
+        var nlsHPCC = nlsHPCCMod.default;
         return declare("HexViewWidget", [_Widget], {
             templateString: template,
             baseClass: "HexViewWidget",

+ 4 - 3
esp/src/eclwatch/IFrameWidget.js

@@ -1,7 +1,6 @@
 define([
     "dojo/_base/declare",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/dom-construct",
 
     "dijit/registry",
@@ -15,10 +14,12 @@ define([
     "dijit/ToolbarSeparator",
     "dijit/form/Button",
     "dijit/layout/ContentPane"
-], function (declare, i18n, nlsHPCC, domConstruct,
+], function (declare, nlsHPCCMod, domConstruct,
     registry,
     _Widget,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("IFrameWidget", [_Widget], {
         templateString: template,
         baseClass: "IFrameWidget",

+ 4 - 3
esp/src/eclwatch/InfoGridWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
     "dojo/dom",
     "dojo/dom-construct",
@@ -30,10 +29,12 @@ define([
     "dijit/Toolbar",
     "dijit/ToolbarSeparator"
 ],
-    function (declare, lang, i18n, nlsHPCC, arrayUtil, dom, domConstruct, domClass, Memory, Observable, topic, has,
+    function (declare, lang, nlsHPCCMod, arrayUtil, dom, domConstruct, domClass, Memory, Observable, topic, has,
         registry,
         _Widget, ESPUtil, ESPWorkunit, Utility,
         template) {
+
+        var nlsHPCC = nlsHPCCMod.default;
         return declare("InfoGridWidget", [_Widget], {
             templateString: template,
             baseClass: "InfoGridWidget",

+ 3 - 3
esp/src/eclwatch/JSGraphWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
     "dojo/Evented",
 
@@ -15,10 +14,11 @@ define([
     "src/Utility",
 
     "css!font-awesome/css/font-awesome.css"
-], function (declare, lang, i18n, nlsHPCC, arrayUtil, Evented,
+], function (declare, lang, nlsHPCCMod, arrayUtil, Evented,
     hpccCommon, hpccGraph, hpccLayout,
     GraphWidget, ESPGraph, Utility) {
 
+    var nlsHPCC = nlsHPCCMod.default;
     var faCharFactory = function (kind) {
         switch (kind) {
             case "2": return "\uf0c7";      //  Disk Write

+ 4 - 3
esp/src/eclwatch/LFDetailsWidget.js

@@ -2,8 +2,7 @@ define([
     "exports",
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/dom",
     "dojo/dom-attr",
     "dojo/dom-class",
@@ -48,10 +47,12 @@ define([
 
     "hpcc/TableContainer"
 
-], function (exports, declare, lang, i18n, nlsHPCC, dom, domAttr, domClass, domForm,
+], function (exports, declare, lang, nlsHPCCMod, dom, domAttr, domClass, domForm,
     registry,
     _TabContainerWidget, DelayLoadWidget, Clippy, ESPLogicalFile, ESPDFUWorkunit, FileSpray, DataPatternsWidget,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     exports.fixCircularDependency = declare("LFDetailsWidget", [_TabContainerWidget], {
         templateString: template,
         baseClass: "LFDetailsWidget",

+ 4 - 3
esp/src/eclwatch/LZBrowseWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
     "dojo/dom-form",
     "dojo/dom-class",
@@ -53,11 +52,13 @@ define([
     "dojox/form/uploader/FileList",
 
     "hpcc/TableContainer"
-], function (declare, lang, i18n, nlsHPCC, arrayUtil, domForm, domClass, iframe, topic,
+], function (declare, lang, nlsHPCCMod, arrayUtil, domForm, domClass, iframe, topic,
     registry, MenuItem, TextBox, ValidationTextBox,
     tree, editor, selector,
     _TabContainerWidget, FileSpray, ESPUtil, ESPRequest, ESPDFUWorkunit, DelayLoadWidget, Utility,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("LZBrowseWidget", [_TabContainerWidget, ESPUtil.FormHelper], {
         templateString: template,
         baseClass: "LZBrowseWidget",

+ 4 - 3
esp/src/eclwatch/LibrariesUsedWidget.js

@@ -1,15 +1,16 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
 
     "hpcc/GridDetailsWidget",
     "src/ESPQuery",
     "src/ESPUtil"
-], function (declare, lang, i18n, nlsHPCC, arrayUtil,
+], function (declare, lang, nlsHPCCMod, arrayUtil,
     GridDetailsWidget, ESPQuery, ESPUtil) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("LibrariesUsedWidget", [GridDetailsWidget], {
         i18n: nlsHPCC,
 

+ 4 - 3
esp/src/eclwatch/LockDialogWidget.js

@@ -1,7 +1,6 @@
 define([
     "dojo/_base/declare",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/dom",
     "dojo/dom-class",
     "dojo/on",
@@ -25,10 +24,12 @@ define([
 
     "hpcc/TableContainer"
 
-], function (declare, i18n, nlsHPCC, dom, domClass, on, xhr, cookie, topic,
+], function (declare, nlsHPCCMod, dom, domClass, on, xhr, cookie, topic,
     registry,
     _Widget, WsAccount, ESPUtil,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("LockDialogWidget", [_Widget], {
         templateString: template,
         baseClass: "LockDialogWidget",

+ 4 - 3
esp/src/eclwatch/LogVisualizationWidget.js

@@ -1,7 +1,6 @@
 define([
     "dojo/_base/declare",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
 
     "hpcc/_TabContainerWidget",
 
@@ -13,8 +12,10 @@ define([
     "dijit/form/Button",
     "dijit/ToolbarSeparator",
     "dijit/form/ToggleButton"
-], function (declare, i18n, nlsHPCC,
+], function (declare, nlsHPCCMod,
     _TabContainerWidget) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("LogVisualizationWidget", [_TabContainerWidget], {
         i18n: nlsHPCC
     });

+ 4 - 3
esp/src/eclwatch/LogWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
 
     "dijit/registry",
 
@@ -31,10 +30,12 @@ define([
     "dijit/ToolbarSeparator",
     "dijit/TooltipDialog"
 
-], function (declare, lang, i18n, nlsHPCC,
+], function (declare, lang, nlsHPCCMod,
     registry,
     _TabContainerWidget, ESPBaseMod, ESPUtil, WsTopology,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("LogWidget", [_TabContainerWidget, ESPUtil.FormHelper], {
         templateString: template,
         baseClass: "LogWidget",

+ 4 - 3
esp/src/eclwatch/MachineInformationWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
     "dojo/dom",
     "dojo/dom-style",
@@ -25,10 +24,12 @@ define([
 
     "hpcc/TableContainer"
 
-], function (declare, lang, i18n, nlsHPCC, arrayUtil, dom, domStyle, topic,
+], function (declare, lang, nlsHPCCMod, arrayUtil, dom, domStyle, topic,
     registry,
     _Widget, WsMachine,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("MachineInformationWidget", [_Widget], {
         templateString: template,
         baseClass: "MachineInformationWidget",

+ 4 - 3
esp/src/eclwatch/MemberOfWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
     "dojo/promise/all",
 
@@ -18,10 +17,12 @@ define([
     "src/ESPUtil",
     "hpcc/TargetSelectWidget"
 
-], function (declare, lang, i18n, nlsHPCC, arrayUtil, all,
+], function (declare, lang, nlsHPCCMod, arrayUtil, all,
     registry, Button, ToolbarSeparator, Dialog,
     selector,
     GridDetailsWidget, WsAccess, ESPUtil, TargetSelectWidget) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("MemberOfWidget", [GridDetailsWidget], {
         i18n: nlsHPCC,
 

+ 4 - 3
esp/src/eclwatch/MembersWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
     "dojo/promise/all",
     "dojo/on",
@@ -21,10 +20,12 @@ define([
     "src/Utility",
     "hpcc/TargetSelectWidget"
 
-], function (declare, lang, i18n, nlsHPCC, arrayUtil, all, on,
+], function (declare, lang, nlsHPCCMod, arrayUtil, all, on,
     registry, Button, ValidationTextBox, ToolbarSeparator, Dialog,
     selector,
     GridDetailsWidget, WsAccess, ESPUtil, Utility, TargetSelectWidget) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("MembersWidget", [GridDetailsWidget], {
         i18n: nlsHPCC,
 

+ 4 - 3
esp/src/eclwatch/MonitoringWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
     "dojo/dom-class",
     "dojo/topic",
@@ -14,9 +13,11 @@ define([
     "src/ESPUtil",
     "src/Utility"
 
-], function (declare, lang, i18n, nlsHPCC, arrayUtil, domClass, topic,
+], function (declare, lang, nlsHPCCMod, arrayUtil, domClass, topic,
     tree,
     GridDetailsWidget, WsMachine, ESPUtil, Utility) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("MonitoringWidget", [GridDetailsWidget], {
         i18n: nlsHPCC,
 

+ 4 - 3
esp/src/eclwatch/PackageMapDetailsWidget.js

@@ -1,7 +1,6 @@
 define([
     "dojo/_base/declare",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/dom-attr",
     "dojo/dom-class",
     "dojo/topic",
@@ -22,8 +21,10 @@ define([
     "dijit/form/Button",
     "dijit/form/ToggleButton",
     "dijit/Toolbar"
-], function (declare, i18n, nlsHPCC, domAttr, domClass, topic, registry,
+], function (declare, nlsHPCCMod, domAttr, domClass, topic, registry,
     _TabContainerWidget, Clippy, WsPackageMaps, template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("PackageMapDetailsWidget", [_TabContainerWidget], {
         templateString: template,
         baseClass: "PackageMapDetailsWidget",

+ 4 - 3
esp/src/eclwatch/PackageMapPartsWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
     "dojo/promise/all",
 
@@ -23,10 +22,12 @@ define([
     "src/WsPackageMaps",
     "src/Utility",
     "hpcc/FilterDropDownWidget"
-], function (declare, lang, i18n, nlsHPCC, arrayUtil, all,
+], function (declare, lang, nlsHPCCMod, arrayUtil, all,
     registry, ToolbarSeparator, Button, ValidationTextBox, Textarea, TextBox, CheckBox, Dialog,
     selector,
     GridDetailsWidget, DelayLoadWidget, ESPUtil, WsPackageMaps, Utility, FilterDropDownWidget) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("PackageMapPartsWidget", [GridDetailsWidget], {
         i18n: nlsHPCC,
         gridTitle: nlsHPCC.Parts,

+ 4 - 3
esp/src/eclwatch/PackageMapQueryWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/_base/array",
     "dojo/dom",
     "dojo/topic",
@@ -36,11 +35,13 @@ define([
     "dijit/Toolbar",
     "dijit/ToolbarSeparator",
     "dijit/TooltipDialog"
-], function (declare, lang, i18n, nlsHPCC, arrayUtil, dom, topic,
+], function (declare, lang, nlsHPCCMod, arrayUtil, dom, topic,
     _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin, registry,
     selector,
     _TabContainerWidget, DelayLoadWidget, WsPackageMaps, ESPPackageProcess, ESPUtil,
     template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("PackageMapQueryWidget", [_TabContainerWidget], {
         templateString: template,
         baseClass: "PackageMapQueryWidget",

+ 4 - 3
esp/src/eclwatch/PackageMapValidateContentWidget.js

@@ -1,8 +1,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/topic",
     "dijit/registry",
 
@@ -19,8 +18,10 @@ define([
     "dijit/form/Button",
     "dijit/form/ToggleButton"
 
-], function (declare, lang, i18n, nlsHPCC, topic, registry,
+], function (declare, lang, nlsHPCCMod, topic, registry,
     _TabContainerWidget, EclSourceWidget, WsPackageMaps, template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("PackageMapValidateContentWidget", [_TabContainerWidget], {
         templateString: template,
         baseClass: "PackageMapValidateContentWidget",

+ 6 - 4
esp/src/eclwatch/PackageMapValidateWidget.js

@@ -2,7 +2,7 @@ define([
     "dojo/_base/declare",
     "dojo/_base/lang",
     "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/topic",
     "dijit/registry",
 
@@ -19,8 +19,10 @@ define([
     "dijit/form/Button",
     "dijit/form/ToggleButton",
     "dijit/form/Select"
-], function (declare, lang, i18n, nlsHPCC, topic, registry,
+], function (declare, lang, i18n, nlsHPCCMod, topic, registry,
     _TabContainerWidget, WsPackageMaps, template) {
+
+    var nlsHPCC = nlsHPCCMod.default;
     return declare("PackageMapValidateWidget", [_TabContainerWidget], {
         templateString: template,
         baseClass: "PackageMapValidateWidget",
@@ -216,8 +218,8 @@ define([
                         responseText = context.i18n.ValidateResult + responseText;
                         context.resultControl.setText(responseText);
                     }
-                        context.validateButton.set("disabled", false);
-                        return response;
+                    context.validateButton.set("disabled", false);
+                    return response;
                 } else {
                     context.validateButton.set("disabled", false);
                 }

+ 4 - 2
esp/src/eclwatch/PackageSourceWidget.js

@@ -2,7 +2,7 @@ define([
     "dojo/_base/declare",
     "dojo/_base/lang",
     "dojo/i18n",
-    "dojo/i18n!./nls/hpcc",
+    "src/nlsHPCC",
     "dojo/dom",
     "dojo/topic",
 
@@ -20,11 +20,13 @@ define([
     "dijit/layout/BorderContainer",
     "dijit/layout/ContentPane"
 ],
-    function (declare, lang, i18n, nlsHPCC, dom, topic,
+    function (declare, lang, i18n, nlsHPCCMod, dom, topic,
         _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin,
         registry,
         CodeMirror,
         WsPackageMaps, template) {
+
+        var nlsHPCC = nlsHPCCMod.default;
         return declare("PackageSourceWidget", [_LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
             templateString: template,
             baseClass: "PackageSourceWidget",

+ 0 - 0
esp/src/eclwatch/PermissionsWidget.js


部分文件因文件數量過多而無法顯示