feat: functional JS mocks
Build / Build-and-ng-test (pull_request) Successful in 5m28s
Lighthouse Checks / lighthouse (pull_request) Successful in 21m25s
Build / Build-and-test-development (pull_request) Failing after 33m34s

This commit is contained in:
hermes committed 2026-08-27 17:21:01 +01:00
1 parent 18a16fcb06
commit ee52bb8967
17 files changed
+1194 -1836

No files matched your search

+1 -1
View File
@@ -24,4 +24,4 @@ client/.npmrc
*~
.lighthouseci
audit.log
tmp/
+197 -197
View File
@@ -33,24 +33,24 @@ const tables = {
MPE_ALERTS: [],
MPE_AUDIT: [],
MPE_COLUMN_LEVEL_SECURITY: [
{ tx_from: 0, tx_to: '31DEC9999:23:59:59', CLS_SCOPE: 'EDIT', CLS_GROUP: 'AllUsers', CLS_LIBREF: dcLibref, CLS_TABLE: 'MPE_LOCKANYTABLE', CLS_VARIABLE_NM: 'LOCK_STATUS_CD', CLS_ACTIVE: 1, CLS_HIDE: 0 }
{ tx_from: 0, tx_to: 253717919999, CLS_SCOPE: 'EDIT', CLS_GROUP: 'AllUsers', CLS_LIBREF: dcLibref, CLS_TABLE: 'MPE_LOCKANYTABLE', CLS_VARIABLE_NM: 'LOCK_STATUS_CD', CLS_ACTIVE: 1, CLS_HIDE: 0 }
],
MPE_CONFIG: [
{ tx_from: 0, tx_to: '31DEC9999:23:59:59', var_scope: 'DC', var_name: 'DC_EMAIL_ALERTS', var_value: 'NO', var_active: 1, var_desc: 'YES or NO to enable email alerts.' },
{ tx_from: 0, tx_to: '31DEC9999:23:59:59', var_scope: 'DC', var_name: 'DC_VIEWLIB_CHECK', var_value: 'NO', var_active: 1, var_desc: 'Set to YES to enable library validity checking in viewLibs service.' },
{ tx_from: 0, tx_to: '31DEC9999:23:59:59', var_scope: 'DC', var_name: 'DC_MACROS', var_value: dataDir + '/dc_macros', var_active: 1, var_desc: 'Location of underlying macros - EUC feature.' },
{ tx_from: 0, tx_to: '31DEC9999:23:59:59', var_scope: 'DC', var_name: 'DC_MAXOBS_WEBEDIT', var_value: '100', var_active: 1, var_desc: 'Maximum observations for editing in the EDIT screen.' },
{ tx_from: 0, tx_to: '31DEC9999:23:59:59', var_scope: 'DC', var_name: 'DC_REQUEST_LOGS', var_value: 'YES', var_active: 1, var_desc: 'Setting to NO will prevent each request being logged to MPE_REQUESTS.' },
{ tx_from: 0, tx_to: '31DEC9999:23:59:59', var_scope: 'DC', var_name: 'DC_RESTRICT_VIEWER', var_value: 'NO', var_active: 1, var_desc: 'YES will restrict the viewer to tables in MPE_SECURITY.' },
{ tx_from: 0, tx_to: '31DEC9999:23:59:59', var_scope: 'DC', var_name: 'DC_RESTRICT_EDITRECORD', var_value: 'NO', var_active: 1, var_desc: 'YES will prevent the EDIT RECORD dialog.' },
{ tx_from: 0, tx_to: '31DEC9999:23:59:59', var_scope: 'DC_CATALOG', var_name: 'DC_IGNORELIBS', var_value: '|MAPSSAS|MAPS|', var_active: 1, var_desc: 'Pipe separated list of librefs to ignore in Data Catalog.' },
{ tx_from: 0, tx_to: '31DEC9999:23:59:59', var_scope: 'DC', var_name: 'DC_LOCALE', var_value: 'SYSTEM', var_active: 1, var_desc: 'Set to a locale to override the system value.' },
{ tx_from: 0, tx_to: '31DEC9999:23:59:59', var_scope: 'DC_REVIEW', var_name: 'HISTORY_ROWS', var_value: '100', var_active: 1, var_desc: 'Number of rows to return in the HISTORY page.' },
{ tx_from: 0, tx_to: '31DEC9999:23:59:59', var_scope: 'DC', var_name: 'DC_LICENCE_KEY', var_value: ' ', var_active: 1, var_desc: 'Licence Key' },
{ tx_from: 0, tx_to: '31DEC9999:23:59:59', var_scope: 'DC', var_name: 'DC_ACTIVATION_KEY', var_value: ' ', var_active: 1, var_desc: 'Activation Key' },
{ tx_from: 0, tx_to: '31DEC9999:23:59:59', var_scope: 'DC_EMAIL', var_name: 'SUBMITTED_TEMPLATE', var_value: 'Dear user, a change has been submitted.', var_active: 1, var_desc: 'Template email sent after submitting a change.' },
{ tx_from: 0, tx_to: '31DEC9999:23:59:59', var_scope: 'DC_EMAIL', var_name: 'APPROVED_TEMPLATE', var_value: 'Dear user, a change has been approved.', var_active: 1, var_desc: 'Template email sent after approving a change.' },
{ tx_from: 0, tx_to: '31DEC9999:23:59:59', var_scope: 'DC_EMAIL', var_name: 'REJECTED_TEMPLATE', var_value: 'Dear user, a change has been rejected.', var_active: 1, var_desc: 'Template email sent after rejecting a change.' }
{ tx_from: 0, tx_to: 253717919999, var_scope: 'DC', var_name: 'DC_EMAIL_ALERTS', var_value: 'NO', var_active: 1, var_desc: 'YES or NO to enable email alerts.' },
{ tx_from: 0, tx_to: 253717919999, var_scope: 'DC', var_name: 'DC_VIEWLIB_CHECK', var_value: 'NO', var_active: 1, var_desc: 'Set to YES to enable library validity checking in viewLibs service.' },
{ tx_from: 0, tx_to: 253717919999, var_scope: 'DC', var_name: 'DC_MACROS', var_value: dataDir + '/dc_macros', var_active: 1, var_desc: 'Location of underlying macros - EUC feature.' },
{ tx_from: 0, tx_to: 253717919999, var_scope: 'DC', var_name: 'DC_MAXOBS_WEBEDIT', var_value: '100', var_active: 1, var_desc: 'Maximum observations for editing in the EDIT screen.' },
{ tx_from: 0, tx_to: 253717919999, var_scope: 'DC', var_name: 'DC_REQUEST_LOGS', var_value: 'YES', var_active: 1, var_desc: 'Setting to NO will prevent each request being logged to MPE_REQUESTS.' },
{ tx_from: 0, tx_to: 253717919999, var_scope: 'DC', var_name: 'DC_RESTRICT_VIEWER', var_value: 'NO', var_active: 1, var_desc: 'YES will restrict the viewer to tables in MPE_SECURITY.' },
{ tx_from: 0, tx_to: 253717919999, var_scope: 'DC', var_name: 'DC_RESTRICT_EDITRECORD', var_value: 'NO', var_active: 1, var_desc: 'YES will prevent the EDIT RECORD dialog.' },
{ tx_from: 0, tx_to: 253717919999, var_scope: 'DC_CATALOG', var_name: 'DC_IGNORELIBS', var_value: '|MAPSSAS|MAPS|', var_active: 1, var_desc: 'Pipe separated list of librefs to ignore in Data Catalog.' },
{ tx_from: 0, tx_to: 253717919999, var_scope: 'DC', var_name: 'DC_LOCALE', var_value: 'SYSTEM', var_active: 1, var_desc: 'Set to a locale to override the system value.' },
{ tx_from: 0, tx_to: 253717919999, var_scope: 'DC_REVIEW', var_name: 'HISTORY_ROWS', var_value: '100', var_active: 1, var_desc: 'Number of rows to return in the HISTORY page.' },
{ tx_from: 0, tx_to: 253717919999, var_scope: 'DC', var_name: 'DC_LICENCE_KEY', var_value: ' ', var_active: 1, var_desc: 'Licence Key' },
{ tx_from: 0, tx_to: 253717919999, var_scope: 'DC', var_name: 'DC_ACTIVATION_KEY', var_value: ' ', var_active: 1, var_desc: 'Activation Key' },
{ tx_from: 0, tx_to: 253717919999, var_scope: 'DC_EMAIL', var_name: 'SUBMITTED_TEMPLATE', var_value: 'Dear user, a change has been submitted.', var_active: 1, var_desc: 'Template email sent after submitting a change.' },
{ tx_from: 0, tx_to: 253717919999, var_scope: 'DC_EMAIL', var_name: 'APPROVED_TEMPLATE', var_value: 'Dear user, a change has been approved.', var_active: 1, var_desc: 'Template email sent after approving a change.' },
{ tx_from: 0, tx_to: 253717919999, var_scope: 'DC_EMAIL', var_name: 'REJECTED_TEMPLATE', var_value: 'Dear user, a change has been rejected.', var_active: 1, var_desc: 'Template email sent after rejecting a change.' }
],
MPE_DATACATALOG_CATS: [],
MPE_DATACATALOG_LIBS: [],
@@ -62,12 +62,12 @@ const tables = {
MPE_DATASTATUS_OBJS: [],
MPE_DATASTATUS_TABS: [],
MPE_DATADICTIONARY: [
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', DD_TYPE: 'LIBRARY', DD_SOURCE: dcLibref, DD_SHORTDESC: 'Data Controller Control Tables', DD_LONGDESC: '# The Data Controller Library', DD_OWNER: 'sasdemo', DD_RESPONSIBLE: 'sasdemo', DD_SENSITIVITY: 'Low' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', DD_TYPE: 'TABLE', DD_SOURCE: dcLibref + '.MPE_TABLES', DD_SHORTDESC: 'Configuration of new tables for Data Controller', DD_LONGDESC: '# MPE_TABLES', DD_OWNER: 'sasdemo', DD_RESPONSIBLE: 'sasdemo', DD_SENSITIVITY: 'Low' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', DD_TYPE: 'COLUMN', DD_SOURCE: dcLibref + '.MPE_TABLES.DSN', DD_SHORTDESC: 'Dataset Name to be edited', DD_LONGDESC: '_DSN_ - must be UPCASE', DD_OWNER: 'sasdemo', DD_RESPONSIBLE: 'sasdemo', DD_SENSITIVITY: 'Low' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', DD_TYPE: 'DIRECTORY', DD_SOURCE: '/some/directory', DD_SHORTDESC: 'Directory for some purpose', DD_LONGDESC: 'This directory is great.', DD_OWNER: 'sasdemo', DD_RESPONSIBLE: 'sasdemo', DD_SENSITIVITY: 'Low' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', DD_TYPE: 'TABLE', DD_SOURCE: dcLibref, DD_SHORTDESC: 'Transaction table for capturing Data Controller users', DD_LONGDESC: 'After a user accepts the EULA they are registered here.', DD_OWNER: 'sasdemo', DD_RESPONSIBLE: 'sasdemo', DD_SENSITIVITY: 'Low' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', DD_TYPE: 'COLUMN', DD_SOURCE: dcLibref + '.MPE_CONFIG.VAR_ACTIVE', DD_SHORTDESC: 'Set to 1 to make an option active', DD_LONGDESC: 'Used as a filter when querying for option settings.', DD_OWNER: 'sasdemo', DD_RESPONSIBLE: 'sasdemo', DD_SENSITIVITY: 'Low' }
{ tx_from: 0, tx_to: 127490111999, DD_TYPE: 'LIBRARY', DD_SOURCE: dcLibref, DD_SHORTDESC: 'Data Controller Control Tables', DD_LONGDESC: '# The Data Controller Library', DD_OWNER: 'sasdemo', DD_RESPONSIBLE: 'sasdemo', DD_SENSITIVITY: 'Low' },
{ tx_from: 0, tx_to: 127490111999, DD_TYPE: 'TABLE', DD_SOURCE: dcLibref + '.MPE_TABLES', DD_SHORTDESC: 'Configuration of new tables for Data Controller', DD_LONGDESC: '# MPE_TABLES', DD_OWNER: 'sasdemo', DD_RESPONSIBLE: 'sasdemo', DD_SENSITIVITY: 'Low' },
{ tx_from: 0, tx_to: 127490111999, DD_TYPE: 'COLUMN', DD_SOURCE: dcLibref + '.MPE_TABLES.DSN', DD_SHORTDESC: 'Dataset Name to be edited', DD_LONGDESC: '_DSN_ - must be UPCASE', DD_OWNER: 'sasdemo', DD_RESPONSIBLE: 'sasdemo', DD_SENSITIVITY: 'Low' },
{ tx_from: 0, tx_to: 127490111999, DD_TYPE: 'DIRECTORY', DD_SOURCE: '/some/directory', DD_SHORTDESC: 'Directory for some purpose', DD_LONGDESC: 'This directory is great.', DD_OWNER: 'sasdemo', DD_RESPONSIBLE: 'sasdemo', DD_SENSITIVITY: 'Low' },
{ tx_from: 0, tx_to: 127490111999, DD_TYPE: 'TABLE', DD_SOURCE: dcLibref, DD_SHORTDESC: 'Transaction table for capturing Data Controller users', DD_LONGDESC: 'After a user accepts the EULA they are registered here.', DD_OWNER: 'sasdemo', DD_RESPONSIBLE: 'sasdemo', DD_SENSITIVITY: 'Low' },
{ tx_from: 0, tx_to: 127490111999, DD_TYPE: 'COLUMN', DD_SOURCE: dcLibref + '.MPE_CONFIG.VAR_ACTIVE', DD_SHORTDESC: 'Set to 1 to make an option active', DD_LONGDESC: 'Used as a filter when querying for option settings.', DD_OWNER: 'sasdemo', DD_RESPONSIBLE: 'sasdemo', DD_SENSITIVITY: 'Low' }
],
MPE_DATALOADS: [],
MPE_EMAILS: [],
@@ -75,9 +75,9 @@ const tables = {
MPE_FILTERANYTABLE: [],
MPE_FILTERSOURCE: [],
MPE_GROUPS: [
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', group_name: 'dc-admin', group_desc: 'Custom Group for Data Controller Purposes', user_name: 'allbow' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', group_name: 'dc-admin', group_desc: 'Custom Group for Data Controller Purposes', user_name: 'dctestuser1' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', group_name: 'dc-admin', group_desc: 'Custom Group for Data Controller Purposes', user_name: 'mihmed' }
{ tx_from: 0, tx_to: 127490111999, group_name: 'dc-admin', group_desc: 'Custom Group for Data Controller Purposes', user_name: 'allbow' },
{ tx_from: 0, tx_to: 127490111999, group_name: 'dc-admin', group_desc: 'Custom Group for Data Controller Purposes', user_name: 'dctestuser1' },
{ tx_from: 0, tx_to: 127490111999, group_name: 'dc-admin', group_desc: 'Custom Group for Data Controller Purposes', user_name: 'mihmed' }
],
MPE_LINEAGE_COLS: [],
MPE_LINEAGE_TABS: [],
@@ -86,194 +86,194 @@ const tables = {
MPE_REVIEW: [],
MPE_REQUESTS: [],
MPE_ROW_LEVEL_SECURITY: [
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', RLS_RK: 1, RLS_SCOPE: 'ALL', RLS_GROUP: 'dc-admin', RLS_LIBREF: dcLibref, RLS_TABLE: 'MPE_GROUPS', RLS_GROUP_LOGIC: 'AND', RLS_SUBGROUP_LOGIC: 'OR', RLS_SUBGROUP_ID: 0, RLS_VARIABLE_NM: 'GROUP_NAME', RLS_OPERATOR_NM: 'NE', RLS_RAW_VALUE: "'-1'", RLS_ACTIVE: 1 },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', RLS_RK: 2, RLS_SCOPE: 'ALL', RLS_GROUP: 'dc-admin', RLS_LIBREF: dcLibref, RLS_TABLE: 'MPE_ROW_LEVEL_SECURITY', RLS_GROUP_LOGIC: 'AND', RLS_SUBGROUP_LOGIC: 'OR', RLS_SUBGROUP_ID: 0, RLS_VARIABLE_NM: 'RLS_RK', RLS_OPERATOR_NM: '>', RLS_RAW_VALUE: '0', RLS_ACTIVE: 1 },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', RLS_RK: 3, RLS_SCOPE: 'ALL', RLS_GROUP: 'DC Demo Group', RLS_LIBREF: dcLibref, RLS_TABLE: 'MPE_SECURITY', RLS_GROUP_LOGIC: 'AND', RLS_SUBGROUP_LOGIC: 'OR', RLS_SUBGROUP_ID: 0, RLS_VARIABLE_NM: 'ACCESS_LEVEL', RLS_OPERATOR_NM: 'NE', RLS_RAW_VALUE: "'N/A'", RLS_ACTIVE: 1 }
{ tx_from: 0, tx_to: 127490111999, RLS_RK: 1, RLS_SCOPE: 'ALL', RLS_GROUP: 'dc-admin', RLS_LIBREF: dcLibref, RLS_TABLE: 'MPE_GROUPS', RLS_GROUP_LOGIC: 'AND', RLS_SUBGROUP_LOGIC: 'OR', RLS_SUBGROUP_ID: 0, RLS_VARIABLE_NM: 'GROUP_NAME', RLS_OPERATOR_NM: 'NE', RLS_RAW_VALUE: "'-1'", RLS_ACTIVE: 1 },
{ tx_from: 0, tx_to: 127490111999, RLS_RK: 2, RLS_SCOPE: 'ALL', RLS_GROUP: 'dc-admin', RLS_LIBREF: dcLibref, RLS_TABLE: 'MPE_ROW_LEVEL_SECURITY', RLS_GROUP_LOGIC: 'AND', RLS_SUBGROUP_LOGIC: 'OR', RLS_SUBGROUP_ID: 0, RLS_VARIABLE_NM: 'RLS_RK', RLS_OPERATOR_NM: '>', RLS_RAW_VALUE: '0', RLS_ACTIVE: 1 },
{ tx_from: 0, tx_to: 127490111999, RLS_RK: 3, RLS_SCOPE: 'ALL', RLS_GROUP: 'DC Demo Group', RLS_LIBREF: dcLibref, RLS_TABLE: 'MPE_SECURITY', RLS_GROUP_LOGIC: 'AND', RLS_SUBGROUP_LOGIC: 'OR', RLS_SUBGROUP_ID: 0, RLS_VARIABLE_NM: 'ACCESS_LEVEL', RLS_OPERATOR_NM: 'NE', RLS_RAW_VALUE: "'N/A'", RLS_ACTIVE: 1 }
],
MPE_SECURITY: [
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: '*ALL*', dsn: '*ALL*', access_level: 'APPROVE', sas_group: 'dc-admin' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: '*ALL*', dsn: '*ALL*', access_level: 'EDIT', sas_group: 'dc-admin' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: '*ALL*', dsn: '*ALL*', access_level: 'VIEW', sas_group: 'AllUsers' }
{ tx_from: 0, tx_to: 127490111999, libref: '*ALL*', dsn: '*ALL*', access_level: 'APPROVE', sas_group: 'dc-admin' },
{ tx_from: 0, tx_to: 127490111999, libref: '*ALL*', dsn: '*ALL*', access_level: 'EDIT', sas_group: 'dc-admin' },
{ tx_from: 0, tx_to: 127490111999, libref: '*ALL*', dsn: '*ALL*', access_level: 'VIEW', sas_group: 'AllUsers' }
],
MPE_SELECTBOX: [
{ selectbox_rk: 1, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_LOCKANYTABLE', base_column: 'LOCK_STATUS_CD', selectbox_value: 'LOCKED', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 2, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_LOCKANYTABLE', base_column: 'LOCK_STATUS_CD', selectbox_value: 'UNLOCKED', selectbox_order: 2, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 3, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_SECURITY', base_column: 'ACCESS_LEVEL', selectbox_value: 'EDIT', selectbox_order: 0, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 4, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_SECURITY', base_column: 'ACCESS_LEVEL', selectbox_value: 'APPROVE', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 5, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_SECURITY', base_column: 'ACCESS_LEVEL', selectbox_value: 'VIEW', selectbox_order: 2, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 6, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_SECURITY', base_column: 'ACCESS_LEVEL', selectbox_value: 'SIGNOFF', selectbox_order: 3, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 7, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_SECURITY', base_column: 'ACCESS_LEVEL', selectbox_value: 'AUDIT', selectbox_order: 4, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 8, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_TABLES', base_column: 'LOADTYPE', selectbox_value: 'UPDATE', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 9, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_TABLES', base_column: 'LOADTYPE', selectbox_value: 'REPLACE', selectbox_order: 2, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 10, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_TABLES', base_column: 'LOADTYPE', selectbox_value: 'TXTEMPORAL', selectbox_order: 3, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 11, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_TABLES', base_column: 'LOADTYPE', selectbox_value: 'BITEMPORAL', selectbox_order: 4, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 12, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_TABLES', base_column: 'LOADTYPE', selectbox_value: 'FORMAT_CAT', selectbox_order: 5, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 13, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ALERTS', base_column: 'ALERT_EVENT', selectbox_value: '*ALL*', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 14, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ALERTS', base_column: 'ALERT_EVENT', selectbox_value: 'SUBMITTED', selectbox_order: 2, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 15, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ALERTS', base_column: 'ALERT_EVENT', selectbox_value: 'APPROVED', selectbox_order: 3, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 16, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ALERTS', base_column: 'ALERT_EVENT', selectbox_value: 'REJECTED', selectbox_order: 4, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 17, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_X_TEST', base_column: 'SOME_DROPDOWN', selectbox_value: 'Option 1', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 18, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_X_TEST', base_column: 'SOME_DROPDOWN', selectbox_value: 'Option 2', selectbox_order: 2, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 19, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_X_TEST', base_column: 'SOME_DROPDOWN', selectbox_value: 'Option 3', selectbox_order: 2, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 20, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_X_TEST', base_column: 'SOME_DROPDOWN', selectbox_value: 'This is a long option. This option is very long. It is optional, though.', selectbox_order: 3, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 21, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'CASE', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 22, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'HARDSELECT', selectbox_order: 2, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 23, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'HARDSELECT_HOOK', selectbox_order: 3, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 24, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'HIDDEN', selectbox_order: 4, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 25, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'MAXVAL', selectbox_order: 5, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 26, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'MINVAL', selectbox_order: 6, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 27, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'NOTNULL', selectbox_order: 7, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 28, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'NUMBER_FORMAT', selectbox_order: 8, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 29, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'READONLY', selectbox_order: 9, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 30, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'ROUND', selectbox_order: 10, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 31, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'SOFTSELECT', selectbox_order: 11, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 32, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'SOFTSELECT_HOOK', selectbox_order: 12, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 33, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'HARDREGEX', selectbox_order: 13, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 34, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'SOFTREGEX', selectbox_order: 14, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 35, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'HARDFORMULA', selectbox_order: 15, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 36, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'SOFTFORMULA', selectbox_order: 16, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 37, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_ACTIVE', selectbox_value: '1', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 38, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_ACTIVE', selectbox_value: '0', selectbox_order: 2, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 39, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_SECURITY', base_column: 'DSN', selectbox_value: '*ALL*', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 40, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_SECURITY', base_column: 'LIBREF', selectbox_value: '*ALL*', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 41, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_DATADICTIONARY', base_column: 'DD_TYPE', selectbox_value: 'COLUMN', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 42, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_DATADICTIONARY', base_column: 'DD_TYPE', selectbox_value: 'TABLE', selectbox_order: 2, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 43, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_DATADICTIONARY', base_column: 'DD_TYPE', selectbox_value: 'LIBRARY', selectbox_order: 3, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 44, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_DATADICTIONARY', base_column: 'DD_TYPE', selectbox_value: 'CATALOG', selectbox_order: 3, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 45, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_DATADICTIONARY', base_column: 'DD_TYPE', selectbox_value: 'FORMAT', selectbox_order: 3, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 46, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_SCOPE', selectbox_value: 'ALL', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 47, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_SCOPE', selectbox_value: 'EDIT', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 48, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_SCOPE', selectbox_value: 'VIEW', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 49, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_GROUP_LOGIC', selectbox_value: 'AND', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 50, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_GROUP_LOGIC', selectbox_value: 'OR', selectbox_order: 2, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 51, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_SUBGROUP_LOGIC', selectbox_value: 'AND', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 52, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_SUBGROUP_LOGIC', selectbox_value: 'OR', selectbox_order: 2, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 53, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_OPERATOR_NM', selectbox_value: '=', selectbox_order: 0, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 54, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_OPERATOR_NM', selectbox_value: '>', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 55, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_OPERATOR_NM', selectbox_value: '<', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 56, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_OPERATOR_NM', selectbox_value: '<=', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 57, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_OPERATOR_NM', selectbox_value: '>=', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 58, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_OPERATOR_NM', selectbox_value: 'BETWEEN', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 59, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_OPERATOR_NM', selectbox_value: 'IN', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 60, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_OPERATOR_NM', selectbox_value: 'NOT IN', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 61, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_OPERATOR_NM', selectbox_value: 'NE', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 62, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_OPERATOR_NM', selectbox_value: 'CONTAINS', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 63, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_ACTIVE', selectbox_value: '1', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 64, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_ACTIVE', selectbox_value: '0', selectbox_order: 2, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 65, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_column: 'CLS_ACTIVE', selectbox_value: '1', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 66, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_column: 'CLS_ACTIVE', selectbox_value: '0', selectbox_order: 2, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 67, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_column: 'CLS_SCOPE', selectbox_value: 'EDIT', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 68, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_column: 'CLS_SCOPE', selectbox_value: 'VIEW', selectbox_order: 2, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 69, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_column: 'CLS_SCOPE', selectbox_value: 'ALL', selectbox_order: 3, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 70, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_column: 'CLS_HIDE', selectbox_value: '0', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 71, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_column: 'CLS_HIDE', selectbox_value: '1', selectbox_order: 2, ver_to_dttm: '31DEC5999:23:59:59' },
{ selectbox_rk: 72, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_EXCEL_CONFIG', base_column: 'XL_RULE', selectbox_value: 'FORMULA', selectbox_order: 1, ver_to_dttm: '31DEC5999:23:59:59' }
{ selectbox_rk: 1, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_LOCKANYTABLE', base_column: 'LOCK_STATUS_CD', selectbox_value: 'LOCKED', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 2, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_LOCKANYTABLE', base_column: 'LOCK_STATUS_CD', selectbox_value: 'UNLOCKED', selectbox_order: 2, ver_to_dttm: 127490111999 },
{ selectbox_rk: 3, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_SECURITY', base_column: 'ACCESS_LEVEL', selectbox_value: 'EDIT', selectbox_order: 0, ver_to_dttm: 127490111999 },
{ selectbox_rk: 4, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_SECURITY', base_column: 'ACCESS_LEVEL', selectbox_value: 'APPROVE', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 5, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_SECURITY', base_column: 'ACCESS_LEVEL', selectbox_value: 'VIEW', selectbox_order: 2, ver_to_dttm: 127490111999 },
{ selectbox_rk: 6, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_SECURITY', base_column: 'ACCESS_LEVEL', selectbox_value: 'SIGNOFF', selectbox_order: 3, ver_to_dttm: 127490111999 },
{ selectbox_rk: 7, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_SECURITY', base_column: 'ACCESS_LEVEL', selectbox_value: 'AUDIT', selectbox_order: 4, ver_to_dttm: 127490111999 },
{ selectbox_rk: 8, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_TABLES', base_column: 'LOADTYPE', selectbox_value: 'UPDATE', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 9, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_TABLES', base_column: 'LOADTYPE', selectbox_value: 'REPLACE', selectbox_order: 2, ver_to_dttm: 127490111999 },
{ selectbox_rk: 10, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_TABLES', base_column: 'LOADTYPE', selectbox_value: 'TXTEMPORAL', selectbox_order: 3, ver_to_dttm: 127490111999 },
{ selectbox_rk: 11, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_TABLES', base_column: 'LOADTYPE', selectbox_value: 'BITEMPORAL', selectbox_order: 4, ver_to_dttm: 127490111999 },
{ selectbox_rk: 12, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_TABLES', base_column: 'LOADTYPE', selectbox_value: 'FORMAT_CAT', selectbox_order: 5, ver_to_dttm: 127490111999 },
{ selectbox_rk: 13, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ALERTS', base_column: 'ALERT_EVENT', selectbox_value: '*ALL*', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 14, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ALERTS', base_column: 'ALERT_EVENT', selectbox_value: 'SUBMITTED', selectbox_order: 2, ver_to_dttm: 127490111999 },
{ selectbox_rk: 15, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ALERTS', base_column: 'ALERT_EVENT', selectbox_value: 'APPROVED', selectbox_order: 3, ver_to_dttm: 127490111999 },
{ selectbox_rk: 16, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ALERTS', base_column: 'ALERT_EVENT', selectbox_value: 'REJECTED', selectbox_order: 4, ver_to_dttm: 127490111999 },
{ selectbox_rk: 17, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_X_TEST', base_column: 'SOME_DROPDOWN', selectbox_value: 'Option 1', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 18, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_X_TEST', base_column: 'SOME_DROPDOWN', selectbox_value: 'Option 2', selectbox_order: 2, ver_to_dttm: 127490111999 },
{ selectbox_rk: 19, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_X_TEST', base_column: 'SOME_DROPDOWN', selectbox_value: 'Option 3', selectbox_order: 2, ver_to_dttm: 127490111999 },
{ selectbox_rk: 20, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_X_TEST', base_column: 'SOME_DROPDOWN', selectbox_value: 'This is a long option. This option is very long. It is optional, though.', selectbox_order: 3, ver_to_dttm: 127490111999 },
{ selectbox_rk: 21, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'CASE', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 22, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'HARDSELECT', selectbox_order: 2, ver_to_dttm: 127490111999 },
{ selectbox_rk: 23, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'HARDSELECT_HOOK', selectbox_order: 3, ver_to_dttm: 127490111999 },
{ selectbox_rk: 24, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'HIDDEN', selectbox_order: 4, ver_to_dttm: 127490111999 },
{ selectbox_rk: 25, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'MAXVAL', selectbox_order: 5, ver_to_dttm: 127490111999 },
{ selectbox_rk: 26, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'MINVAL', selectbox_order: 6, ver_to_dttm: 127490111999 },
{ selectbox_rk: 27, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'NOTNULL', selectbox_order: 7, ver_to_dttm: 127490111999 },
{ selectbox_rk: 28, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'NUMBER_FORMAT', selectbox_order: 8, ver_to_dttm: 127490111999 },
{ selectbox_rk: 29, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'READONLY', selectbox_order: 9, ver_to_dttm: 127490111999 },
{ selectbox_rk: 30, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'ROUND', selectbox_order: 10, ver_to_dttm: 127490111999 },
{ selectbox_rk: 31, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'SOFTSELECT', selectbox_order: 11, ver_to_dttm: 127490111999 },
{ selectbox_rk: 32, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'SOFTSELECT_HOOK', selectbox_order: 12, ver_to_dttm: 127490111999 },
{ selectbox_rk: 33, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'HARDREGEX', selectbox_order: 13, ver_to_dttm: 127490111999 },
{ selectbox_rk: 34, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'SOFTREGEX', selectbox_order: 14, ver_to_dttm: 127490111999 },
{ selectbox_rk: 35, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'HARDFORMULA', selectbox_order: 15, ver_to_dttm: 127490111999 },
{ selectbox_rk: 36, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_TYPE', selectbox_value: 'SOFTFORMULA', selectbox_order: 16, ver_to_dttm: 127490111999 },
{ selectbox_rk: 37, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_ACTIVE', selectbox_value: '1', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 38, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_VALIDATIONS', base_column: 'RULE_ACTIVE', selectbox_value: '0', selectbox_order: 2, ver_to_dttm: 127490111999 },
{ selectbox_rk: 39, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_SECURITY', base_column: 'DSN', selectbox_value: '*ALL*', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 40, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_SECURITY', base_column: 'LIBREF', selectbox_value: '*ALL*', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 41, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_DATADICTIONARY', base_column: 'DD_TYPE', selectbox_value: 'COLUMN', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 42, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_DATADICTIONARY', base_column: 'DD_TYPE', selectbox_value: 'TABLE', selectbox_order: 2, ver_to_dttm: 127490111999 },
{ selectbox_rk: 43, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_DATADICTIONARY', base_column: 'DD_TYPE', selectbox_value: 'LIBRARY', selectbox_order: 3, ver_to_dttm: 127490111999 },
{ selectbox_rk: 44, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_DATADICTIONARY', base_column: 'DD_TYPE', selectbox_value: 'CATALOG', selectbox_order: 3, ver_to_dttm: 127490111999 },
{ selectbox_rk: 45, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_DATADICTIONARY', base_column: 'DD_TYPE', selectbox_value: 'FORMAT', selectbox_order: 3, ver_to_dttm: 127490111999 },
{ selectbox_rk: 46, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_SCOPE', selectbox_value: 'ALL', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 47, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_SCOPE', selectbox_value: 'EDIT', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 48, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_SCOPE', selectbox_value: 'VIEW', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 49, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_GROUP_LOGIC', selectbox_value: 'AND', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 50, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_GROUP_LOGIC', selectbox_value: 'OR', selectbox_order: 2, ver_to_dttm: 127490111999 },
{ selectbox_rk: 51, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_SUBGROUP_LOGIC', selectbox_value: 'AND', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 52, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_SUBGROUP_LOGIC', selectbox_value: 'OR', selectbox_order: 2, ver_to_dttm: 127490111999 },
{ selectbox_rk: 53, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_OPERATOR_NM', selectbox_value: '=', selectbox_order: 0, ver_to_dttm: 127490111999 },
{ selectbox_rk: 54, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_OPERATOR_NM', selectbox_value: '>', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 55, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_OPERATOR_NM', selectbox_value: '<', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 56, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_OPERATOR_NM', selectbox_value: '<=', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 57, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_OPERATOR_NM', selectbox_value: '>=', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 58, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_OPERATOR_NM', selectbox_value: 'BETWEEN', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 59, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_OPERATOR_NM', selectbox_value: 'IN', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 60, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_OPERATOR_NM', selectbox_value: 'NOT IN', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 61, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_OPERATOR_NM', selectbox_value: 'NE', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 62, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_OPERATOR_NM', selectbox_value: 'CONTAINS', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 63, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_ACTIVE', selectbox_value: '1', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 64, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_ROW_LEVEL_SECURITY', base_column: 'RLS_ACTIVE', selectbox_value: '0', selectbox_order: 2, ver_to_dttm: 127490111999 },
{ selectbox_rk: 65, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_column: 'CLS_ACTIVE', selectbox_value: '1', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 66, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_column: 'CLS_ACTIVE', selectbox_value: '0', selectbox_order: 2, ver_to_dttm: 127490111999 },
{ selectbox_rk: 67, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_column: 'CLS_SCOPE', selectbox_value: 'EDIT', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 68, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_column: 'CLS_SCOPE', selectbox_value: 'VIEW', selectbox_order: 2, ver_to_dttm: 127490111999 },
{ selectbox_rk: 69, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_column: 'CLS_SCOPE', selectbox_value: 'ALL', selectbox_order: 3, ver_to_dttm: 127490111999 },
{ selectbox_rk: 70, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_column: 'CLS_HIDE', selectbox_value: '0', selectbox_order: 1, ver_to_dttm: 127490111999 },
{ selectbox_rk: 71, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_column: 'CLS_HIDE', selectbox_value: '1', selectbox_order: 2, ver_to_dttm: 127490111999 },
{ selectbox_rk: 72, ver_from_dttm: 0, select_lib: dcLibref, select_ds: 'MPE_EXCEL_CONFIG', base_column: 'XL_RULE', selectbox_value: 'FORMULA', selectbox_order: 1, ver_to_dttm: 127490111999 }
],
MPE_SUBMIT: [],
MPE_TABLES: [
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: dcLibref, dsn: 'MPE_COLUMN_LEVEL_SECURITY', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', var_txfrom: 'TX_FROM', var_txto: 'TX_TO', buskey: 'CLS_SCOPE CLS_GROUP CLS_LIBREF CLS_TABLE CLS_VARIABLE_NM', notes: 'Column Level Security config', post_edit_hook: 'services/hooks/mpe_column_level_security_postedit' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: dcLibref, dsn: 'MPE_XLMAP_INFO', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', var_txfrom: 'TX_FROM', var_txto: 'TX_TO', buskey: 'XLMAP_ID', notes: 'Excel Map Info', post_edit_hook: 'services/hooks/mpe_xlmap_info_postedit' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: dcLibref, dsn: 'MPE_XLMAP_RULES', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', var_txfrom: 'TX_FROM', var_txto: 'TX_TO', buskey: 'XLMAP_ID XLMAP_RANGE_ID', notes: 'Excel Map Rules', post_edit_hook: 'services/hooks/mpe_xlmap_rules_postedit' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: dcLibref, dsn: 'MPE_XLMAP_DATA', num_of_approvals_required: 1, loadtype: 'UPDATE', buskey: 'LOAD_REF XLMAP_ID XLMAP_RANGE_ID ROW_NO COL_NO', notes: 'Excel Map Data' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: dcLibref, dsn: 'MPE_LOCKANYTABLE', num_of_approvals_required: 1, loadtype: 'UPDATE', buskey: 'LOCK_LIB LOCK_DS', notes: 'Table lock management' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: dcLibref, dsn: 'MPE_TABLES', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'LIBREF DSN', var_txfrom: 'TX_FROM', var_txto: 'TX_TO', notes: 'MPE Editor self-edit', post_edit_hook: 'services/hooks/mpe_tables_postedit' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: dcLibref, dsn: 'MPE_SECURITY', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'LIBREF DSN ACCESS_LEVEL SAS_GROUP', var_txfrom: 'TX_FROM', var_txto: 'TX_TO', notes: 'Group access control', post_edit_hook: 'services/hooks/mpe_security_postedit' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: dcLibref, dsn: 'MPE_SELECTBOX', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'SELECTBOX_RK', var_txfrom: 'VER_FROM_DTTM', var_txto: 'VER_TO_DTTM', notes: 'Dropdown configuration', rk_underlying: 'SELECT_LIB SELECT_DS BASE_COLUMN SELECTBOX_VALUE' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: dcLibref, dsn: 'MPE_X_TEST', num_of_approvals_required: 1, loadtype: 'UPDATE', buskey: 'PRIMARY_KEY_FIELD', notes: 'Test table for controller' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: dcLibref, dsn: 'MPE_EMAILS', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'USER_NAME', notes: 'Primary Emails Table', var_txfrom: 'TX_FROM', var_txto: 'TX_TO' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: dcLibref, dsn: 'MPE_CONFIG', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'VAR_SCOPE VAR_NAME', notes: 'Configuration variables', var_txfrom: 'TX_FROM', var_txto: 'TX_TO' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: dcLibref, dsn: 'MPE_ALERTS', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'ALERT_EVENT ALERT_LIB ALERT_DS ALERT_USER', notes: 'Alert email events', var_txfrom: 'TX_FROM', var_txto: 'TX_TO' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: dcLibref, dsn: 'MPE_GROUPS', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'GROUP_NAME USER_NAME', notes: 'Additional DC groups', var_txfrom: 'TX_FROM', var_txto: 'TX_TO' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: dcLibref, dsn: 'MPE_VALIDATIONS', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'BASE_LIB BASE_DS BASE_COL RULE_TYPE', notes: 'Data quality rules', var_txfrom: 'TX_FROM', var_txto: 'TX_TO', post_edit_hook: 'services/hooks/mpe_validations_postedit' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: dcLibref, dsn: 'MPE_DATADICTIONARY', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'DD_TYPE DD_SOURCE', notes: 'Data dictionary', var_txfrom: 'TX_FROM', var_txto: 'TX_TO' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: dcLibref, dsn: 'MPE_EXCEL_CONFIG', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'XL_LIBREF XL_TABLE XL_COLUMN', notes: 'Excel import rules', var_txfrom: 'TX_FROM', var_txto: 'TX_TO' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: dcLibref, dsn: 'MPE_ROW_LEVEL_SECURITY', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'RLS_RK', notes: 'Row Level Security', var_txfrom: 'TX_FROM', var_txto: 'TX_TO', rk_underlying: 'RLS_SCOPE RLS_GROUP RLS_LIBREF RLS_TABLE RLS_GROUP_LOGIC RLS_SUBGROUP_LOGIC RLS_SUBGROUP_ID RLS_VARIABLE_NM RLS_OPERATOR_NM RLS_RAW_VALUE', post_edit_hook: 'services/hooks/mpe_row_level_security_postedit' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', libref: dcLibref, dsn: 'MPE_X_CATALOG-FC', num_of_approvals_required: 1, loadtype: 'FORMAT_CAT', buskey: 'TYPE FMTNAME FMTROW', notes: 'Sample Format Catalog' }
{ tx_from: 0, tx_to: 127490111999, libref: dcLibref, dsn: 'MPE_COLUMN_LEVEL_SECURITY', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', var_txfrom: 'TX_FROM', var_txto: 'TX_TO', buskey: 'CLS_SCOPE CLS_GROUP CLS_LIBREF CLS_TABLE CLS_VARIABLE_NM', notes: 'Column Level Security config', post_edit_hook: 'services/hooks/mpe_column_level_security_postedit' },
{ tx_from: 0, tx_to: 127490111999, libref: dcLibref, dsn: 'MPE_XLMAP_INFO', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', var_txfrom: 'TX_FROM', var_txto: 'TX_TO', buskey: 'XLMAP_ID', notes: 'Excel Map Info', post_edit_hook: 'services/hooks/mpe_xlmap_info_postedit' },
{ tx_from: 0, tx_to: 127490111999, libref: dcLibref, dsn: 'MPE_XLMAP_RULES', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', var_txfrom: 'TX_FROM', var_txto: 'TX_TO', buskey: 'XLMAP_ID XLMAP_RANGE_ID', notes: 'Excel Map Rules', post_edit_hook: 'services/hooks/mpe_xlmap_rules_postedit' },
{ tx_from: 0, tx_to: 127490111999, libref: dcLibref, dsn: 'MPE_XLMAP_DATA', num_of_approvals_required: 1, loadtype: 'UPDATE', buskey: 'LOAD_REF XLMAP_ID XLMAP_RANGE_ID ROW_NO COL_NO', notes: 'Excel Map Data' },
{ tx_from: 0, tx_to: 127490111999, libref: dcLibref, dsn: 'MPE_LOCKANYTABLE', num_of_approvals_required: 1, loadtype: 'UPDATE', buskey: 'LOCK_LIB LOCK_DS', notes: 'Table lock management' },
{ tx_from: 0, tx_to: 127490111999, libref: dcLibref, dsn: 'MPE_TABLES', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'LIBREF DSN', var_txfrom: 'TX_FROM', var_txto: 'TX_TO', notes: 'MPE Editor self-edit', post_edit_hook: 'services/hooks/mpe_tables_postedit' },
{ tx_from: 0, tx_to: 127490111999, libref: dcLibref, dsn: 'MPE_SECURITY', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'LIBREF DSN ACCESS_LEVEL SAS_GROUP', var_txfrom: 'TX_FROM', var_txto: 'TX_TO', notes: 'Group access control', post_edit_hook: 'services/hooks/mpe_security_postedit' },
{ tx_from: 0, tx_to: 127490111999, libref: dcLibref, dsn: 'MPE_SELECTBOX', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'SELECTBOX_RK', var_txfrom: 'VER_FROM_DTTM', var_txto: 'VER_TO_DTTM', notes: 'Dropdown configuration', rk_underlying: 'SELECT_LIB SELECT_DS BASE_COLUMN SELECTBOX_VALUE' },
{ tx_from: 0, tx_to: 127490111999, libref: dcLibref, dsn: 'MPE_X_TEST', num_of_approvals_required: 1, loadtype: 'UPDATE', buskey: 'PRIMARY_KEY_FIELD', notes: 'Test table for controller' },
{ tx_from: 0, tx_to: 127490111999, libref: dcLibref, dsn: 'MPE_EMAILS', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'USER_NAME', notes: 'Primary Emails Table', var_txfrom: 'TX_FROM', var_txto: 'TX_TO' },
{ tx_from: 0, tx_to: 127490111999, libref: dcLibref, dsn: 'MPE_CONFIG', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'VAR_SCOPE VAR_NAME', notes: 'Configuration variables', var_txfrom: 'TX_FROM', var_txto: 'TX_TO' },
{ tx_from: 0, tx_to: 127490111999, libref: dcLibref, dsn: 'MPE_ALERTS', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'ALERT_EVENT ALERT_LIB ALERT_DS ALERT_USER', notes: 'Alert email events', var_txfrom: 'TX_FROM', var_txto: 'TX_TO' },
{ tx_from: 0, tx_to: 127490111999, libref: dcLibref, dsn: 'MPE_GROUPS', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'GROUP_NAME USER_NAME', notes: 'Additional DC groups', var_txfrom: 'TX_FROM', var_txto: 'TX_TO' },
{ tx_from: 0, tx_to: 127490111999, libref: dcLibref, dsn: 'MPE_VALIDATIONS', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'BASE_LIB BASE_DS BASE_COL RULE_TYPE', notes: 'Data quality rules', var_txfrom: 'TX_FROM', var_txto: 'TX_TO', post_edit_hook: 'services/hooks/mpe_validations_postedit' },
{ tx_from: 0, tx_to: 127490111999, libref: dcLibref, dsn: 'MPE_DATADICTIONARY', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'DD_TYPE DD_SOURCE', notes: 'Data dictionary', var_txfrom: 'TX_FROM', var_txto: 'TX_TO' },
{ tx_from: 0, tx_to: 127490111999, libref: dcLibref, dsn: 'MPE_EXCEL_CONFIG', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'XL_LIBREF XL_TABLE XL_COLUMN', notes: 'Excel import rules', var_txfrom: 'TX_FROM', var_txto: 'TX_TO' },
{ tx_from: 0, tx_to: 127490111999, libref: dcLibref, dsn: 'MPE_ROW_LEVEL_SECURITY', num_of_approvals_required: 1, loadtype: 'TXTEMPORAL', buskey: 'RLS_RK', notes: 'Row Level Security', var_txfrom: 'TX_FROM', var_txto: 'TX_TO', rk_underlying: 'RLS_SCOPE RLS_GROUP RLS_LIBREF RLS_TABLE RLS_GROUP_LOGIC RLS_SUBGROUP_LOGIC RLS_SUBGROUP_ID RLS_VARIABLE_NM RLS_OPERATOR_NM RLS_RAW_VALUE', post_edit_hook: 'services/hooks/mpe_row_level_security_postedit' },
{ tx_from: 0, tx_to: 127490111999, libref: dcLibref, dsn: 'MPE_X_CATALOG-FC', num_of_approvals_required: 1, loadtype: 'FORMAT_CAT', buskey: 'TYPE FMTNAME FMTROW', notes: 'Sample Format Catalog' }
],
MPE_VALIDATIONS: [
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_col: 'CLS_SCOPE', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_col: 'CLS_LIBREF', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_col: 'CLS_LIBREF', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/libraries_all', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_col: 'CLS_TABLE', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_col: 'CLS_TABLE', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/tables_all', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_col: 'CLS_VARIABLE_NM', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_col: 'CLS_VARIABLE_NM', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/columns_in_libds', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_col: 'CLS_ACTIVE', rule_type: 'MAXVAL', rule_value: '1', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_col: 'CLS_HIDE', rule_type: 'MAXVAL', rule_value: '1', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_col: 'CLS_GROUP', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/sas_groups', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'LIBREF', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'DSN', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'LIBREF', rule_type: 'NOTNULL', rule_value: ' ', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'DSN', rule_type: 'NOTNULL', rule_value: ' ', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'NUM_OF_APPROVALS_REQUIRED', rule_type: 'MINVAL', rule_value: '1', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'BUSKEY', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'BUSKEY', rule_type: 'NOTNULL', rule_value: ' ', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'VAR_TXFROM', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'VAR_TXTO', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'VAR_BUSFROM', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'VAR_BUSTO', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'VAR_PROCESSED', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'LIBREF', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/libraries_all', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'DSN', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/mpe_tables.dsn', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_SECURITY', base_col: 'LIBREF', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_SECURITY', base_col: 'LIBREF', rule_type: 'HARDSELECT', rule_value: dcLibref + '.MPE_TABLES.LIBREF', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_SECURITY', base_col: 'DSN', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_SECURITY', base_col: 'DSN', rule_type: 'SOFTSELECT', rule_value: dcLibref + '.MPE_TABLES.DSN', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_SECURITY', base_col: 'SAS_GROUP', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/sas_groups', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_VALIDATIONS', base_col: 'BASE_LIB', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/libraries_editable', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_VALIDATIONS', base_col: 'BASE_DS', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/tables_editable', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_VALIDATIONS', base_col: 'BASE_COL', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/columns_in_libds', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_VALIDATIONS', base_col: 'RULE_ACTIVE', rule_type: 'MINVAL', rule_value: '0', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_VALIDATIONS', base_col: 'RULE_ACTIVE', rule_type: 'MAXVAL', rule_value: '1', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_EXCEL_CONFIG', base_col: 'XL_LIBREF', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/libraries_editable', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_EXCEL_CONFIG', base_col: 'XL_TABLE', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/tables_editable', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_EXCEL_CONFIG', base_col: 'XL_COLUMN', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/columns_in_libds', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_EXCEL_CONFIG', base_col: 'XL_ACTIVE', rule_type: 'MINVAL', rule_value: '0', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_EXCEL_CONFIG', base_col: 'XL_ACTIVE', rule_type: 'MAXVAL', rule_value: '1', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_XLMAP_INFO', base_col: 'XLMAP_ID', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_XLMAP_INFO', base_col: 'XLMAP_ID', rule_type: 'SOFTSELECT', rule_value: dcLibref + '.MPE_XLMAP_RULES.XLMAP_ID', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_XLMAP_RULES', base_col: 'XLMAP_ID', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_SELECTBOX', base_col: 'SELECT_LIB', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/libraries_editable', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_SELECTBOX', base_col: 'SELECT_DS', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/tables_editable', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_SELECTBOX', base_col: 'BASE_COLUMN', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/columns_in_libds', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_ROW_LEVEL_SECURITY', base_col: 'RLS_GROUP', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/sas_groups', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_ROW_LEVEL_SECURITY', base_col: 'RLS_LIBREF', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/libraries_all', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_ROW_LEVEL_SECURITY', base_col: 'RLS_TABLE', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/tables_all', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_ROW_LEVEL_SECURITY', base_col: 'RLS_SUBGROUP_ID', rule_type: 'MINVAL', rule_value: '0', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_ROW_LEVEL_SECURITY', base_col: 'RLS_SUBGROUP_ID', rule_type: 'NOTNULL', rule_value: '0', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_ROW_LEVEL_SECURITY', base_col: 'RLS_VARIABLE_NM', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/columns_in_libds', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_ALERTS', base_col: 'ALERT_LIB', rule_type: 'HARDSELECT_HOOK', rule_value: 'services/validations/mpe_alerts.alert_lib', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_X_TEST', base_col: 'SOME_BESTNUM', rule_type: 'SOFTSELECT', rule_value: dcLibref + '.MPE_X_TEST.SOME_BESTNUM', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_X_TEST', base_col: 'SOME_CHAR', rule_type: 'HARDREGEX', rule_value: '/the|data/i', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_X_TEST', base_col: 'SOME_CHAR', rule_type: 'SOFTREGEX', rule_value: '/t/', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_X_TEST', base_col: 'PRIMARY_KEY_FIELD', rule_type: 'SOFTREGEX', rule_value: '/^\\d+$/', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_X_TEST', base_col: 'SOME_SHORTNUM', rule_type: 'HARDREGEX', rule_value: '/^(?![1-5](\\.\\d+)?$).*/', rule_active: 1, tx_to: '31DEC5999:23:59:59' },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_X_TEST', base_col: 'SOME_NUM', rule_type: 'HARDSELECT_HOOK', rule_value: 'services/validations/mpe_x_test.some_num', rule_active: 1, tx_to: '31DEC5999:23:59:59' }
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_col: 'CLS_SCOPE', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_col: 'CLS_LIBREF', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_col: 'CLS_LIBREF', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/libraries_all', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_col: 'CLS_TABLE', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_col: 'CLS_TABLE', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/tables_all', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_col: 'CLS_VARIABLE_NM', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_col: 'CLS_VARIABLE_NM', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/columns_in_libds', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_col: 'CLS_ACTIVE', rule_type: 'MAXVAL', rule_value: '1', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_col: 'CLS_HIDE', rule_type: 'MAXVAL', rule_value: '1', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_COLUMN_LEVEL_SECURITY', base_col: 'CLS_GROUP', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/sas_groups', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'LIBREF', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'DSN', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'LIBREF', rule_type: 'NOTNULL', rule_value: ' ', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'DSN', rule_type: 'NOTNULL', rule_value: ' ', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'NUM_OF_APPROVALS_REQUIRED', rule_type: 'MINVAL', rule_value: '1', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'BUSKEY', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'BUSKEY', rule_type: 'NOTNULL', rule_value: ' ', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'VAR_TXFROM', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'VAR_TXTO', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'VAR_BUSFROM', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'VAR_BUSTO', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'VAR_PROCESSED', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'LIBREF', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/libraries_all', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_TABLES', base_col: 'DSN', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/mpe_tables.dsn', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_SECURITY', base_col: 'LIBREF', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_SECURITY', base_col: 'LIBREF', rule_type: 'HARDSELECT', rule_value: dcLibref + '.MPE_TABLES.LIBREF', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_SECURITY', base_col: 'DSN', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_SECURITY', base_col: 'DSN', rule_type: 'SOFTSELECT', rule_value: dcLibref + '.MPE_TABLES.DSN', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_SECURITY', base_col: 'SAS_GROUP', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/sas_groups', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_VALIDATIONS', base_col: 'BASE_LIB', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/libraries_editable', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_VALIDATIONS', base_col: 'BASE_DS', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/tables_editable', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_VALIDATIONS', base_col: 'BASE_COL', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/columns_in_libds', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_VALIDATIONS', base_col: 'RULE_ACTIVE', rule_type: 'MINVAL', rule_value: '0', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_VALIDATIONS', base_col: 'RULE_ACTIVE', rule_type: 'MAXVAL', rule_value: '1', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_EXCEL_CONFIG', base_col: 'XL_LIBREF', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/libraries_editable', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_EXCEL_CONFIG', base_col: 'XL_TABLE', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/tables_editable', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_EXCEL_CONFIG', base_col: 'XL_COLUMN', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/columns_in_libds', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_EXCEL_CONFIG', base_col: 'XL_ACTIVE', rule_type: 'MINVAL', rule_value: '0', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_EXCEL_CONFIG', base_col: 'XL_ACTIVE', rule_type: 'MAXVAL', rule_value: '1', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_XLMAP_INFO', base_col: 'XLMAP_ID', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_XLMAP_INFO', base_col: 'XLMAP_ID', rule_type: 'SOFTSELECT', rule_value: dcLibref + '.MPE_XLMAP_RULES.XLMAP_ID', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_XLMAP_RULES', base_col: 'XLMAP_ID', rule_type: 'CASE', rule_value: 'UPCASE', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_SELECTBOX', base_col: 'SELECT_LIB', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/libraries_editable', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_SELECTBOX', base_col: 'SELECT_DS', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/tables_editable', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_SELECTBOX', base_col: 'BASE_COLUMN', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/columns_in_libds', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_ROW_LEVEL_SECURITY', base_col: 'RLS_GROUP', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/sas_groups', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_ROW_LEVEL_SECURITY', base_col: 'RLS_LIBREF', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/libraries_all', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_ROW_LEVEL_SECURITY', base_col: 'RLS_TABLE', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/tables_all', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_ROW_LEVEL_SECURITY', base_col: 'RLS_SUBGROUP_ID', rule_type: 'MINVAL', rule_value: '0', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_ROW_LEVEL_SECURITY', base_col: 'RLS_SUBGROUP_ID', rule_type: 'NOTNULL', rule_value: '0', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_ROW_LEVEL_SECURITY', base_col: 'RLS_VARIABLE_NM', rule_type: 'SOFTSELECT_HOOK', rule_value: 'services/validations/columns_in_libds', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_ALERTS', base_col: 'ALERT_LIB', rule_type: 'HARDSELECT_HOOK', rule_value: 'services/validations/mpe_alerts.alert_lib', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_X_TEST', base_col: 'SOME_BESTNUM', rule_type: 'SOFTSELECT', rule_value: dcLibref + '.MPE_X_TEST.SOME_BESTNUM', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_X_TEST', base_col: 'SOME_CHAR', rule_type: 'HARDREGEX', rule_value: '/the|data/i', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_X_TEST', base_col: 'SOME_CHAR', rule_type: 'SOFTREGEX', rule_value: '/t/', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_X_TEST', base_col: 'PRIMARY_KEY_FIELD', rule_type: 'SOFTREGEX', rule_value: '/^\\d+$/', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_X_TEST', base_col: 'SOME_SHORTNUM', rule_type: 'HARDREGEX', rule_value: '/^(?![1-5](\\.\\d+)?$).*/', rule_active: 1, tx_to: 127490111999 },
{ tx_from: 0, base_lib: dcLibref, base_ds: 'MPE_X_TEST', base_col: 'SOME_NUM', rule_type: 'HARDSELECT_HOOK', rule_value: 'services/validations/mpe_x_test.some_num', rule_active: 1, tx_to: 127490111999 }
],
MPE_X_TEST: [
{ PRIMARY_KEY_FIELD: 0, SOME_CHAR: 'this is dummy data', SOME_DROPDOWN: 'Option 1', SOME_NUM: 42, SOME_DATE: '12FEB1960', SOME_DATETIME: '01JAN1960:00:00:42', SOME_TIME: '0:00:42', SOME_SHORTNUM: 8, SOME_BESTNUM: 44 },
{ PRIMARY_KEY_FIELD: 1, SOME_CHAR: 'more dummy data', SOME_DROPDOWN: 'Option 2', SOME_NUM: 42, SOME_DATE: '12FEB1960', SOME_DATETIME: '01JAN1960:00:00:42', SOME_TIME: '0:07:02', SOME_SHORTNUM: 8, SOME_BESTNUM: 44 },
{ PRIMARY_KEY_FIELD: 2, SOME_CHAR: 'even more dummy data', SOME_DROPDOWN: 'Option 3', SOME_NUM: 42, SOME_DATE: '12FEB1960', SOME_DATETIME: '01JAN1960:00:00:42', SOME_TIME: '0:02:22', SOME_SHORTNUM: 8, SOME_BESTNUM: 44 },
{ PRIMARY_KEY_FIELD: 3, SOME_CHAR: 'It was a dark and stormy night. The wind was blowing a gale! The captain said to his mate - mate, tell us a tale. And this, is the tale he told: It was a dark and stormy night. The wind was blowing a gale! The captain said to his mate - mate, tell us a tale. And this, is the tale he told: It was a dark and stormy night. The wind was blowing a gale! The captain said to his mate - mate, tell us a tale. And this, is the tale he told:', SOME_DROPDOWN: 'Option 2', SOME_NUM: 1613.001, SOME_DATE: '27FEB1961', SOME_DATETIME: '01JAN1960:00:07:03', SOME_TIME: '0:00:44', SOME_SHORTNUM: 8, SOME_BESTNUM: 44 },
{ PRIMARY_KEY_FIELD: 4, SOME_CHAR: 'if you can fill the unforgiving minute', SOME_DROPDOWN: 'Option 1', SOME_NUM: 1613.001123456, SOME_DATE: '02AUG1971', SOME_DATETIME: '29MAY1973:06:12:03', SOME_TIME: '0:06:52', SOME_SHORTNUM: 8, SOME_BESTNUM: 44 },
{ PRIMARY_KEY_FIELD: 5, SOME_CHAR: '= testing the formula situation', SOME_DROPDOWN: 'Option 1', SOME_NUM: 42, SOME_DATE: '12FEB1960', SOME_DATETIME: '01JAN1960:00:00:42', SOME_TIME: '0:00:42', SOME_SHORTNUM: 8, SOME_BESTNUM: 44 },
{ PRIMARY_KEY_FIELD: 6, SOME_CHAR: "'=the formula with leading apostrophe", SOME_DROPDOWN: 'Option 1', SOME_NUM: 42, SOME_DATE: '12FEB1960', SOME_DATETIME: '01JAN1960:00:00:42', SOME_TIME: '0:00:42', SOME_SHORTNUM: 8, SOME_BESTNUM: 44 }
{ PRIMARY_KEY_FIELD: 0, SOME_CHAR: 'this is dummy data', SOME_DROPDOWN: 'Option 1', SOME_NUM: 42, SOME_DATE: 42, SOME_DATETIME: 42, SOME_TIME: 42, SOME_SHORTNUM: 8, SOME_BESTNUM: 44 },
{ PRIMARY_KEY_FIELD: 1, SOME_CHAR: 'more dummy data', SOME_DROPDOWN: 'Option 2', SOME_NUM: 42, SOME_DATE: 42, SOME_DATETIME: 42, SOME_TIME: 422, SOME_SHORTNUM: 8, SOME_BESTNUM: 44 },
{ PRIMARY_KEY_FIELD: 2, SOME_CHAR: 'even more dummy data', SOME_DROPDOWN: 'Option 3', SOME_NUM: 42, SOME_DATE: 42, SOME_DATETIME: 42, SOME_TIME: 142, SOME_SHORTNUM: 8, SOME_BESTNUM: 44 },
{ PRIMARY_KEY_FIELD: 3, SOME_CHAR: 'It was a dark and stormy night. The wind was blowing a gale! The captain said to his mate - mate, tell us a tale. And this, is the tale he told: It was a dark and stormy night. The wind was blowing a gale! The captain said to his mate - mate, tell us a tale. And this, is the tale he told: It was a dark and stormy night. The wind was blowing a gale! The captain said to his mate - mate, tell us a tale. And this, is the tale he told:', SOME_DROPDOWN: 'Option 2', SOME_NUM: 1613.001, SOME_DATE: 423, SOME_DATETIME: 423, SOME_TIME: 44, SOME_SHORTNUM: 8, SOME_BESTNUM: 44 },
{ PRIMARY_KEY_FIELD: 4, SOME_CHAR: 'if you can fill the unforgiving minute', SOME_DROPDOWN: 'Option 1', SOME_NUM: 1613.001123456, SOME_DATE: 4231, SOME_DATETIME: 423123123, SOME_TIME: 412, SOME_SHORTNUM: 8, SOME_BESTNUM: 44 },
{ PRIMARY_KEY_FIELD: 5, SOME_CHAR: '= testing the formula situation', SOME_DROPDOWN: 'Option 1', SOME_NUM: 42, SOME_DATE: 42, SOME_DATETIME: 42, SOME_TIME: 42, SOME_SHORTNUM: 8, SOME_BESTNUM: 44 },
{ PRIMARY_KEY_FIELD: 6, SOME_CHAR: "'=the formula with leading apostrophe", SOME_DROPDOWN: 'Option 1', SOME_NUM: 42, SOME_DATE: 42, SOME_DATETIME: 42, SOME_TIME: 42, SOME_SHORTNUM: 8, SOME_BESTNUM: 44 }
],
MPE_XLMAP_DATA: [],
MPE_XLMAP_INFO: [
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', XLMAP_ID: 'BASEL-KM1', XLMAP_DESCRIPTION: 'Basel 3 Key Metrics report', XLMAP_TARGETLIBDS: dcLibref + '.MPE_XLMAP_DATA' }
{ tx_from: 0, tx_to: 127490111999, XLMAP_ID: 'BASEL-KM1', XLMAP_DESCRIPTION: 'Basel 3 Key Metrics report', XLMAP_TARGETLIBDS: dcLibref + '.MPE_XLMAP_DATA' }
],
MPE_XLMAP_RULES: [
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', xlmap_id: 'BASEL-KM1', xlmap_range_id: 'KM1:a', xlmap_sheet: 'KM1', xlmap_start: 'MATCH 4 R[2]C[0]:a' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', xlmap_id: 'BASEL-KM1', xlmap_range_id: 'KM1:b', xlmap_sheet: 'KM1', xlmap_start: 'MATCH 4 R[2]C[0]:b' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', xlmap_id: 'BASEL-KM1', xlmap_range_id: 'KM1:c', xlmap_sheet: 'KM1', xlmap_start: 'MATCH 4 R[2]C[0]:c' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', xlmap_id: 'BASEL-KM1', xlmap_range_id: 'KM1:d', xlmap_sheet: 'KM1', xlmap_start: 'MATCH 4 R[2]C[0]:d' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', xlmap_id: 'BASEL-KM1', xlmap_range_id: 'KM1:e', xlmap_sheet: 'KM1', xlmap_start: 'MATCH 4 R[2]C[0]:e' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', xlmap_id: 'BASEL-KM1', xlmap_range_id: 'KM1:f', xlmap_sheet: 'KM1', xlmap_start: 'MATCH 4 R[2]C[0]:f' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', xlmap_id: 'BASEL-CR2', xlmap_range_id: 'CR2-sec1', xlmap_sheet: 'CR2', xlmap_start: 'ABSOLUTE D8', xlmap_finish: 'BLANKROW' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', xlmap_id: 'BASEL-CR2', xlmap_range_id: 'CR2-sec2', xlmap_sheet: 'CR2', xlmap_start: 'ABSOLUTE D18', xlmap_finish: 'LASTDOWN' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', xlmap_id: 'SAMPLE', xlmap_range_id: 'header', xlmap_sheet: '/1', xlmap_start: 'ABSOLUTE B3', xlmap_finish: 'ABSOLUTE B8' },
{ tx_from: 0, tx_to: '31DEC5999:23:59:59', xlmap_id: 'SAMPLE', xlmap_range_id: 'data', xlmap_sheet: '/1', xlmap_start: 'ABSOLUTE B13', xlmap_finish: 'ABSOLUTE E16' }
{ tx_from: 0, tx_to: 127490111999, xlmap_id: 'BASEL-KM1', xlmap_range_id: 'KM1:a', xlmap_sheet: 'KM1', xlmap_start: 'MATCH 4 R[2]C[0]:a' },
{ tx_from: 0, tx_to: 127490111999, xlmap_id: 'BASEL-KM1', xlmap_range_id: 'KM1:b', xlmap_sheet: 'KM1', xlmap_start: 'MATCH 4 R[2]C[0]:b' },
{ tx_from: 0, tx_to: 127490111999, xlmap_id: 'BASEL-KM1', xlmap_range_id: 'KM1:c', xlmap_sheet: 'KM1', xlmap_start: 'MATCH 4 R[2]C[0]:c' },
{ tx_from: 0, tx_to: 127490111999, xlmap_id: 'BASEL-KM1', xlmap_range_id: 'KM1:d', xlmap_sheet: 'KM1', xlmap_start: 'MATCH 4 R[2]C[0]:d' },
{ tx_from: 0, tx_to: 127490111999, xlmap_id: 'BASEL-KM1', xlmap_range_id: 'KM1:e', xlmap_sheet: 'KM1', xlmap_start: 'MATCH 4 R[2]C[0]:e' },
{ tx_from: 0, tx_to: 127490111999, xlmap_id: 'BASEL-KM1', xlmap_range_id: 'KM1:f', xlmap_sheet: 'KM1', xlmap_start: 'MATCH 4 R[2]C[0]:f' },
{ tx_from: 0, tx_to: 127490111999, xlmap_id: 'BASEL-CR2', xlmap_range_id: 'CR2-sec1', xlmap_sheet: 'CR2', xlmap_start: 'ABSOLUTE D8', xlmap_finish: 'BLANKROW' },
{ tx_from: 0, tx_to: 127490111999, xlmap_id: 'BASEL-CR2', xlmap_range_id: 'CR2-sec2', xlmap_sheet: 'CR2', xlmap_start: 'ABSOLUTE D18', xlmap_finish: 'LASTDOWN' },
{ tx_from: 0, tx_to: 127490111999, xlmap_id: 'SAMPLE', xlmap_range_id: 'header', xlmap_sheet: '/1', xlmap_start: 'ABSOLUTE B3', xlmap_finish: 'ABSOLUTE B8' },
{ tx_from: 0, tx_to: 127490111999, xlmap_id: 'SAMPLE', xlmap_range_id: 'data', xlmap_sheet: '/1', xlmap_start: 'ABSOLUTE B13', xlmap_finish: 'ABSOLUTE E16' }
],
MPE_X_CATALOG: [],
MPE_USERS: []
@@ -6,8 +6,8 @@ let activationKey = ''
let writeError = 0
if (_WEBIN_FILEREF1) {
const fileText = _WEBIN_FILEREF1.toString()
if (_webin_fileref1) {
const fileText = _webin_fileref1.toString()
const split = fileText.split('\n')[1].split(',')
activationKey = split[0]
licenceKey = split[1]
@@ -27,7 +27,7 @@ const json = {
}
try {
fs.writeFileSync(licenceStore, JSON.stringify(json))
fs.writeFileSync(licenceStore, JSON.stringify(json, null, 2))
} catch (err) {
writeError = 1
}
@@ -19,7 +19,7 @@ try {
REVIEW_STATUS_ID: r.SUBMIT_STATUS_CD,
SUBMITTED_BY_NM: r.SUBMITTED_BY_NM,
BASE_TABLE: r.BASE_LIB + '.' + r.BASE_DS,
SUBMITTED_ON_DTTM: new Date(r.SUBMITTED_ON_DTTM * 1000).toISOString().replace('T',' ').replace(/\.\d+Z$/, ''),
SUBMITTED_ON_DTTM: ' ' + new Date(r.SUBMITTED_ON_DTTM * 1000).toISOString().replace('T',' ').replace(/\.\d+Z$/, ''),
SUBMITTED_ON_DTTM2: r.SUBMITTED_ON_DTTM,
SUBMITTED_REASON_TXT: r.SUBMITTED_REASON_TXT || '',
NUM_OF_APPROVALS_REQUIRED: r.NUM_OF_APPROVALS_REQUIRED,
@@ -7,45 +7,39 @@ const dcLibref = 'DC_JSLIB'
const dataDir = nodePath.resolve(driveRoot, 'files', appLoc, 'data', dcLibref)
const stagingDir = nodePath.resolve(dataDir, 'staging')
// Parse the iwant input to get table_id
let tableId = ''
for (let i = 1; i <= 10; i++) {
const nameVar = '_WEBIN_NAME' + i
try {
const nameVal = eval(nameVar)
if (nameVal && nameVal.toLowerCase() === 'iwant') {
const refVar = '_WEBIN_FILEREF' + i
const raw = eval(refVar).toString()
const lines = raw.split(/\r?\n/)
if (lines.length >= 2) {
const headers = lines[0].trim().split(/\s+/).map(h => h.split(':')[0].trim().toLowerCase())
const values = lines[1].trim().split(',')
const idx = headers.indexOf('table_id')
if (idx >= 0) tableId = values[idx]
}
break
}
} catch(e) { break }
}
eval(fs.readFileSync(nodePath.resolve(driveRoot, 'files', appLoc, 'services', 'dcMockUtils.js'), 'utf8'))
const loadTableData = makeTableLoader(dataDir)
// ─── Parse input ──────────────────────────────────────────────────────────────
const _iwantRow = fetchTable('iwant')[0] || {}
const tableId = _iwantRow.TABLE_ID || _iwantRow.table_id || ''
// Load the staged data from the staging directory
let stagetable = []
let fmtStagetable = []
let fmt_stagetable = []
if (tableId) {
try {
const stageFile = nodePath.resolve(stagingDir, tableId + '.json')
const raw = fs.readFileSync(stageFile, {encoding:'utf8'}).toString()
const stageData = JSON.parse(raw)
const stageData = JSON.parse(fs.readFileSync(stageFile, {encoding:'utf8'}).toString())
// Return the rows as stagetable (raw values)
stagetable = stageData.rows
// Build fmt_stagetable (stringified values for display)
fmtStagetable = stageData.rows.map(r => {
// Build fmt_stagetable by applying SAS formats to numeric temporal columns
const dsn = stageData.dsn || ''
const schema = loadTableSchema(dataDir, dsn)
const colDdtypes = {}
for (const col of schema) colDdtypes[col.name.toUpperCase()] = getDdType(col)
fmt_stagetable = stageData.rows.map(r => {
const fmt = {}
for (const key of Object.keys(r)) {
fmt[key] = String(r[key])
const ddtype = colDdtypes[key.toUpperCase()]
if (ddtype === 'DATE' || ddtype === 'DATETIME' || ddtype === 'TIME') {
fmt[key] = formatSasValue(r[key], ddtype)
} else {
fmt[key] = String(r[key])
}
}
return fmt
})
@@ -55,29 +49,14 @@ if (tableId) {
}
_webout = JSON.stringify({
SYSDATE: '26SEP22',
SYSTIME: '08:43',
stagetable: stagetable,
fmt_stagetable: fmtStagetable,
_DEBUG: '',
_METAUSER: 'sasdemo@SAS',
_METAPERSON: 'sasdemo',
_PROGRAM: _program,
AUTOEXEC: '',
MF_GETUSER: 'sasdemo',
SYSCC: '0',
SYSENCODING: 'utf-8',
SYSERRORTEXT: '',
SYSHOSTNAME: 'sasjs-server',
SYSPROCESSID: '0',
SYSPROCESSMODE: 'Stored Program',
SYSPROCESSNAME: '',
SYSJOBID: '0',
SYSSCPL: 'LINUX',
SYSSITE: '123',
SYSUSERID: 'sasdemo',
SYSVLONG: '9.04.01M7P080520',
SYSWARNINGTEXT: '',
END_DTTM: new Date().toISOString(),
MEMSIZE: '0KB'
SYSDATE: '26SEP22', SYSTIME: '08:43',
stagetable, fmt_stagetable,
_DEBUG: '', _METAUSER: 'sasdemo@SAS', _METAPERSON: 'sasdemo',
_PROGRAM: _program, AUTOEXEC: '', MF_GETUSER: 'sasdemo',
SYSCC: '0', SYSENCODING: 'utf-8', SYSERRORTEXT: '',
SYSHOSTNAME: 'sasjs-server', SYSPROCESSID: '0',
SYSPROCESSMODE: 'Stored Program', SYSPROCESSNAME: '',
SYSJOBID: '0', SYSSCPL: 'LINUX', SYSSITE: '123',
SYSUSERID: 'sasdemo', SYSVLONG: '9.04.01M7P080520',
SYSWARNINGTEXT: '', END_DTTM: new Date().toISOString(), MEMSIZE: '0KB'
})
+373
View File
@@ -0,0 +1,373 @@
/**
* @file dcMockUtils.js
* @brief Shared utilities for Data Controller JS mock services on SASjs Server.
*
* Provides:
* - fetchTable / fetchRaw / parseCsv : emulate SAS %webout(FETCH)
* - webOutOpen / webOutObj / webOutClose : emulate SAS %webout(OPEN/OBJ/CLOSE)
* - formatSasValue : apply a SAS format to a numeric value
* - parseFormattedToSas : convert an ISO string back to a SAS numeric
* - getDdType : derive DATE/DATETIME/TIME/N/C from a column format
* - loadTableData / loadTableSchema : read a DC data JSON file from the Drive
* - sasVarsRow : build a $sasdata/$viewdata vars entry for a column
* - sasVarsRow : build a $sasdata/$viewdata vars entry for a column
*
* Usage (from a mock service that is eval'd by the SASjs Server):
* const _utilPath = nodePath.resolve(driveRoot, 'files', appLoc, 'services', 'dcMockUtils.js')
* eval(fs.readFileSync(_utilPath, 'utf8'))
* const rows = fetchTable('SASControlTable')
* const libds = rows[0]?.LIBDS
*/
// ─── SAS epoch ────────────────────────────────────────────────────────────────
const SAS_EPOCH_MS = Date.UTC(1960, 0, 1)
const MONTHS_ABBR = ['JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC']
const MONTHS_NUM = {JAN:'01',FEB:'02',MAR:'03',APR:'04',MAY:'05',JUN:'06',JUL:'07',AUG:'08',SEP:'09',OCT:'10',NOV:'11',DEC:'12'}
// ─── %webout(FETCH) emulation ────────────────────────────────────────────────
/**
* Fetches the raw CSV text of a named input table.
* Uses eval() to access variables in the CALLER's scope.
*/
function fetchRaw(tableName) {
// 1. Direct variable (SASjs Server may set form fields as top-level JS vars)
try {
const val = eval(tableName)
if (val !== undefined && val !== null && val !== '') return val.toString()
} catch(e) { /* not defined */ }
// 2. _WEBIN_NAME / _WEBIN_FILEREF loop (SASjs Server format)
// Variable names are UPPERCASE: _WEBIN_NAME1, _WEBIN_FILEREF1, etc.
// _WEBIN_FILEREF may be a Buffer (from fs.readFileSync) or a string.
for (let i = 1; i <= 10; i++) {
try {
const nameVal = eval('_WEBIN_NAME' + i)
if (nameVal && nameVal.toLowerCase() === tableName.toLowerCase()) {
const refVal = eval('_WEBIN_FILEREF' + i)
if (refVal) return refVal.toString()
}
} catch(e) {}
// Also try lowercase variant
try {
const nameVal = eval('_webin_name' + i)
if (nameVal && nameVal.toLowerCase() === tableName.toLowerCase()) {
const refVal = eval('_webin_fileref' + i)
if (refVal) return refVal.toString()
}
} catch(e) {}
}
// 3. _WEBIN_FILENAME / _WEBIN_FILEREF fallback
for (let i = 1; i <= 10; i++) {
try {
const nameVal = eval('_WEBIN_FILENAME' + i)
if (nameVal && nameVal.toLowerCase().includes(tableName.toLowerCase())) {
const refVal = eval('_WEBIN_FILEREF' + i)
if (refVal) return refVal.toString()
}
} catch(e) {}
try {
const nameVal = eval('_webin_filename' + i)
if (nameVal && nameVal.toLowerCase().includes(tableName.toLowerCase())) {
const refVal = eval('_webin_fileref' + i)
if (refVal) return refVal.toString()
}
} catch(e) {}
}
return null
}
/**
* Fetches a named input table as parsed row objects.
*/
function fetchTable(tableName) {
const raw = fetchRaw(tableName)
if (!raw) return []
return parseCsv(raw)
}
/**
* Parses a SASjs adapter CSV string into an array of row objects.
* Header line: "COL1:$char10. COL2:$char8." (space-separated, name before colon)
* Data lines: comma-separated with double-quote escaping.
*/
function parseCsv(csvText) {
if (!csvText) return []
const lines = csvText.split(/\r?\n/)
if (lines.length < 2) return []
const headers = lines[0].trim().split(/\s+/).map(h => h.split(':')[0])
if (headers.length === 0) return []
const rows = []
for (let i = 1; i < lines.length; i++) {
const line = lines[i].trim()
if (!line) continue
const values = _parseCsvLine(line)
const row = {}
for (let j = 0; j < headers.length && j < values.length; j++) {
row[headers[j]] = values[j]
}
rows.push(row)
}
return rows
}
function _parseCsvLine(line) {
const values = []
let cur = ''
let inQuote = false
for (let j = 0; j < line.length; j++) {
const ch = line[j]
if (ch === '"') {
if (inQuote && line[j + 1] === '"') { cur += '"'; j++ }
else inQuote = !inQuote
} else if (ch === ',' && !inQuote) {
values.push(cur); cur = ''
} else { cur += ch }
}
values.push(cur)
return values
}
// ─── SAS format <-> ISO conversions ──────────────────────────────────────────
/**
* Derives a DDTYPE (DATE, DATETIME, TIME, N, C) from a SAS column format string.
*/
function getDdType(col) {
const fmt = (col.format || '').toLowerCase()
if (fmt.startsWith('datetime') || fmt.startsWith('e8601dt')) return 'DATETIME'
if (fmt.startsWith('date') || fmt.startsWith('yymmdd') || fmt.startsWith('ddmmyy') || fmt.startsWith('mmddyy')) return 'DATE'
if (fmt.startsWith('time')) return 'TIME'
return col.type === 'N' ? 'N' : 'C'
}
/**
* Applies a SAS format to a raw numeric value, producing the display string.
* DATE: 42 -> "12FEB1960"
* DATETIME: 42 -> "01JAN1960:00:00:42"
* TIME: 42 -> "0:00:42"
*/
function formatSasValue(value, ddtype) {
if (value === null || value === undefined || value === '') return String(value)
if (typeof value !== 'number') return String(value)
if (ddtype === 'DATE') {
const d = new Date(SAS_EPOCH_MS + value * 86400000)
return `${d.getUTCDate()}${MONTHS_ABBR[d.getUTCMonth()]}${d.getUTCFullYear()}`
}
if (ddtype === 'DATETIME') {
const d = new Date(SAS_EPOCH_MS + value * 1000)
return `${d.getUTCDate()}${MONTHS_ABBR[d.getUTCMonth()]}${d.getUTCFullYear()}:${String(d.getUTCHours()).padStart(2,'0')}:${String(d.getUTCMinutes()).padStart(2,'0')}:${String(d.getUTCSeconds()).padStart(2,'0')}`
}
if (ddtype === 'TIME') {
const h = Math.floor(value / 3600)
const m = Math.floor((value % 3600) / 60)
const s = value % 60
return `${h}:${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')}`
}
return String(value)
}
/**
* Converts a numeric SAS value to the ISO string Handsontable expects.
* DATE: 42 -> "1960-02-12"
* DATETIME: 42 -> "1960-01-01 00:00:42"
* TIME: 42 -> "00:00:42"
*/
function sasToIso(value, ddtype) {
if (value === null || value === undefined || value === '') return value
if (typeof value !== 'number') return value
if (ddtype === 'DATE') {
const d = new Date(SAS_EPOCH_MS + value * 86400000)
return `${d.getUTCFullYear()}-${String(d.getUTCMonth()+1).padStart(2,'0')}-${String(d.getUTCDate()).padStart(2,'0')}`
}
if (ddtype === 'DATETIME') {
const d = new Date(SAS_EPOCH_MS + value * 1000)
return `${d.getUTCFullYear()}-${String(d.getUTCMonth()+1).padStart(2,'0')}-${String(d.getUTCDate()).padStart(2,'0')} ${String(d.getUTCHours()).padStart(2,'0')}:${String(d.getUTCMinutes()).padStart(2,'0')}:${String(d.getUTCSeconds()).padStart(2,'0')}`
}
if (ddtype === 'TIME') {
const h = Math.floor(value / 3600)
const m = Math.floor((value % 3600) / 60)
const s = value % 60
return `${String(h).padStart(2,'0')}:${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')}`
}
return value
}
/**
* Converts an ISO-formatted string (as sent by the editor) back to a SAS numeric.
* DATE: "1960-02-12" -> 42
* DATETIME: "1960-01-01 00:00:42" -> 42
* TIME: "00:00:42" -> 42
* Non-temporal values pass through unchanged.
*/
function parseFormattedToSas(value, ddtype) {
if (value === null || value === undefined || value === '') return value
if (ddtype !== 'DATE' && ddtype !== 'DATETIME' && ddtype !== 'TIME') return value
if (typeof value === 'number') return value
const str = String(value)
if (ddtype === 'DATE') {
const m = str.match(/^(\d{4})-(\d{2})-(\d{2})$/)
if (m) return Math.round((Date.UTC(+m[1], +m[2]-1, +m[3]) - SAS_EPOCH_MS) / 86400000)
return value
}
if (ddtype === 'DATETIME') {
const m = str.match(/^(\d{4})-(\d{2})-(\d{2})[ T](\d{2}):(\d{2}):(\d{2})/)
if (m) return Math.round((Date.UTC(+m[1], +m[2]-1, +m[3], +m[4], +m[5], +m[6]) - SAS_EPOCH_MS) / 1000)
return value
}
if (ddtype === 'TIME') {
const parts = str.split(':')
if (parts.length >= 3) return (+parts[0]) * 3600 + (+parts[1]) * 60 + (+parts[2])
return value
}
return value
}
/**
* Handles either numeric or string temporal values, converting to ISO for
* Handsontable. Numeric values use sasToIso; string values use the legacy
* regex parsing (for backwards compatibility with old data files).
*/
function formatCellValue(value, ddtype) {
if (value === null || value === undefined || value === '') return value
if (typeof value === 'number') return sasToIso(value, ddtype)
const str = String(value)
if (ddtype === 'DATE') {
const m = str.match(/^(\d{1,2})([A-Z]{3})(\d{4})$/)
if (m) return `${m[3]}-${MONTHS_NUM[m[2]]}-${m[1].padStart(2,'0')}`
return str
}
if (ddtype === 'DATETIME') {
const m = str.match(/^(\d{1,2})([A-Z]{3})(\d{4}):(\d{1,2}):(\d{2}):(\d{2})$/)
if (m) return `${m[3]}-${MONTHS_NUM[m[2]]}-${m[1].padStart(2,'0')} ${m[4].padStart(2,'0')}:${m[5]}:${m[6]}`
return str
}
if (ddtype === 'TIME') {
const parts = str.split(':')
if (parts.length >= 3) return `${parts[0].padStart(2,'0')}:${parts[1].padStart(2,'0')}:${parts[2].padStart(2,'0')}`
return str
}
return value
}
// ─── DC data file helpers ────────────────────────────────────────────────────
/**
* Creates a loadTableData function bound to a specific data directory.
* const loadTableData = makeTableLoader(dataDir)
* const mpeXTest = loadTableData('MPE_X_TEST')
*/
function makeTableLoader(dataDir) {
return function loadTableData(tableName) {
try {
const file = nodePath.resolve(dataDir, tableName.toLowerCase() + '.json')
return JSON.parse(fs.readFileSync(file, {encoding:'utf8'}).toString())
} catch(err) { return null }
}
}
/**
* Loads just the column schema (array of column metadata) for a table.
*/
function loadTableSchema(dataDir, tableName) {
const data = makeTableLoader(dataDir)(tableName)
return (data && data.columns) ? data.columns : []
}
/**
* Builds a $sasdata/$viewdata vars entry for a column.
* Temporal columns are sent as char ($200.) by the real SAS backend.
*/
function sasVarsEntry(col) {
const ddtype = getDdType(col)
if (ddtype === 'DATE' || ddtype === 'DATETIME' || ddtype === 'TIME') {
return { format: '$200.', label: col.label || col.name, length: '200', type: 'char' }
}
const fmt = col.type === 'N' ? (col.format || 'best.') : ('$' + col.length + '.')
return { format: fmt, label: col.label || col.name, length: String(col.length), type: col.type === 'N' ? 'num' : 'char' }
}
// ─── %webout(OPEN/OBJ/CLOSE) emulation ───────────────────────────────────────
/**
* Internal buffer for the webOut stream.
* webOutOpen() starts it, webOutObj() appends tables, webOutClose()
* finalises and assigns to _webout.
*/
let _webOutBuf = ''
let _webOutFirst = true
/**
* Opens the JSON stream, writing the opening brace and PROCESSED_DTTM.
* Mirrors %webout(OPEN).
*
* Usage:
* webOutOpen()
* webOutObj(rows, 'sasdata', { vars })
* webOutObj(params, 'sasparams')
* webOutClose()
*/
function webOutOpen() {
const now = new Date()
const pad = n => String(n).padStart(2, '0')
const processedDttm = now.getFullYear() + '-' + pad(now.getMonth()+1) + '-' + pad(now.getDate()) +
'T' + pad(now.getHours()) + ':' + pad(now.getMinutes()) + ':' + pad(now.getSeconds()) +
'.' + String(now.getMilliseconds()).padStart(3,'0')
_webOutBuf = '{"PROCESSED_DTTM":"' + processedDttm + '"'
_webOutFirst = true
}
/**
* Appends a table to the JSON stream.
* Mirrors %webout(OBJ,ds,dslabel=,showmeta=).
*
* @param {Array<Object>} rows - Array of row objects to send as a JSON array.
* @param {string} label - The key name in the JSON (e.g. 'sasdata', 'sasparams').
* @param {Object} [meta] - Optional metadata object. If provided, it is sent
* as `$label` (e.g. `$sasdata`), matching the showmeta=YES output from SAS.
* Typically { vars: { COL1: {format,label,length,type}, ... } }.
*/
function webOutObj(rows, label, meta) {
if (_webOutFirst) { _webOutBuf += ','; _webOutFirst = false }
else _webOutBuf += ','
_webOutBuf += '"' + label + '":' + JSON.stringify(rows)
if (meta) {
_webOutBuf += ',"$' + label + '":' + JSON.stringify(meta)
}
}
/**
* Closes the JSON stream, appends the standard SAS runtime variables
* (SYSDATE, SYSCC, _PROGRAM, etc.), and assigns the final JSON string to
* the `_webout` variable that the SASjs Server reads.
* Mirrors %webout(CLOSE).
*/
function webOutClose() {
_webOutBuf += '}'
_webout = _webOutBuf
}
/**
* Convenience: builds a complete response in one call.
* Opens, adds each table, closes.
*
* @param {Object} tables - { label1: { rows: [...], meta: {...} }, label2: { rows: [...] } }
*/
function webOutSend(tables) {
webOutOpen()
for (const [label, entry] of Object.entries(tables)) {
webOutObj(entry.rows, label, entry.meta)
}
webOutClose()
}
+180 -309
View File
@@ -6,248 +6,111 @@ const driveRoot = nodePath.resolve(sasjsRoot, 'drive')
const dcLibref = 'DC_JSLIB'
const dataDir = nodePath.resolve(driveRoot, 'files', appLoc, 'data', dcLibref)
let FILTER_TEXT = ''
// Load shared DC mock utilities
eval(fs.readFileSync(nodePath.resolve(driveRoot, 'files', appLoc, 'services', 'dcMockUtils.js'), 'utf8'))
// Read SASControlTable from the adapter input
let sasControlTableFileText = ''
if (typeof _WEBIN_NAME1 !== 'undefined' && _WEBIN_NAME1 && _WEBIN_NAME1.includes('SASControlTable')) {
sasControlTableFileText = _WEBIN_FILEREF1.toString()
} else if (typeof _WEBIN_FILENAME1 !== 'undefined' && _WEBIN_FILENAME1 && _WEBIN_FILENAME1.includes('SASControlTable')) {
sasControlTableFileText = _WEBIN_FILEREF1.toString()
}
const loadTableData = makeTableLoader(dataDir)
// Extract the requested table name from SASControlTable
// The frontend sends LIBDS (e.g. "DC_JSLIB.MPE_X_TEST"), not separate LIBREF/DSN
// Adapter CSV format: "LIBDS:$100.\r\nDC_JSLIB.MPE_X_TEST\r\n"
// ─── Parse input ──────────────────────────────────────────────────────────────
const _sctRow = fetchTable('SASControlTable')[0] || {}
let requestedLibref = dcLibref
let requestedTable = ''
try {
const lines = sasControlTableFileText.split(/\r?\n/)
if (lines.length >= 2) {
const headers = lines[0].trim().split(/\s+/).map(h => h.split(':')[0].trim().toLowerCase())
const values = lines[1].trim().split(',')
const libdsIndex = headers.indexOf('libds')
if (libdsIndex >= 0 && values[libdsIndex]) {
const libds = values[libdsIndex].trim()
const parts = libds.split('.')
if (parts.length >= 2) {
requestedLibref = parts[0]
requestedTable = parts[1]
}
}
// Fallback: check for separate LIBREF/DSN columns
if (!requestedTable) {
const dsIndex = headers.indexOf('dsn')
const libIndex = headers.indexOf('libref')
if (dsIndex >= 0 && values[dsIndex]) requestedTable = values[dsIndex].trim()
if (libIndex >= 0 && values[libIndex]) requestedLibref = values[libIndex].trim()
}
}
} catch(err) {}
// Also check for filter_pk in the SASControlTable
try {
const lines = sasControlTableFileText.split(/\r?\n/)
if (lines.length >= 2) {
const headers = lines[0].trim().split(/\s+/).map(h => h.split(':')[0].trim().toLowerCase())
const values = lines[1].trim().split(',')
const filterIndex = headers.indexOf('filter_rk')
if (filterIndex >= 0 && values[filterIndex] === '1') {
const filterStore = nodePath.resolve(driveRoot, 'files', appLoc, 'mock-storage', 'filter.txt')
try { FILTER_TEXT = fs.readFileSync(filterStore, {encoding:'utf8'}).toString() } catch(e) {}
}
}
} catch(err) {}
// Helper: load a table JSON file from the makedata data directory
function loadTableData(tableName) {
try {
const file = nodePath.resolve(dataDir, tableName.toLowerCase() + '.json')
const raw = fs.readFileSync(file, {encoding:'utf8'}).toString()
return JSON.parse(raw)
} catch(err) {
return null
}
if (_sctRow.LIBDS) {
const parts = _sctRow.LIBDS.split('.')
if (parts.length >= 2) { requestedLibref = parts[0]; requestedTable = parts[1] }
}
if (!requestedTable) {
if (_sctRow.DSN) requestedTable = _sctRow.DSN.trim()
if (_sctRow.LIBREF) requestedLibref = _sctRow.LIBREF.trim()
}
// Helper: convert a schema column to the getdata "cols" format
function schemaToCols(columns) {
return columns.map(col => {
const fmt = col.format || ''
let ddtype = col.type === 'N' ? 'N' : 'C'
if (fmt.startsWith('datetime') || fmt.startsWith('E8601DT')) ddtype = 'DATETIME'
else if (fmt.startsWith('date')) ddtype = 'DATE'
else if (fmt.startsWith('time')) ddtype = 'TIME'
const fmtname = fmt
? fmt.replace(/[\d.]+$/, '').replace('datetime', 'DATETIME').replace('date', 'DATE').replace('time', 'TIME').replace('best', 'BEST').replace('E8601DT', 'DATETIME')
: ''
// COLTYPE type maps to DDTYPE: date, datetime, time, numeric, or omitted (character)
let coltype
if (ddtype === 'DATE') {
coltype = `{"data":"${col.name}","type":"date"}`
} else if (ddtype === 'DATETIME') {
coltype = `{"data":"${col.name}","type":"datetime"}`
} else if (ddtype === 'TIME') {
coltype = `{"data":"${col.name}","type":"time"}`
} else if (ddtype === 'N') {
coltype = `{"data":"${col.name}","type":"numeric","format":"0"}`
} else {
coltype = `{"data":"${col.name}"}`
}
return {
NAME: col.name,
LABEL: col.label || col.name,
FMTNAME: fmtname || ' ',
DDTYPE: ddtype,
CLS_RULE: 'READ',
MEMLABEL: ' ',
DESC: ' ',
LONGDESC: ' ',
COLTYPE: coltype
}
})
}
// ─── Load table data and schema ──────────────────────────────────────────────
// Helper: compute maxvarlengths from actual row data
// Row keys may be any case, so do case-insensitive lookup
function computeMaxVarLengths(columns, rows) {
return columns.map(col => {
let maxLen = 0
const lcName = col.name.toLowerCase()
for (const row of rows) {
// Try exact match first, then case-insensitive
let val = row[col.name]
if (val === undefined) val = row[lcName]
if (val === undefined) {
const key = Object.keys(row).find(k => k.toLowerCase() === lcName)
if (key) val = row[key]
}
if (val !== undefined && val !== null) {
const len = String(val).length
if (len > maxLen) maxLen = len
}
}
return { NAME: col.name.toLowerCase(), MAXLEN: maxLen }
})
}
// Helper: convert a SAS date/datetime/time value to the ISO format expected by Handsontable
// SAS dates: "12FEB1960" -> "1960-02-12"
// SAS datetimes: "01JAN1960:00:00:42" -> "1960-01-01 00:00:42"
// SAS times: "0:00:42" or "0:07:02" -> "00:00:42" or "00:07:02"
function formatCellValue(value, ddtype) {
if (value === null || value === undefined || value === '') return value
const str = String(value)
if (ddtype === 'DATE') {
// SAS date: DDMMMYYYY -> YYYY-MM-DD
const months = {JAN:'01',FEB:'02',MAR:'03',APR:'04',MAY:'05',JUN:'06',JUL:'07',AUG:'08',SEP:'09',OCT:'10',NOV:'11',DEC:'12'}
const m = str.match(/^(\d{1,2})([A-Z]{3})(\d{4})$/)
if (m) return `${m[3]}-${months[m[2]]}-${m[1].padStart(2,'0')}`
return str
}
if (ddtype === 'DATETIME') {
// SAS datetime: DDMMMYYYY:HH:MM:SS -> YYYY-MM-DD HH:mm:ss
const months = {JAN:'01',FEB:'02',MAR:'03',APR:'04',MAY:'05',JUN:'06',JUL:'07',AUG:'08',SEP:'09',OCT:'10',NOV:'11',DEC:'12'}
const m = str.match(/^(\d{1,2})([A-Z]{3})(\d{4}):(\d{1,2}):(\d{2}):(\d{2})$/)
if (m) return `${m[3]}-${months[m[2]]}-${m[1].padStart(2,'0')} ${m[4].padStart(2,'0')}:${m[5]}:${m[6]}`
return str
}
if (ddtype === 'TIME') {
// SAS time: H:MM:SS or H:MM:SS -> HH:mm:ss
const parts = str.split(':')
if (parts.length >= 3) {
return `${parts[0].padStart(2,'0')}:${parts[1].padStart(2,'0')}:${parts[2].padStart(2,'0')}`
}
return str
}
return value
}
// Helper: prepend _____DELETE__THIS__RECORD_____ to rows and build $sasdata vars
// Also normalises row keys to match column names (uppercase)
// Also formats date/datetime/time values to ISO format for Handsontable
function addDeleteFlag(columns, rows) {
// Build a lookup from lowercase column name to { name, ddtype }
const colLookup = {}
for (const col of columns) {
const fmt = (col.format || '').toLowerCase()
let ddtype = col.type === 'N' ? 'N' : 'C'
if (fmt.startsWith('datetime') || fmt.startsWith('e8601dt')) ddtype = 'DATETIME'
else if (fmt.startsWith('date')) ddtype = 'DATE'
else if (fmt.startsWith('time')) ddtype = 'TIME'
colLookup[col.name.toLowerCase()] = { name: col.name, ddtype }
}
const augmentedRows = rows.map(r => {
const normalised = {}
for (const key of Object.keys(r)) {
const info = colLookup[key.toLowerCase()]
const targetKey = info ? info.name : key
normalised[targetKey] = info ? formatCellValue(r[key], info.ddtype) : r[key]
}
return {
_____DELETE__THIS__RECORD_____: 'No',
...normalised
}
})
// $sasdata vars: date/datetime/time are converted to char strings by SAS
const vars = { _____DELETE__THIS__RECORD_____: { format: '$3.', label: '_____DELETE__THIS__RECORD_____', length: '3', type: 'char' } }
for (const col of columns) {
const info = colLookup[col.name.toLowerCase()]
const isTemporal = info && (info.ddtype === 'DATE' || info.ddtype === 'DATETIME' || info.ddtype === 'TIME')
if (isTemporal) {
vars[col.name] = { format: '$200.', label: col.label || col.name, length: '200', type: 'char' }
} else {
const fmt = col.type === 'N' ? (col.format || 'best.') : ('$' + col.length + '.')
vars[col.name] = { format: fmt, label: col.label || col.name, length: String(col.length), type: col.type === 'N' ? 'num' : 'char' }
}
}
return { augmentedRows, vars }
}
// Load the requested table's data
const tableData = loadTableData(requestedTable)
// Load DQ rules for this table from MPE_VALIDATIONS
const validationsData = loadTableData('MPE_VALIDATIONS')
let dqrules = []
let dqdata = []
if (validationsData && validationsData.rows) {
dqrules = validationsData.rows
.filter(r => r.base_lib === requestedLibref && r.base_ds === requestedTable)
.map(r => ({ BASE_COL: r.base_col, RULE_TYPE: r.rule_type, RULE_VALUE: r.rule_value, X: 0 }))
}
// Load DQ dropdown data for this table from MPE_SELECTBOX
const selectboxData = loadTableData('MPE_SELECTBOX')
if (selectboxData && selectboxData.rows) {
dqdata = selectboxData.rows
.filter(r => r.select_lib === requestedLibref && r.select_ds === requestedTable)
.map(r => ({ BASE_COL: r.base_column, RULE_VALUE: r.base_column, RULE_DATA: r.selectbox_value, SELECTBOX_ORDER: r.selectbox_order }))
}
// Load table registration from MPE_TABLES for sasparams
// Load table registration from MPE_TABLES (needed for PK detection, temporal
// column exclusion, and sasparams)
const mpeTablesData = loadTableData('MPE_TABLES')
let tableReg = null
if (mpeTablesData && mpeTablesData.rows) {
tableReg = mpeTablesData.rows.find(r => r.libref === requestedLibref && r.dsn === requestedTable)
}
// Build the response
// ─── DQ rules (from MPE_VALIDATIONS) ─────────────────────────────────────────
const validationsData = loadTableData('MPE_VALIDATIONS')
let dqrules = []
let dqdata = []
if (validationsData && validationsData.rows) {
const pkCols = new Set()
if (tableReg && tableReg.buskey) {
tableReg.buskey.trim().split(/\s+/).forEach(c => pkCols.add(c.toUpperCase()))
}
dqrules = validationsData.rows
.filter(r => r.base_lib === requestedLibref && r.base_ds === requestedTable)
.map(r => ({
BASE_COL: r.base_col,
RULE_TYPE: r.rule_type,
RULE_VALUE: r.rule_value,
X: pkCols.has(r.base_col.toUpperCase()) ? 0 : 1
}))
}
// ─── DQ dropdown data (from MPE_SELECTBOX + SOFTSELECT from table data) ──────
const selectboxData = loadTableData('MPE_SELECTBOX')
if (selectboxData && selectboxData.rows) {
dqdata = selectboxData.rows
.filter(r => r.select_lib === requestedLibref && r.select_ds === requestedTable)
.map(r => ({
BASE_COL: r.base_column,
RULE_VALUE: r.base_column,
RULE_DATA: r.selectbox_value,
SELECTBOX_ORDER: r.selectbox_order
}))
}
// For SOFTSELECT/HARDSELECT rules that reference the table's own data,
// generate dropdown values from the actual table rows
if (tableData && tableData.rows && tableData.columns) {
const selectRules = dqrules.filter(r =>
(r.RULE_TYPE === 'SOFTSELECT' || r.RULE_TYPE === 'HARDSELECT') && r.RULE_VALUE.includes('.'))
for (const rule of selectRules) {
const parts = rule.RULE_VALUE.split('.')
const colName = parts[parts.length - 1]
const lcName = colName.toLowerCase()
const seen = new Set()
let order = 1
for (const row of tableData.rows) {
let val = row[colName]
if (val === undefined) val = row[lcName]
if (val === undefined) {
const key = Object.keys(row).find(k => k.toLowerCase() === lcName)
if (key) val = row[key]
}
if (val !== undefined && val !== null) {
const strVal = String(val)
if (!seen.has(strVal)) {
seen.add(strVal)
dqdata.push({ BASE_COL: rule.BASE_COL, RULE_VALUE: rule.RULE_VALUE, RULE_DATA: strVal, SELECTBOX_ORDER: order++ })
}
}
}
}
}
// ─── Build response ──────────────────────────────────────────────────────────
let response
if (tableData && tableData.columns && tableData.rows) {
// For TXTEMPORAL and BITEMPORAL tables, the VAR_TXFROM / VAR_TXTO columns
// are technical versioning columns that should be excluded from the editor
// Exclude temporal columns (TX_FROM/TX_TO etc.) from the editor view
let excludeCols = new Set()
if (tableReg && (tableReg.loadtype === 'TXTEMPORAL' || tableReg.loadtype === 'BITEMPORAL')) {
if (tableReg.var_txfrom) excludeCols.add(tableReg.var_txfrom.toUpperCase())
if (tableReg.var_txto) excludeCols.add(tableReg.var_txto.toUpperCase())
}
// For BITEMPORAL, also exclude VAR_BUSFROM / VAR_BUSTO
if (tableReg && tableReg.loadtype === 'BITEMPORAL') {
if (tableReg.var_busfrom) excludeCols.add(tableReg.var_busfrom.toUpperCase())
if (tableReg.var_busto) excludeCols.add(tableReg.var_busto.toUpperCase())
@@ -262,29 +125,86 @@ if (tableData && tableData.columns && tableData.rows) {
return copy
})
const { augmentedRows, vars } = addDeleteFlag(visibleColumns, visibleRows)
// Augment rows: add delete flag, normalise keys, convert temporal values to ISO
const colLookup = {}
for (const col of visibleColumns) {
colLookup[col.name.toLowerCase()] = { name: col.name, ddtype: getDdType(col) }
}
const augmentedRows = visibleRows.map(r => {
const normalised = {}
for (const key of Object.keys(r)) {
const info = colLookup[key.toLowerCase()]
const targetKey = info ? info.name : key
normalised[targetKey] = info ? formatCellValue(r[key], info.ddtype) : r[key]
}
return { _____DELETE__THIS__RECORD_____: 'No', ...normalised }
})
// $sasdata vars: temporal columns are char ($200.), others keep their SAS type
const vars = { _____DELETE__THIS__RECORD_____: { format: '$3.', label: '_____DELETE__THIS__RECORD_____', length: '3', type: 'char' } }
for (const col of visibleColumns) {
vars[col.name] = sasVarsEntry(col)
}
const colHeaders = ['_____DELETE__THIS__RECORD_____', ...visibleColumns.map(c => c.name)]
// Determine DTVARS, DTTMVARS, TMVARS from column formats
let dtVars = []
let dttmVars = []
let tmVars = []
let dtVars = [], dttmVars = [], tmVars = []
for (const col of visibleColumns) {
const fmt = (col.format || '').toLowerCase()
if (fmt.startsWith('datetime') || fmt.startsWith('e8601dt')) dttmVars.push(col.name)
else if (fmt.startsWith('date')) dtVars.push(col.name)
else if (fmt.startsWith('time')) tmVars.push(col.name)
const ddtype = getDdType(col)
if (ddtype === 'DATETIME') dttmVars.push(col.name)
else if (ddtype === 'DATE') dtVars.push(col.name)
else if (ddtype === 'TIME') tmVars.push(col.name)
}
// Build cols array
const cols = visibleColumns.map(col => {
const ddtype = getDdType(col)
const fmtname = col.format
? col.format.replace(/[\d.]+$/, '').replace('datetime', 'DATETIME').replace('date', 'DATE').replace('time', 'TIME').replace('best', 'BEST').replace('E8601DT', 'DATETIME')
: ' '
let coltype
if (ddtype === 'DATE') coltype = `{"data":"${col.name}","type":"date"}`
else if (ddtype === 'DATETIME') coltype = `{"data":"${col.name}","type":"datetime"}`
else if (ddtype === 'TIME') coltype = `{"data":"${col.name}","type":"time"}`
else if (ddtype === 'N') coltype = `{"data":"${col.name}","type":"numeric","format":"0"}`
else coltype = `{"data":"${col.name}"}`
return {
NAME: col.name,
LABEL: col.label || col.name,
FMTNAME: fmtname || ' ',
DDTYPE: ddtype,
CLS_RULE: 'READ',
MEMLABEL: ' ',
DESC: ' ',
LONGDESC: ' ',
COLTYPE: coltype
}
}).sort((a, b) => a.NAME.localeCompare(b.NAME))
// Build maxvarlengths
const maxvarlengths = [
{ NAME: '_____DELETE__THIS__RECORD_____', MAXLEN: 3 },
...visibleColumns.map(col => {
let maxLen = 0
const lcName = col.name.toLowerCase()
for (const row of augmentedRows) {
let val = row[col.name]
if (val === undefined) val = row[lcName]
if (val !== undefined && val !== null) {
const len = String(val).length
if (len > maxLen) maxLen = len
}
}
return { NAME: col.name.toLowerCase(), MAXLEN: maxLen }
})
]
response = {
SYSDATE: '26SEP22',
SYSTIME: '08:30',
approvers: [
{ PERSONNAME: 'sasdemo', EMAIL: 'sasdemo', USERID: 'sasdemo' }
],
cols: schemaToCols(visibleColumns),
dqdata: dqdata,
dqrules: dqrules,
SYSDATE: '26SEP22', SYSTIME: '08:30',
approvers: [{ PERSONNAME: 'sasdemo', EMAIL: 'sasdemo', USERID: 'sasdemo' }],
cols,
dqdata, dqrules,
dsmeta: [
{ ODS_TABLE: 'ATTRIBUTES', NAME: 'Data Set Name', VALUE: requestedLibref + '.' + requestedTable },
{ ODS_TABLE: 'ATTRIBUTES', NAME: 'Observations', VALUE: String(tableData.rows.length) },
@@ -292,16 +212,13 @@ if (tableData && tableData.columns && tableData.rows) {
{ ODS_TABLE: 'ATTRIBUTES', NAME: 'Variables', VALUE: String(tableData.columns.length) },
{ ODS_TABLE: 'ATTRIBUTES', NAME: 'Engine', VALUE: 'V9' }
],
maxvarlengths: [
{ NAME: '_____DELETE__THIS__RECORD_____', MAXLEN: 3 },
...computeMaxVarLengths(visibleColumns, augmentedRows)
],
maxvarlengths,
query: [],
sasdata: augmentedRows,
$sasdata: { vars: vars },
$sasdata: { vars },
sasparams: [{
COLHEADERS: colHeaders.join(','),
FILTER_TEXT: FILTER_TEXT || ' ',
FILTER_TEXT: ' ',
PKCNT: tableReg && tableReg.buskey ? tableReg.buskey.trim().split(/\s+/).length : 0,
PK: tableReg ? tableReg.buskey || '' : '',
DTVARS: dtVars.length ? ' ' + dtVars.join(' ') : '',
@@ -312,84 +229,38 @@ if (tableData && tableData.columns && tableData.rows) {
CLS_FLAG: 0,
ISMAP: 0
}],
versions: [],
xl_rules: [],
_DEBUG: '',
_METAUSER: 'sasdemo@SAS',
_METAPERSON: 'sasdemo',
_PROGRAM: _program,
AUTOEXEC: '',
MF_GETUSER: 'sasdemo',
SYSCC: '0',
SYSENCODING: 'utf-8',
SYSERRORTEXT: '',
SYSHOSTNAME: 'sasjs-server',
SYSPROCESSID: '0',
SYSPROCESSMODE: 'Stored Program',
SYSPROCESSNAME: '',
SYSJOBID: '0',
SYSSCPL: 'LINUX',
SYSSITE: '123',
SYSUSERID: 'sasdemo',
SYSVLONG: '9.04.01M7P080520',
SYSWARNINGTEXT: '',
END_DTTM: new Date().toISOString(),
MEMSIZE: '0KB'
_DEBUG: '', _METAUSER: 'sasdemo@SAS', _METAPERSON: 'sasdemo',
_PROGRAM: _program, AUTOEXEC: '', MF_GETUSER: 'sasdemo',
SYSCC: '0', SYSENCODING: 'utf-8', SYSERRORTEXT: '',
SYSHOSTNAME: 'sasjs-server', SYSPROCESSID: '0',
SYSPROCESSMODE: 'Stored Program', SYSPROCESSNAME: '',
SYSJOBID: '0', SYSSCPL: 'LINUX', SYSSITE: '123',
SYSUSERID: 'sasdemo', SYSVLONG: '9.04.01M7P080520',
SYSWARNINGTEXT: '', END_DTTM: new Date().toISOString(), MEMSIZE: '0KB'
}
} else {
// Table not found - return minimal empty response
response = {
SYSDATE: '26SEP22',
SYSTIME: '08:30',
approvers: [],
cols: [],
dqdata: [],
dqrules: [],
SYSDATE: '26SEP22', SYSTIME: '08:30',
approvers: [], cols: [], dqdata: [], dqrules: [],
dsmeta: [
{ ODS_TABLE: 'ATTRIBUTES', NAME: 'Data Set Name', VALUE: requestedLibref + '.' + requestedTable },
{ ODS_TABLE: 'ATTRIBUTES', NAME: 'Observations', VALUE: '0' },
{ ODS_TABLE: 'ATTRIBUTES', NAME: 'Member Type', VALUE: 'DATA' }
],
maxvarlengths: [],
query: [],
sasdata: [],
$sasdata: { vars: {} },
sasparams: [{
COLHEADERS: '',
FILTER_TEXT: ' ',
PKCNT: 0,
PK: '',
DTVARS: '',
DTTMVARS: '',
TMVARS: '',
LOADTYPE: 'UPDATE',
RK_FLAG: 0,
CLS_FLAG: 0,
ISMAP: 0
}],
xl_rules: [],
_DEBUG: '',
_METAUSER: 'sasdemo@SAS',
_METAPERSON: 'sasdemo',
_PROGRAM: _program,
AUTOEXEC: '',
MF_GETUSER: 'sasdemo',
SYSCC: '0',
SYSENCODING: 'utf-8',
SYSERRORTEXT: '',
SYSHOSTNAME: 'sasjs-server',
SYSPROCESSID: '0',
SYSPROCESSMODE: 'Stored Program',
SYSPROCESSNAME: '',
SYSJOBID: '0',
SYSSCPL: 'LINUX',
SYSSITE: '123',
SYSUSERID: 'sasdemo',
SYSVLONG: '9.04.01M7P080520',
SYSWARNINGTEXT: '',
END_DTTM: new Date().toISOString(),
MEMSIZE: '0KB'
maxvarlengths: [], query: [], sasdata: [], $sasdata: { vars: {} },
sasparams: [{ COLHEADERS: '', FILTER_TEXT: ' ', PKCNT: 0, PK: '', DTVARS: '', DTTMVARS: '', TMVARS: '', LOADTYPE: 'UPDATE', RK_FLAG: 0, CLS_FLAG: 0, ISMAP: 0 }],
versions: [], xl_rules: [],
_DEBUG: '', _METAUSER: 'sasdemo@SAS', _METAPERSON: 'sasdemo',
_PROGRAM: _program, AUTOEXEC: '', MF_GETUSER: 'sasdemo',
SYSCC: '0', SYSENCODING: 'utf-8', SYSERRORTEXT: '',
SYSHOSTNAME: 'sasjs-server', SYSPROCESSID: '0',
SYSPROCESSMODE: 'Stored Program', SYSPROCESSNAME: '',
SYSJOBID: '0', SYSSCPL: 'LINUX', SYSSITE: '123',
SYSUSERID: 'sasdemo', SYSVLONG: '9.04.01M7P080520',
SYSWARNINGTEXT: '', END_DTTM: new Date().toISOString(), MEMSIZE: '0KB'
}
console.log('Warning: table ' + requestedTable + ' not found in ' + dataDir)
}
_webout = JSON.stringify(response)
@@ -6213,10 +6213,10 @@ let other = {
MEMSIZE: '93GB'
}
if (_WEBIN_FILENAME1.includes('SASControlTable'))
jsDataFileText = _WEBIN_FILEREF1.toString()
if (_WEBIN_FILENAME2.includes('SASControlTable'))
jsDataFileText = _WEBIN_FILEREF2.toString()
if (_webin_filename1.includes('SASControlTable'))
jsDataFileText = _webin_fileref1.toString()
if (_webin_filename2.includes('SASControlTable'))
jsDataFileText = _webin_fileref2.toString()
if (jsDataFileText.length > 0) {
if (jsDataFileText.includes('MPE_TABLES')) {
+53 -129
View File
@@ -7,77 +7,30 @@ const dcLibref = 'DC_JSLIB'
const dataDir = nodePath.resolve(driveRoot, 'files', appLoc, 'data', dcLibref)
const stagingDir = nodePath.resolve(dataDir, 'staging')
// Ensure staging directory exists
if (!fs.existsSync(stagingDir)) {
fs.mkdirSync(stagingDir, { recursive: true })
}
if (!fs.existsSync(stagingDir)) fs.mkdirSync(stagingDir, { recursive: true })
// Helper: load a table JSON file
function loadTableData(tableName) {
try {
const file = nodePath.resolve(dataDir, tableName.toLowerCase() + '.json')
return JSON.parse(fs.readFileSync(file, {encoding:'utf8'}).toString())
} catch(err) { return null }
}
eval(fs.readFileSync(nodePath.resolve(driveRoot, 'files', appLoc, 'services', 'dcMockUtils.js'), 'utf8'))
const loadTableData = makeTableLoader(dataDir)
// Helper: save a table JSON file
function saveTableData(tableName, tableData) {
const file = nodePath.resolve(dataDir, tableName.toLowerCase() + '.json')
fs.writeFileSync(file, JSON.stringify(tableData, null, 2))
}
// Parse SASControlTable (ACTION, MESSAGE, LIBDS)
let action = 'LOAD'
let message = ''
let libds = ''
let sasControlTableFileText = ''
for (let i = 1; i <= 10; i++) {
const nameVar = '_WEBIN_NAME' + i
try {
const nameVal = eval(nameVar)
if (nameVal && nameVal.includes('SASControlTable')) {
const refVar = '_WEBIN_FILEREF' + i
sasControlTableFileText = eval(refVar).toString()
break
}
} catch(e) { break }
}
try {
const lines = sasControlTableFileText.split(/\r?\n/)
if (lines.length >= 2) {
const headers = lines[0].trim().split(/\s+/).map(h => h.split(':')[0].trim().toLowerCase())
const values = lines[1].trim().split(',')
const actionIdx = headers.indexOf('action')
const msgIdx = headers.indexOf('message')
const libdsIdx = headers.indexOf('libds')
if (actionIdx >= 0) action = values[actionIdx] || 'LOAD'
if (msgIdx >= 0) message = values[msgIdx] || ''
if (libdsIdx >= 0) libds = values[libdsIdx] || ''
}
} catch(err) {}
// ─── Parse input ──────────────────────────────────────────────────────────────
const _sctRow = fetchTable('SASControlTable')[0] || {}
let action = _sctRow.ACTION || 'LOAD'
let message = _sctRow.MESSAGE || ''
let libds = _sctRow.LIBDS || ''
const libref = libds.split('.')[0] || dcLibref
const dsn = libds.split('.')[1] || ''
// Parse jsdata (the edited rows from the grid)
let jsDataRows = []
let jsDataRaw = ''
const jsDataRaw = fetchRaw('jsdata')
let jsDataHeaders = []
for (let i = 1; i <= 10; i++) {
const nameVar = '_WEBIN_NAME' + i
try {
const nameVal = eval(nameVar)
if (nameVal && nameVal.toLowerCase() === 'jsdata') {
const refVar = '_WEBIN_FILEREF' + i
jsDataRaw = eval(refVar).toString()
break
}
} catch(e) { break }
}
let jsDataRows = []
if (jsDataRaw) {
try {
const lines = jsDataRaw.split(/\r?\n/)
@@ -87,34 +40,39 @@ if (jsDataRaw) {
const line = lines[i].trim()
if (!line) continue
const values = []
let cur = ''
let inQuote = false
let cur = '', inQuote = false
for (let j = 0; j < line.length; j++) {
const ch = line[j]
if (ch === '"') {
if (inQuote && line[j+1] === '"') { cur += '"'; j++ }
else inQuote = !inQuote
} else if (ch === ',' && !inQuote) {
values.push(cur)
cur = ''
} else {
cur += ch
}
if (ch === '"') { if (inQuote && line[j+1] === '"') { cur += '"'; j++ } else inQuote = !inQuote }
else if (ch === ',' && !inQuote) { values.push(cur); cur = '' }
else cur += ch
}
values.push(cur)
const row = {}
for (let k = 0; k < jsDataHeaders.length && k < values.length; k++) {
row[jsDataHeaders[k]] = values[k]
}
for (let k = 0; k < jsDataHeaders.length && k < values.length; k++) row[jsDataHeaders[k]] = values[k]
jsDataRows.push(row)
}
}
} catch(err) {
console.log('Error parsing jsdata: ' + err.message)
}
} catch(err) { console.log('Error parsing jsdata: ' + err.message) }
}
// Generate a unique table_id matching SAS mperef format
// Convert formatted date/datetime/time strings back to SAS numeric values
const schema = loadTableSchema(dataDir, dsn)
if (schema.length > 0) {
const colDdtypes = {}
for (const col of schema) colDdtypes[col.name.toUpperCase()] = getDdType(col)
jsDataRows = jsDataRows.map(row => {
const converted = {}
for (const key of Object.keys(row)) {
const ddtype = colDdtypes[key.toUpperCase()]
converted[key] = ddtype ? parseFormattedToSas(row[key], ddtype) : row[key]
}
return converted
})
}
// ─── Generate table_id and stage the data ────────────────────────────────────
const now = new Date()
const pad = (n, w) => String(n).padStart(w, '0')
const dtStr = now.getFullYear() + pad(now.getMonth()+1,2) + pad(now.getDate(),2) + '-' +
@@ -124,70 +82,36 @@ const rand6 = pad(Math.floor(Math.random() * 1000000), 6)
const pid4 = pad(process.pid % 10000, 4)
const tableId = `DC${dtStr}_${rand6}_${pid4}`
// Store the staged rows as a separate file in the staging directory
const stageFile = nodePath.resolve(stagingDir, tableId + '.json')
const stageData = {
table_id: tableId,
libds: libds,
libref: libref,
dsn: dsn,
headers: jsDataHeaders,
rows: jsDataRows
table_id: tableId, libds, libref, dsn,
headers: jsDataHeaders, rows: jsDataRows
}
fs.writeFileSync(stageFile, JSON.stringify(stageData, null, 2))
// Insert a record into MPE_SUBMIT
const submitTable = loadTableData('MPE_SUBMIT') || { name: 'MPE_SUBMIT', columns: [], rows: [] }
const submitRow = {
TABLE_ID: tableId,
SUBMIT_STATUS_CD: 'SUBMITTED',
BASE_LIB: libref,
BASE_DS: dsn,
SUBMITTED_BY_NM: 'sasdemo',
SUBMITTED_ON_DTTM: now.getTime() / 1000,
submitTable.rows.push({
TABLE_ID: tableId, SUBMIT_STATUS_CD: 'SUBMITTED',
BASE_LIB: libref, BASE_DS: dsn,
SUBMITTED_BY_NM: 'sasdemo', SUBMITTED_ON_DTTM: now.getTime() / 1000,
SUBMITTED_REASON_TXT: message,
INPUT_OBS: jsDataRows.length,
INPUT_VARS: jsDataHeaders.filter(h => h !== '_____DELETE__THIS__RECORD_____').length,
NUM_OF_APPROVALS_REQUIRED: 1,
NUM_OF_APPROVALS_REMAINING: 1,
REVIEWED_BY_NM: '',
REVIEWED_ON_DTTM: null
}
submitTable.rows.push(submitRow)
NUM_OF_APPROVALS_REQUIRED: 1, NUM_OF_APPROVALS_REMAINING: 1,
REVIEWED_BY_NM: '', REVIEWED_ON_DTTM: null
})
saveTableData('MPE_SUBMIT', submitTable)
console.log('Staged data written to: ' + stageFile)
console.log('table_id: ' + tableId)
console.log('libds: ' + libds)
console.log('rows: ' + jsDataRows.length)
_webout = JSON.stringify({
SYSDATE: '26SEP22',
SYSTIME: '08:43',
sasparams: [{
STATUS: 'SUCCESS',
DSID: tableId,
URL: ''
}],
_DEBUG: '',
_METAUSER: 'sasdemo@SAS',
_METAPERSON: 'sasdemo',
_PROGRAM: _program,
AUTOEXEC: '',
MF_GETUSER: 'sasdemo',
SYSCC: '0',
SYSENCODING: 'utf-8',
SYSERRORTEXT: '',
SYSHOSTNAME: 'sasjs-server',
SYSPROCESSID: '0',
SYSPROCESSMODE: 'Stored Program',
SYSPROCESSNAME: '',
SYSJOBID: '0',
SYSSCPL: 'LINUX',
SYSSITE: '123',
SYSUSERID: 'sasdemo',
SYSVLONG: '9.04.01M7P080520',
SYSWARNINGTEXT: '',
END_DTTM: new Date().toISOString(),
MEMSIZE: '0KB'
SYSDATE: '26SEP22', SYSTIME: '08:43',
sasparams: [{ STATUS: 'SUCCESS', DSID: tableId, URL: '' }],
_DEBUG: '', _METAUSER: 'sasdemo@SAS', _METAPERSON: 'sasdemo',
_PROGRAM: _program, AUTOEXEC: '', MF_GETUSER: 'sasdemo',
SYSCC: '0', SYSENCODING: 'utf-8', SYSERRORTEXT: '',
SYSHOSTNAME: 'sasjs-server', SYSPROCESSID: '0',
SYSPROCESSMODE: 'Stored Program', SYSPROCESSNAME: '',
SYSJOBID: '0', SYSSCPL: 'LINUX', SYSSITE: '123',
SYSUSERID: 'sasdemo', SYSVLONG: '9.04.01M7P080520',
SYSWARNINGTEXT: '', END_DTTM: new Date().toISOString(), MEMSIZE: '0KB'
})
@@ -1,29 +1,68 @@
_webout = `{"SYSDATE" : "07OCT22"
,"SYSTIME" : "12:25"
, "jsparams":
[
{"TABLE_ID":"DC20221007T122326121_612316_7259" ,"SUBMIT_STATUS_CD":"SUBMITTED" ,"BASE_LIB":"DC_JSLIB" ,"BASE_DS":"MPE_X_TEST" ,"SUBMITTED_BY_NM":"mihajlo" ,"SUBMITTED_ON":1980764606.22 ,"SUBMITTED_REASON_TXT":"" ,"INPUT_OBS":15 ,"INPUT_VARS":10 ,"NUM_OF_APPROVALS_REQUIRED":1 ,"NUM_OF_APPROVALS_REMAINING":1 ,"REVIEWED_BY_NM":"" ,"REVIEWED_ON":null ,"TABLE_NM":"DC_JSLIB.MPE_X_TEST" ,"BASE_TABLE":"DC_JSLIB.MPE_X_TEST" ,"REVIEWED_ON_DTTM":"." ,"SUBMITTED_ON_DTTM":"07OCT2022:12:23:26" ,"LIB_ENGINE":"WPD" }
]
,"_DEBUG" : ""
,"_PROGRAM" : "/30.SASApps/app/mihajlo/services/public/getchangeinfo"
,"AUTOEXEC" : "%2Fhome%2Fmihajlo%2Fsasjs_root%2Fsessions%2F20221007122549-44480-1665145549621%2Fautoexec.sas"
,"MF_GETUSER" : "mihajlo"
,"SYSCC" : "0"
,"SYSENCODING" : "utf-8"
,"SYSERRORTEXT" : ""
,"SYSHOSTINFOLONG" : ""
,"SYSHOSTNAME" : "sas.4gl.io"
,"SYSPROCESSID" : "41DD8404936CF0DC0000000000000000"
,"SYSPROCESSMODE" : "Stored Program"
,"SYSPROCESSNAME" : ""
,"SYSJOBID" : "726819"
,"SYSSCPL" : "LINUX"
,"syssite" : "123"
,"SYSTCPIPHOSTNAME" : "https://sas.4gl.io:5002"
,"SYSUSERID" : "mihajlo"
,"SYSVLONG" : "05.00.00.02.001146"
,"SYSWARNINGTEXT" : ""
,"END_DTTM" : "2022-10-07T12:25:57.433259"
,"MEMSIZE" : "0KB"
const nodePath = require('path')
let appLoc = nodePath.join(..._program.split('services')[0].split('/'))
const sasjsRoot = nodePath.resolve(weboutPath, '..', '..', '..')
const driveRoot = nodePath.resolve(sasjsRoot, 'drive')
const dcLibref = 'DC_JSLIB'
const dataDir = nodePath.resolve(driveRoot, 'files', appLoc, 'data', dcLibref)
eval(fs.readFileSync(nodePath.resolve(driveRoot, 'files', appLoc, 'services', 'dcMockUtils.js'), 'utf8'))
const loadTableData = makeTableLoader(dataDir)
// ─── Parse input: frontend sends SASControlTable with TABLE column ───────────
const _sctRow = fetchTable('SASControlTable')[0] || {}
const tableId = _sctRow.TABLE || _sctRow.table || ''
// ─── Load submit info from MPE_SUBMIT ────────────────────────────────────────
let jsparams = []
if (tableId) {
const submitData = loadTableData('MPE_SUBMIT')
if (submitData && submitData.rows) {
const row = submitData.rows.find(r => r.TABLE_ID === tableId)
if (row) {
const baseTable = row.BASE_LIB + '.' + row.BASE_DS
const submittedOn = new Date(row.SUBMITTED_ON_DTTM * 1000)
const pad = n => String(n).padStart(2, '0')
const submittedOnStr = submittedOn.getFullYear() + '-' + pad(submittedOn.getMonth()+1) + '-' + pad(submittedOn.getDate()) + ' ' +
pad(submittedOn.getHours()) + ':' + pad(submittedOn.getMinutes()) + ':' + pad(submittedOn.getSeconds())
jsparams = [{
TABLE_ID: row.TABLE_ID,
REVIEW_STATUS_ID: row.SUBMIT_STATUS_CD,
BASE_LIB: row.BASE_LIB,
BASE_DS: row.BASE_DS,
SUBMITTED_BY_NM: row.SUBMITTED_BY_NM,
SUBMITTED_ON: row.SUBMITTED_ON_DTTM,
SUBMITTED_REASON_TXT: row.SUBMITTED_REASON_TXT || '',
INPUT_OBS: row.INPUT_OBS,
INPUT_VARS: row.INPUT_VARS,
NUM_OF_APPROVALS_REQUIRED: row.NUM_OF_APPROVALS_REQUIRED,
NUM_OF_APPROVALS_REMAINING: row.NUM_OF_APPROVALS_REMAINING,
REVIEWED_BY_NM: row.REVIEWED_BY_NM || '',
REVIEWED_ON: row.REVIEWED_ON_DTTM,
TABLE_NM: baseTable,
BASE_TABLE: baseTable,
REVIEWED_ON_DTTM: row.REVIEWED_ON_DTTM
? new Date(row.REVIEWED_ON_DTTM * 1000).toISOString().replace('T',' ').replace(/\.\d+Z$/, '')
: '.',
SUBMITTED_ON_DTTM: submittedOnStr,
LIB_ENGINE: 'V9',
ALLOW_RESTORE: 'NO'
}]
}
}
}
`
_webout = JSON.stringify({
SYSDATE: '26SEP22', SYSTIME: '08:43', jsparams,
_DEBUG: '', _METAUSER: 'sasdemo@SAS', _METAPERSON: 'sasdemo',
_PROGRAM: _program, AUTOEXEC: '', MF_GETUSER: 'sasdemo',
SYSCC: '0', SYSENCODING: 'utf-8', SYSERRORTEXT: '',
SYSHOSTNAME: 'sasjs-server', SYSPROCESSID: '0',
SYSPROCESSMODE: 'Stored Program', SYSPROCESSNAME: '',
SYSJOBID: '0', SYSSCPL: 'LINUX', SYSSITE: '123',
SYSUSERID: 'sasdemo', SYSVLONG: '9.04.01M7P080520',
SYSWARNINGTEXT: '', END_DTTM: new Date().toISOString(), MEMSIZE: '0KB'
})
+56 -448
View File
@@ -1,449 +1,57 @@
_webout = `{
"SYSDATE": "26SEP22",
"SYSTIME": "08:49",
"vals": [
{
"FORMATTED": "0",
"UNFORMATTED": 0
},
{
"FORMATTED": "1",
"UNFORMATTED": 1
},
{
"FORMATTED": "3",
"UNFORMATTED": 3
},
{
"FORMATTED": "4",
"UNFORMATTED": 4
},
{
"FORMATTED": "5",
"UNFORMATTED": 5
},
{
"FORMATTED": "6",
"UNFORMATTED": 6
},
{
"FORMATTED": "7",
"UNFORMATTED": 7
},
{
"FORMATTED": "8",
"UNFORMATTED": 8
},
{
"FORMATTED": "9",
"UNFORMATTED": 9
},
{
"FORMATTED": "10",
"UNFORMATTED": 10
},
{
"FORMATTED": "11",
"UNFORMATTED": 11
},
{
"FORMATTED": "12",
"UNFORMATTED": 12
},
{
"FORMATTED": "13",
"UNFORMATTED": 13
},
{
"FORMATTED": "14",
"UNFORMATTED": 14
},
{
"FORMATTED": "15",
"UNFORMATTED": 15
},
{
"FORMATTED": "16",
"UNFORMATTED": 16
},
{
"FORMATTED": "17",
"UNFORMATTED": 17
},
{
"FORMATTED": "18",
"UNFORMATTED": 18
},
{
"FORMATTED": "19",
"UNFORMATTED": 19
},
{
"FORMATTED": "20",
"UNFORMATTED": 20
},
{
"FORMATTED": "21",
"UNFORMATTED": 21
},
{
"FORMATTED": "22",
"UNFORMATTED": 22
},
{
"FORMATTED": "23",
"UNFORMATTED": 23
},
{
"FORMATTED": "24",
"UNFORMATTED": 24
},
{
"FORMATTED": "25",
"UNFORMATTED": 25
},
{
"FORMATTED": "26",
"UNFORMATTED": 26
},
{
"FORMATTED": "27",
"UNFORMATTED": 27
},
{
"FORMATTED": "28",
"UNFORMATTED": 28
},
{
"FORMATTED": "29",
"UNFORMATTED": 29
},
{
"FORMATTED": "30",
"UNFORMATTED": 30
},
{
"FORMATTED": "31",
"UNFORMATTED": 31
},
{
"FORMATTED": "32",
"UNFORMATTED": 32
},
{
"FORMATTED": "33",
"UNFORMATTED": 33
},
{
"FORMATTED": "34",
"UNFORMATTED": 34
},
{
"FORMATTED": "35",
"UNFORMATTED": 35
},
{
"FORMATTED": "36",
"UNFORMATTED": 36
},
{
"FORMATTED": "37",
"UNFORMATTED": 37
},
{
"FORMATTED": "38",
"UNFORMATTED": 38
},
{
"FORMATTED": "39",
"UNFORMATTED": 39
},
{
"FORMATTED": "40",
"UNFORMATTED": 40
},
{
"FORMATTED": "41",
"UNFORMATTED": 41
},
{
"FORMATTED": "42",
"UNFORMATTED": 42
},
{
"FORMATTED": "43",
"UNFORMATTED": 43
},
{
"FORMATTED": "44",
"UNFORMATTED": 44
},
{
"FORMATTED": "45",
"UNFORMATTED": 45
},
{
"FORMATTED": "46",
"UNFORMATTED": 46
},
{
"FORMATTED": "47",
"UNFORMATTED": 47
},
{
"FORMATTED": "48",
"UNFORMATTED": 48
},
{
"FORMATTED": "49",
"UNFORMATTED": 49
},
{
"FORMATTED": "50",
"UNFORMATTED": 50
},
{
"FORMATTED": "51",
"UNFORMATTED": 51
},
{
"FORMATTED": "52",
"UNFORMATTED": 52
},
{
"FORMATTED": "53",
"UNFORMATTED": 53
},
{
"FORMATTED": "54",
"UNFORMATTED": 54
},
{
"FORMATTED": "55",
"UNFORMATTED": 55
},
{
"FORMATTED": "56",
"UNFORMATTED": 56
},
{
"FORMATTED": "57",
"UNFORMATTED": 57
},
{
"FORMATTED": "58",
"UNFORMATTED": 58
},
{
"FORMATTED": "59",
"UNFORMATTED": 59
},
{
"FORMATTED": "60",
"UNFORMATTED": 60
},
{
"FORMATTED": "61",
"UNFORMATTED": 61
},
{
"FORMATTED": "62",
"UNFORMATTED": 62
},
{
"FORMATTED": "63",
"UNFORMATTED": 63
},
{
"FORMATTED": "64",
"UNFORMATTED": 64
},
{
"FORMATTED": "65",
"UNFORMATTED": 65
},
{
"FORMATTED": "66",
"UNFORMATTED": 66
},
{
"FORMATTED": "67",
"UNFORMATTED": 67
},
{
"FORMATTED": "68",
"UNFORMATTED": 68
},
{
"FORMATTED": "69",
"UNFORMATTED": 69
},
{
"FORMATTED": "70",
"UNFORMATTED": 70
},
{
"FORMATTED": "71",
"UNFORMATTED": 71
},
{
"FORMATTED": "72",
"UNFORMATTED": 72
},
{
"FORMATTED": "73",
"UNFORMATTED": 73
},
{
"FORMATTED": "74",
"UNFORMATTED": 74
},
{
"FORMATTED": "75",
"UNFORMATTED": 75
},
{
"FORMATTED": "76",
"UNFORMATTED": 76
},
{
"FORMATTED": "77",
"UNFORMATTED": 77
},
{
"FORMATTED": "78",
"UNFORMATTED": 78
},
{
"FORMATTED": "79",
"UNFORMATTED": 79
},
{
"FORMATTED": "80",
"UNFORMATTED": 80
},
{
"FORMATTED": "81",
"UNFORMATTED": 81
},
{
"FORMATTED": "82",
"UNFORMATTED": 82
},
{
"FORMATTED": "83",
"UNFORMATTED": 83
},
{
"FORMATTED": "84",
"UNFORMATTED": 84
},
{
"FORMATTED": "85",
"UNFORMATTED": 85
},
{
"FORMATTED": "86",
"UNFORMATTED": 86
},
{
"FORMATTED": "87",
"UNFORMATTED": 87
},
{
"FORMATTED": "88",
"UNFORMATTED": 88
},
{
"FORMATTED": "89",
"UNFORMATTED": 89
},
{
"FORMATTED": "90",
"UNFORMATTED": 90
},
{
"FORMATTED": "91",
"UNFORMATTED": 91
},
{
"FORMATTED": "92",
"UNFORMATTED": 92
},
{
"FORMATTED": "93",
"UNFORMATTED": 93
},
{
"FORMATTED": "94",
"UNFORMATTED": 94
},
{
"FORMATTED": "95",
"UNFORMATTED": 95
},
{
"FORMATTED": "96",
"UNFORMATTED": 96
},
{
"FORMATTED": "97",
"UNFORMATTED": 97
},
{
"FORMATTED": "98",
"UNFORMATTED": 98
},
{
"FORMATTED": "99",
"UNFORMATTED": 99
},
{
"FORMATTED": "100",
"UNFORMATTED": 100
const nodePath = require('path')
let appLoc = nodePath.join(..._program.split('services')[0].split('/'))
const sasjsRoot = nodePath.resolve(weboutPath, '..', '..', '..')
const driveRoot = nodePath.resolve(sasjsRoot, 'drive')
const dcLibref = 'DC_JSLIB'
const dataDir = nodePath.resolve(driveRoot, 'files', appLoc, 'data', dcLibref)
eval(fs.readFileSync(nodePath.resolve(driveRoot, 'files', appLoc, 'services', 'dcMockUtils.js'), 'utf8'))
const loadTableData = makeTableLoader(dataDir)
// ─── Parse input: LIBDS format is LIBREF.TABLE.COLUMN ────────────────────────
const _sctRow = fetchTable('SASControlTable')[0] || {}
let libds = _sctRow.LIBDS || ''
const parts = libds.split('.')
let libref = parts[0] || dcLibref
let tableName = parts[1] || ''
let colName = parts[2] || ''
// ─── Extract distinct values for the requested column ────────────────────────
let sasdata = []
if (tableName && colName) {
const tableData = loadTableData(tableName)
if (tableData && tableData.rows) {
const lcName = colName.toLowerCase()
const seen = new Set()
for (const row of tableData.rows) {
let val = row[colName]
if (val === undefined) val = row[lcName]
if (val === undefined) {
const key = Object.keys(row).find(k => k.toLowerCase() === lcName)
if (key) val = row[key]
}
if (val !== undefined && val !== null) {
const strVal = String(val)
if (!seen.has(strVal)) {
seen.add(strVal)
sasdata.push({ val: strVal })
}
}
}
}
],
"$vals": {
"vars": {
"FORMATTED": {
"format": "$12.",
"label": "FORMATTED",
"length": "12",
"type": "char"
},
"UNFORMATTED": {
"format": "best.",
"label": "UNFORMATTED",
"length": "8",
"type": "num"
}
}
},
"meta": [
{
"COLUMN": "SOME_BESTNUM",
"SASFORMAT": "BEST."
}
],
"_DEBUG": "",
"_METAUSER": "sasdemo@SAS",
"_METAPERSON": "sasdemo",
"_PROGRAM": "/Projects/app/dc/services/public/getcolvals",
"AUTOEXEC": "D%3A%5Copt%5Csasinside%5CConfig%5CLev1%5CSASApp%5CStoredProcessServer%5Cautoexec.sas",
"MF_GETUSER": "sasdemo",
"SYSCC": "0",
"SYSENCODING": "wlatin1",
"SYSERRORTEXT": "",
"SYSHOSTNAME": "SAS",
"SYSPROCESSID": "41DD8057C8923D7140BEF70000000000",
"SYSPROCESSMODE": "SAS Stored Process Server",
"SYSPROCESSNAME": "",
"SYSJOBID": "27448",
"SYSSCPL": "Linunx",
"SYSSITE": "123",
"SYSUSERID": "sassrv",
"SYSVLONG": "9.04.01M7P080520",
"SYSWARNINGTEXT": "ENCODING option ignored for files opened with RECFM=N.",
"END_DTTM": "2022-09-26T08:49:39.137000",
"MEMSIZE": "46GB"
}`
}
_webout = JSON.stringify({
SYSDATE: '26SEP22', SYSTIME: '08:43', sasdata,
_DEBUG: '', _METAUSER: 'sasdemo@SAS', _METAPERSON: 'sasdemo',
_PROGRAM: _program, AUTOEXEC: '', MF_GETUSER: 'sasdemo',
SYSCC: '0', SYSENCODING: 'utf-8', SYSERRORTEXT: '',
SYSHOSTNAME: 'sasjs-server', SYSPROCESSID: '0',
SYSPROCESSMODE: 'Stored Program', SYSPROCESSNAME: '',
SYSJOBID: '0', SYSSCPL: 'LINUX', SYSSITE: '123',
SYSUSERID: 'sasdemo', SYSVLONG: '9.04.01M7P080520',
SYSWARNINGTEXT: '', END_DTTM: new Date().toISOString(), MEMSIZE: '0KB'
})
+72 -29
View File
@@ -1,30 +1,73 @@
_webout = `{"SYSDATE" : "06OCT22"
,"SYSTIME" : "14:43"
, "groups":
[
{"GROUPURI":"1" ,"GROUPNAME":"AllUsers" ,"GROUPDESC":"Group contains all users" }
,{"GROUPURI":"2" ,"GROUPNAME":"Public" ,"GROUPDESC":"A special group that can be used to bypass authentication for pa" }
]
,"_DEBUG" : ""
,"_PROGRAM" : "/30.SASApps/app/mihajlo/services/public/getgroups"
,"AUTOEXEC" : "%2Fhome%2Fmihajlo%2Fsasjs_root%2Fsessions%2F20221006144330-61991-1665067410430%2Fautoexec.sas"
,"MF_GETUSER" : "mihajlo"
,"SYSCC" : "0"
,"SYSENCODING" : "utf-8"
,"SYSERRORTEXT" : ""
,"SYSHOSTINFOLONG" : ""
,"SYSHOSTNAME" : "sas.4gl.io"
,"SYSPROCESSID" : "41DD83B844F8941D0000000000000000"
,"SYSPROCESSMODE" : "Stored Program"
,"SYSPROCESSNAME" : ""
,"SYSJOBID" : "717841"
,"SYSSCPL" : "LINUX"
,"syssite" : "123"
,"SYSTCPIPHOSTNAME" : "https://sas.4gl.io:5002"
,"SYSUSERID" : "mihajlo"
,"SYSVLONG" : "05.00.00.02.001146"
,"SYSWARNINGTEXT" : ""
,"END_DTTM" : "2022-10-06T14:46:29.671882"
,"MEMSIZE" : "0KB"
const nodePath = require('path')
let appLoc = nodePath.join(..._program.split('services')[0].split('/'))
const sasjsRoot = nodePath.resolve(weboutPath, '..', '..', '..')
const driveRoot = nodePath.resolve(sasjsRoot, 'drive')
const dcLibref = 'DC_JSLIB'
const dataDir = nodePath.resolve(driveRoot, 'files', appLoc, 'data', dcLibref)
// Helper: load a table JSON file
function loadTableData(tableName) {
try {
const file = nodePath.resolve(dataDir, tableName.toLowerCase() + '.json')
return JSON.parse(fs.readFileSync(file, {encoding:'utf8'}).toString())
} catch(err) { return null }
}
`
// Build groups list from MPE_GROUPS data (one row per group_name + user_name)
// The real Viya service queries the identity provider for custom groups;
// the mock derives them from the MPE_GROUPS table instead.
let groups = []
const groupsData = loadTableData('MPE_GROUPS')
if (groupsData && groupsData.rows) {
const seen = new Set()
for (const r of groupsData.rows) {
const groupName = r.GROUP_NAME || r.group_name
const groupDesc = r.GROUP_DESC || r.group_desc
if (groupName && !seen.has(groupName)) {
seen.add(groupName)
groups.push({
GROUPDESC: groupDesc || ' ',
GROUPURI: groupName,
GROUPNAME: groupName
})
}
}
groups.sort((a, b) => a.GROUPNAME.localeCompare(b.GROUPNAME))
}
// Always include the AllUsers group so the frontend can reference it
if (!groups.find(g => g.GROUPNAME === 'AllUsers')) {
groups.unshift({
GROUPDESC: 'Group contains all users',
GROUPURI: 'AllUsers',
GROUPNAME: 'AllUsers'
})
}
_webout = JSON.stringify({
SYSDATE: '26SEP22',
SYSTIME: '08:48',
groups: groups,
_DEBUG: '',
_METAUSER: 'sasdemo@SAS',
_METAPERSON: 'sasdemo',
_PROGRAM: _program,
AUTOEXEC: '',
MF_GETUSER: 'sasdemo',
SYSCC: '0',
SYSENCODING: 'utf-8',
SYSERRORTEXT: '',
SYSHOSTNAME: 'sasjs-server',
SYSPROCESSID: '0',
SYSPROCESSMODE: 'Stored Program',
SYSPROCESSNAME: '',
SYSJOBID: '0',
SYSSCPL: 'LINUX',
SYSSITE: '123',
SYSUSERID: 'sasdemo',
SYSVLONG: '9.04.01M7P080520',
SYSWARNINGTEXT: '',
END_DTTM: new Date().toISOString(),
MEMSIZE: '0KB'
})
+104 -512
View File
@@ -1,530 +1,122 @@
let mimeType = `application/octet-stream`
let filename = `dc-download`
const nodePath = require('path')
if (table) filename = `${table}`
let appLoc = nodePath.join(..._program.split('services')[0].split('/'))
const sasjsRoot = nodePath.resolve(weboutPath, '..', '..', '..')
const driveRoot = nodePath.resolve(sasjsRoot, 'drive')
const dcLibref = 'DC_JSLIB'
const dataDir = nodePath.resolve(driveRoot, 'files', appLoc, 'data', dcLibref)
switch(type) {
case 'CSV': {
// Helper: load a table JSON file
function loadTableData(tableName) {
try {
const file = nodePath.resolve(dataDir, tableName.toLowerCase() + '.json')
return JSON.parse(fs.readFileSync(file, {encoding:'utf8'}).toString())
} catch(err) { return null }
}
// SAS epoch for date/datetime/time formatting
const SAS_EPOCH_MS = Date.UTC(1960, 0, 1)
const MONTHS = ['JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC']
function formatSasValue(value, ddtype) {
if (value === null || value === undefined || value === '') return ''
if (typeof value !== 'number') return String(value)
if (ddtype === 'DATE') {
const d = new Date(SAS_EPOCH_MS + value * 86400000)
return `${d.getUTCDate()}${MONTHS[d.getUTCMonth()]}${d.getUTCFullYear()}`
}
if (ddtype === 'DATETIME') {
const d = new Date(SAS_EPOCH_MS + value * 1000)
return `${d.getUTCDate()}${MONTHS[d.getUTCMonth()]}${d.getUTCFullYear()}:${String(d.getUTCHours()).padStart(2,'0')}:${String(d.getUTCMinutes()).padStart(2,'0')}:${String(d.getUTCSeconds()).padStart(2,'0')}`
}
if (ddtype === 'TIME') {
const h = Math.floor(value / 3600)
const m = Math.floor((value % 3600) / 60)
const s = value % 60
return `${h}:${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')}`
}
return String(value)
}
// Determine mime type and filename from request params
let mimeType = 'application/octet-stream'
let filename = table || 'dc-download'
switch((type || '').toUpperCase()) {
case 'CSV':
mimeType = 'text/csv'
filename += '.csv'
break
}
case 'EXCEL': {
case 'EXCEL':
mimeType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
filename += '.xlsx'
break
}
case 'MARKDOWN': {
case 'MARKDOWN':
mimeType = 'application/octet-stream'
filename += '.md'
break
}
default:
mimeType = 'application/octet-stream'
filename += '.sas'
break
}
fs.writeFile(_SASJS_WEBOUT_HEADERS, `Content-type: ${mimeType} \n Content-Disposition: attachment;filename=\"${filename}\"`, function (err) {
if (err) throw err;
})
// Write headers
fs.writeFile(_SASJS_WEBOUT_HEADERS,
`Content-type: ${mimeType} \n Content-Disposition: attachment;filename="${filename}"`,
function (err) { if (err) throw err }
)
_webout=`
2,even more dummy data,Option/* */ 3,42,42,42,142,3,44
3,"It was a dark and stormy night. The wind was blowing a gale! The captain said to his mate - mate, tell us a tale. And this, is the tale he told: It was a dark and stormy night. The wind was blowing a gale! The captain said to his mate - mate, tell us a tale. And this, is the tale he told: It was a dark and stormy night. The wind was blowing a gale! The captain said to his mate - mate, tell us a tale. And this, is the tale he told: It was a dark and stormy night. The wind was blowing a gale! The captain said to his mate - mate, tell us a tale. And this, is the tale he told:",Option 2,1613.001,423,423,44,3,44
4,if you can fill the unforgiving minute,Option 1,1613.001123456,4231,423123123,412,3,44
1010,10 bottles of beer on the wall,Option 1,0.36778671125312,429,29804,35,1,72
1011,11 bottles of beer on the wall,Option 1,0.86933304968724,385,5119,1,6,54
1012,12 bottles of beer on the wall,Option 1,0.54327790650691,644,10655,35,54,62
1013,13 bottles of beer on the wall,Option 1,0.50519398669954,781,24475,41,38,4
1014,14 bottles of beer on the wall,Option 1,0.0130502507151339,12,13693,14,92,57
1015,15 bottles of beer on the wall,Option 1,0.58227080087283,923,43518,54,92,80
1016,16 bottles of beer on the wall,Option 1,0.13827249786736,241,10081,1,28,91
1017,17 bottles of beer on the wall,Option 1,0.89270132402549,622,25438,97,91,72
1018,18 bottles of beer on the wall,Option 1,0.18527885674744,432,1368,32,93,79
1019,19 bottles of beer on the wall,Option 1,0.07375510180078,389,11673,21,22,90
1020,20 bottles of beer on the wall,Option 1,0.71285699387679,404,6623,100,65,34
1021,21 bottles of beer on the wall,Option 1,0.67061384425992,433,17575,13,44,97
1022,22 bottles of beer on the wall,Option 1,0.14232157922457,933,26701,70,66,98
1023,23 bottles of beer on the wall,Option 1,0.12598480662609,974,34354,76,44,98
1024,24 bottles of beer on the wall,Option 1,0.38994686370247,705,24831,33,30,90
1025,25 bottles of beer on the wall,Option 1,0.0310356193366626,60,10687,27,73,59
1026,26 bottles of beer on the wall,Option 1,0.90578842391529,277,40648,41,82,46
1027,27 bottles of beer on the wall,Option 1,0.59206758560243,926,12941,22,46,73
1028,28 bottles of beer on the wall,Option 1,0.65800300457421,281,47610,40,35,40
1029,29 bottles of beer on the wall,Option 1,0.80704259397789,360,43034,19,80,12
1030,30 bottles of beer on the wall,Option 1,0.88014504075057,500,36665,25,70,19
1031,31 bottles of beer on the wall,Option 1,0.41501947046025,757,41229,64,94,48
1032,32 bottles of beer on the wall,Option 1,0.9743401203185,739,27875,67,43,3
1033,33 bottles of beer on the wall,Option 1,0.20355956917794,250,42739,42,29,56
1034,34 bottles of beer on the wall,Option 1,0.67924355560878,111,26224,74,68,9
1035,35 bottles of beer on the wall,Option 1,0.9494116971965,18,36938,76,91,10
1036,36 bottles of beer on the wall,Option 1,0.54461349106608,299,14127,84,72,36
1037,37 bottles of beer on the wall,Option 1,0.45877589399869,325,48877,95,97,32
1038,38 bottles of beer on the wall,Option 1,0.15371942387601,491,22453,29,60,98
1039,39 bottles of beer on the wall,Option 1,0.4935002562094,156,25182,45,95,55
1040,40 bottles of beer on the wall,Option 1,0.12472885899465,433,10986,83,35,79
1041,41 bottles of beer on the wall,Option 1,0.27944220010165,917,19766,51,86,66
1042,42 bottles of beer on the wall,Option 1,0.70307754990788,223,43884,38,86,97
1043,43 bottles of beer on the wall,Option 1,0.0701107536769,394,13449,3,25,8
1044,44 bottles of beer on the wall,Option 1,0.64232929267097,745,3427,9,97,37
1045,45 bottles of beer on the wall,Option 1,0.72064477425098,652,44732,7,58,58
1046,46 bottles of beer on the wall,Option 1,0.0431997366450726,255,18777,95,17,8
1047,47 bottles of beer on the wall,Option 1,0.3704071367953,182,9877,6,45,26
1048,48 bottles of beer on the wall,Option 1,0.65441703500897,489,4987,98,41,13
1049,49 bottles of beer on the wall,Option 1,0.13002125645523,371,19649,81,37,66
1050,50 bottles of beer on the wall,Option 1,0.0058409725343068,204,264,40,15,32
1051,51 bottles of beer on the wall,Option 1,0.7239382587019,160,11709,4,42,82
1052,52 bottles of beer on the wall,Option 1,0.83190037116031,225,27515,36,69,81
1053,53 bottles of beer on the wall,Option 1,0.50308288750382,538,41129,53,39,75
1054,54 bottles of beer on the wall,Option 1,0.71480455143135,238,36609,39,6,4
1055,55 bottles of beer on the wall,Option 1,0.85579457872351,292,8252,8,93,36
1056,56 bottles of beer on the wall,Option 1,0.97004633069506,922,40721,51,25,35
1057,57 bottles of beer on the wall,Option 1,0.93803994261568,542,47713,52,57,66
1058,58 bottles of beer on the wall,Option 1,0.84844994863888,153,4491,0,80,58
1059,59 bottles of beer on the wall,Option 1,0.14157076279705,574,23596,58,11,32
1060,60 bottles of beer on the wall,Option 1,0.28267451295753,816,1537,56,79,58
1061,61 bottles of beer on the wall,Option 1,0.37272800801914,734,18463,60,86,92
1062,62 bottles of beer on the wall,Option 1,0.95173373164224,606,9605,5,30,93
1063,63 bottles of beer on the wall,Option 1,0.09674986828898,778,27041,29,90,82
1064,64 bottles of beer on the wall,Option 1,0.054067135348016,511,47623,8,88,45
1065,65 bottles of beer on the wall,Option 1,0.64616364643264,757,10601,19,41,38
1066,66 bottles of beer on the wall,Option 1,0.9053011983192,275,12949,64,68,39
1067,67 bottles of beer on the wall,Option 1,0.97752588101547,930,21200,28,28,34
1068,68 bottles of beer on the wall,Option 1,0.21655531610201,133,6242,72,63,23
1069,69 bottles of beer on the wall,Option 1,0.22483527950236,494,273,9,26,93
1070,70 bottles of beer on the wall,Option 1,0.13862833666551,868,12720,96,83,89
1071,71 bottles of beer on the wall,Option 1,0.93373314148454,501,49614,47,27,56
1072,72 bottles of beer on the wall,Option 1,0.035223550645273,522,32960,76,7,27
1073,73 bottles of beer on the wall,Option 1,0.32066626954854,72,38291,68,3,50
1074,74 bottles of beer on the wall,Option 1,0.46108617049692,608,34541,68,54,68
1075,75 bottles of beer on the wall,Option 1,0.45277456215246,746,24567,45,96,63
1076,76 bottles of beer on the wall,Option 1,0.35812440577807,136,3400,73,72,24
1077,77 bottles of beer on the wall,Option 1,0.89399213338922,386,33391,75,88,69
1078,78 bottles of beer on the wall,Option 1,0.24457270663444,356,11474,97,88,32
1079,79 bottles of beer on the wall,Option 1,0.96830294652297,591,17143,69,51,60
1080,80 bottles of beer on the wall,Option 1,0.13035413675492,789,8090,21,79,87
1081,81 bottles of beer on the wall,Option 1,0.76569796528932,580,24590,91,58,30
1082,82 bottles of beer on the wall,Option 1,0.18556296740917,350,23241,33,1,72
1083,83 bottles of beer on the wall,Option 1,0.47821786416611,471,29123,70,0,1
1084,84 bottles of beer on the wall,Option 1,0.16702721322282,902,49400,27,53,6
1085,85 bottles of beer on the wall,Option 1,0.60682491893266,141,39911,8,17,68
1086,86 bottles of beer on the wall,Option 1,0.09360499172173,931,26169,46,73,37
1087,87 bottles of beer on the wall,Option 1,0.65382491781088,114,7614,59,95,32
1088,88 bottles of beer on the wall,Option 1,0.88461585616907,688,20127,61,87,30
1089,89 bottles of beer on the wall,Option 1,0.15782083159211,427,32522,23,60,53
1090,90 bottles of beer on the wall,Option 1,0.42257537526198,78,44044,60,57,64
1091,91 bottles of beer on the wall,Option 1,0.65989433539095,625,10993,60,41,28
1092,92 bottles of beer on the wall,Option 1,0.62935016892354,656,1273,71,64,7
1093,93 bottles of beer on the wall,Option 1,0.43788449859148,540,37239,27,30,78
1094,94 bottles of beer on the wall,Option 1,0.9838584968745,875,10746,59,48,98
1095,95 bottles of beer on the wall,Option 1,0.08925237697048,532,17660,10,75,33
1096,96 bottles of beer on the wall,Option 1,0.45782051536153,19,38160,41,14,17
1097,97 bottles of beer on the wall,Option 1,0.58632715865332,840,40451,88,66,84
1098,98 bottles of beer on the wall,Option 1,0.29942320580567,185,29741,88,99,85
1099,99 bottles of beer on the wall,Option 1,0.09813780528406,35,40211,43,23,65
10100,100 bottles of beer on the wall,Option 1,0.98297226521324,31,20706,76,28,44
10101,101 bottles of beer on the wall,Option 1,0.45407949129775,945,34023,70,42,44
10102,102 bottles of beer on the wall,Option 1,0.84521743694563,275,11327,23,10,14
10103,103 bottles of beer on the wall,Option 1,0.59049196056578,211,47398,10,68,53
10104,104 bottles of beer on the wall,Option 1,0.70833886773713,205,20990,89,84,33
10105,105 bottles of beer on the wall,Option 1,0.31835502587182,622,8914,51,69,97
10106,106 bottles of beer on the wall,Option 1,0.97297559723862,585,16241,10,91,29
10107,107 bottles of beer on the wall,Option 1,0.5090773215094,266,19231,43,92,73
10108,108 bottles of beer on the wall,Option 1,0.60501769259805,442,8188,35,88,21
10109,109 bottles of beer on the wall,Option 1,0.36126818152203,732,39786,39,67,1
10110,110 bottles of beer on the wall,Option 1,0.92257953710974,181,27439,53,45,96
10111,111 bottles of beer on the wall,Option 1,0.57620774422595,1,10732,13,85,94
10112,112 bottles of beer on the wall,Option 1,0.72213579794491,368,24381,11,81,4
10113,113 bottles of beer on the wall,Option 1,0.68396092331221,876,7786,88,88,35
10114,114 bottles of beer on the wall,Option 1,0.06275422035844,242,39301,65,37,30
10115,115 bottles of beer on the wall,Option 1,0.14623936319082,763,31112,32,26,92
10116,116 bottles of beer on the wall,Option 1,0.88700955448998,461,29947,67,93,100
10117,117 bottles of beer on the wall,Option 1,0.58625199812755,772,33489,84,17,65
10118,118 bottles of beer on the wall,Option 1,0.11950912844366,88,18030,83,74,91
10119,119 bottles of beer on the wall,Option 1,0.25274958287028,73,40520,3,35,48
10120,120 bottles of beer on the wall,Option 1,0.20096259713217,322,37079,25,72,46
10121,121 bottles of beer on the wall,Option 1,0.51715718140693,696,35623,70,2,29
10122,122 bottles of beer on the wall,Option 1,0.62535265396598,349,18863,77,55,42
10123,123 bottles of beer on the wall,Option 1,0.0397578571176892,616,2222,57,21,21
10124,124 bottles of beer on the wall,Option 1,0.15299692198308,781,31566,49,77,36
10125,125 bottles of beer on the wall,Option 1,0.55944163518,848,18125,98,89,81
10126,126 bottles of beer on the wall,Option 1,0.0545679247260876,102,12528,93,78,97
10127,127 bottles of beer on the wall,Option 1,0.37134892836741,650,8167,52,54,88
10128,128 bottles of beer on the wall,Option 1,0.64729823528197,93,1934,51,6,19
10129,129 bottles of beer on the wall,Option 1,0.83002288491931,4,49511,33,81,10
10130,130 bottles of beer on the wall,Option 1,0.26566079038458,556,19220,44,64,96
10131,131 bottles of beer on the wall,Option 1,0.3515388878768,465,9268,65,33,47
10132,132 bottles of beer on the wall,Option 1,0.58481269170754,369,3487,9,27,23
10133,133 bottles of beer on the wall,Option 1,0.35976610256348,821,16327,12,6,79
10134,134 bottles of beer on the wall,Option 1,0.66825788732071,692,43769,43,39,24
10135,135 bottles of beer on the wall,Option 1,0.6738104655751,506,29856,85,25,81
10136,136 bottles of beer on the wall,Option 1,0.61094559291887,719,22506,35,54,62
10137,137 bottles of beer on the wall,Option 1,0.90374875157314,72,5697,78,47,95
10138,138 bottles of beer on the wall,Option 1,0.80794565184411,642,42356,27,12,85
10139,139 bottles of beer on the wall,Option 1,0.38307386654572,96,27737,91,35,33
10140,140 bottles of beer on the wall,Option 1,0.56504530905049,50,436,92,79,7
10141,141 bottles of beer on the wall,Option 1,0.88745929388676,790,2062,19,22,14
10142,142 bottles of beer on the wall,Option 1,0.40486131394508,401,39461,31,67,8
10143,143 bottles of beer on the wall,Option 1,0.46010804244322,141,38118,13,5,56
10144,144 bottles of beer on the wall,Option 1,0.80973751089057,391,29194,40,99,51
10145,145 bottles of beer on the wall,Option 1,0.99359150975644,439,46193,72,64,36
10146,146 bottles of beer on the wall,Option 1,0.0452116918960641,118,22701,24,60,96
10147,147 bottles of beer on the wall,Option 1,0.82811712977854,260,12725,17,62,66
10148,148 bottles of beer on the wall,Option 1,0.10816729632586,938,26840,50,84,81
10149,149 bottles of beer on the wall,Option 1,0.38052640686767,683,3221,86,85,46
10150,150 bottles of beer on the wall,Option 1,0.75572601973811,982,19125,32,95,95
10151,151 bottles of beer on the wall,Option 1,0.14433648304284,978,10712,67,60,46
10152,152 bottles of beer on the wall,Option 1,0.0478734295106835,195,20803,16,11,31
10153,153 bottles of beer on the wall,Option 1,0.99183906660966,846,17321,72,56,75
10154,154 bottles of beer on the wall,Option 1,0.9159638098981,247,6539,24,83,15
10155,155 bottles of beer on the wall,Option 1,0.36824048886459,754,32386,14,80,100
10156,156 bottles of beer on the wall,Option 1,0.26111941517382,730,2622,30,83,10
10157,157 bottles of beer on the wall,Option 1,0.88903899951327,332,11975,96,11,35
10158,158 bottles of beer on the wall,Option 1,0.13194132788662,604,26809,16,51,85
10159,159 bottles of beer on the wall,Option 1,0.62617524323341,174,9160,21,48,61
10160,160 bottles of beer on the wall,Option 1,0.57026278207556,696,43887,57,83,1
10161,161 bottles of beer on the wall,Option 1,0.85756031324042,271,49234,27,2,27
10162,162 bottles of beer on the wall,Option 1,0.1826881850989,47,10724,78,2,97
10163,163 bottles of beer on the wall,Option 1,0.23421087266607,482,10522,88,20,48
10164,164 bottles of beer on the wall,Option 1,0.35695342596478,161,38915,54,32,10
10165,165 bottles of beer on the wall,Option 1,0.91366467481184,378,38006,70,63,6
10166,166 bottles of beer on the wall,Option 1,0.99905551783696,818,43080,35,10,36
10167,167 bottles of beer on the wall,Option 1,0.52259193245442,62,47314,77,73,92
10168,168 bottles of beer on the wall,Option 1,0.37612532376131,455,10513,79,37,41
10169,169 bottles of beer on the wall,Option 1,0.32677267646732,900,43022,33,56,4
10170,170 bottles of beer on the wall,Option 1,0.78282068659682,584,35703,11,96,19
10171,171 bottles of beer on the wall,Option 1,0.86384059622131,383,16268,72,97,52
10172,172 bottles of beer on the wall,Option 1,0.78971071298686,274,40013,11,12,77
10173,173 bottles of beer on the wall,Option 1,0.80251133851823,141,24834,3,24,52
10174,174 bottles of beer on the wall,Option 1,0.75300996366562,391,25598,69,10,50
10175,175 bottles of beer on the wall,Option 1,0.71632067054338,957,17312,75,80,50
10176,176 bottles of beer on the wall,Option 1,0.79148860219469,146,43778,51,4,35
10177,177 bottles of beer on the wall,Option 1,0.09253642060446,108,5706,3,54,99
10178,178 bottles of beer on the wall,Option 1,0.11753227706883,629,20998,30,9,4
10179,179 bottles of beer on the wall,Option 1,0.7680506472327,480,16698,64,29,40
10180,180 bottles of beer on the wall,Option 1,0.72647327497902,3,692,98,26,63
10181,181 bottles of beer on the wall,Option 1,0.61187958652706,804,15515,35,74,9
10182,182 bottles of beer on the wall,Option 1,0.37813100422645,947,17165,45,40,70
10183,183 bottles of beer on the wall,Option 1,0.77219476074548,333,18572,47,75,13
10184,184 bottles of beer on the wall,Option 1,0.08129415338919,544,41948,73,69,42
10185,185 bottles of beer on the wall,Option 1,0.31256898320865,788,40399,79,46,81
10186,186 bottles of beer on the wall,Option 1,0.17449143863026,792,48899,82,75,11
10187,187 bottles of beer on the wall,Option 1,0.96775995286542,287,49710,56,53,48
10188,188 bottles of beer on the wall,Option 1,0.89112877840694,64,19729,89,53,7
10189,189 bottles of beer on the wall,Option 1,0.06672863013424,76,28616,10,62,87
10190,190 bottles of beer on the wall,Option 1,0.94082600806878,147,42133,34,45,53
10191,191 bottles of beer on the wall,Option 1,0.31033688146171,836,30910,16,47,17
10192,192 bottles of beer on the wall,Option 1,0.18763532265445,337,40521,3,51,83
10193,193 bottles of beer on the wall,Option 1,0.96240949442722,291,15471,49,39,59
10194,194 bottles of beer on the wall,Option 1,0.8183761731807,419,40108,43,39,67
10195,195 bottles of beer on the wall,Option 1,0.24989856139286,670,15344,92,43,42
10196,196 bottles of beer on the wall,Option 1,0.30300405309675,389,23570,23,54,49
10197,197 bottles of beer on the wall,Option 1,0.72431187039441,253,33148,8,44,61
10198,198 bottles of beer on the wall,Option 1,0.28154017463398,990,5590,35,70,58
10199,199 bottles of beer on the wall,Option 1,0.91922048801519,128,34408,69,54,0
10200,200 bottles of beer on the wall,Option 1,0.50593937258512,107,18850,78,83,97
10201,201 bottles of beer on the wall,Option 1,0.14390773612256,946,17067,64,26,8
10202,202 bottles of beer on the wall,Option 1,0.22146828529493,610,24559,46,49,59
10203,203 bottles of beer on the wall,Option 1,0.25821849576114,663,34629,1,6,71
10204,204 bottles of beer on the wall,Option 1,0.07666777590134,466,27138,26,99,30
10205,205 bottles of beer on the wall,Option 1,0.99336800817091,694,16168,65,11,46
10206,206 bottles of beer on the wall,Option 1,0.87276060547342,576,25229,80,91,90
10207,207 bottles of beer on the wall,Option 1,0.78940974864615,6,47096,26,63,27
10208,208 bottles of beer on the wall,Option 1,0.34292900066027,14,31458,36,22,82
10209,209 bottles of beer on the wall,Option 1,0.85305621747535,993,2251,86,89,14
10210,210 bottles of beer on the wall,Option 1,0.15697739560016,198,45644,46,91,4
10211,211 bottles of beer on the wall,Option 1,0.28367675109006,906,13627,42,90,59
10212,212 bottles of beer on the wall,Option 1,0.31982582077375,378,7369,78,38,8
10213,213 bottles of beer on the wall,Option 1,0.23638620564545,648,44244,93,90,55
10214,214 bottles of beer on the wall,Option 1,0.74210127105102,24,20396,94,44,25
10215,215 bottles of beer on the wall,Option 1,0.86374284972611,74,48658,100,86,85
10216,216 bottles of beer on the wall,Option 1,0.75050161255081,59,46121,89,20,42
10217,217 bottles of beer on the wall,Option 1,0.66522030609902,994,42468,11,56,86
10218,218 bottles of beer on the wall,Option 1,0.31411136375465,655,27263,65,25,96
10219,219 bottles of beer on the wall,Option 1,0.47560207800734,499,48744,43,95,39
10220,220 bottles of beer on the wall,Option 1,0.29217880745054,499,11765,39,38,34
10221,221 bottles of beer on the wall,Option 1,0.34208696444616,782,48914,46,28,67
10222,222 bottles of beer on the wall,Option 1,0.3618709479281,17,35101,36,32,96
10223,223 bottles of beer on the wall,Option 1,0.57169641674109,255,39862,46,25,32
10224,224 bottles of beer on the wall,Option 1,0.81918335930406,52,678,48,93,9
10225,225 bottles of beer on the wall,Option 1,0.0242283884548714,85,42068,83,16,80
10226,226 bottles of beer on the wall,Option 1,0.41845829338694,302,24667,57,21,94
10227,227 bottles of beer on the wall,Option 1,0.85522656275668,25,4962,39,16,92
10228,228 bottles of beer on the wall,Option 1,0.61243204661292,211,29623,51,3,47
10229,229 bottles of beer on the wall,Option 1,0.0565994717444291,895,43578,3,89,43
10230,230 bottles of beer on the wall,Option 1,0.23499503882368,490,4308,62,37,48
10231,231 bottles of beer on the wall,Option 1,0.90549826105381,400,6623,89,33,46
10232,232 bottles of beer on the wall,Option 1,0.48989009600593,744,25625,56,51,95
10233,233 bottles of beer on the wall,Option 1,0.45866525287677,218,44935,69,85,54
10234,234 bottles of beer on the wall,Option 1,0.85541833977001,639,24786,23,38,89
10235,235 bottles of beer on the wall,Option 1,0.85759922622591,668,22410,58,67,99
10236,236 bottles of beer on the wall,Option 1,0.84442021411118,101,1665,82,65,33
10237,237 bottles of beer on the wall,Option 1,0.47433742809777,378,24480,58,22,29
10238,238 bottles of beer on the wall,Option 1,0.32656197777323,516,43954,3,94,67
10239,239 bottles of beer on the wall,Option 1,0.92182368269275,712,4843,71,46,48
10240,240 bottles of beer on the wall,Option 1,0.12125048326386,352,9277,22,2,32
10241,241 bottles of beer on the wall,Option 1,0.94974516935169,523,24517,34,3,67
10242,242 bottles of beer on the wall,Option 1,0.25598201866074,802,27462,64,76,70
10243,243 bottles of beer on the wall,Option 1,0.75983338978133,179,29989,61,29,71
10244,244 bottles of beer on the wall,Option 1,0.70059782718336,205,18615,38,53,10
10245,245 bottles of beer on the wall,Option 1,0.22119579474497,248,32376,67,44,33
10246,246 bottles of beer on the wall,Option 1,0.20074144573916,83,8942,9,37,88
10247,247 bottles of beer on the wall,Option 1,0.28749029351747,570,10557,57,30,33
10248,248 bottles of beer on the wall,Option 1,0.56116712678278,176,7262,96,49,90
10249,249 bottles of beer on the wall,Option 1,0.34936685829859,424,16012,95,81,25
10250,250 bottles of beer on the wall,Option 1,0.2531839875752,400,13060,93,38,32
10251,251 bottles of beer on the wall,Option 1,0.74716722860334,104,36045,95,12,91
10252,252 bottles of beer on the wall,Option 1,0.2776136003796,621,32945,24,43,56
10253,253 bottles of beer on the wall,Option 1,0.10966447093974,824,1582,82,47,71
10254,254 bottles of beer on the wall,Option 1,0.20580046819793,515,48029,52,84,12
10255,255 bottles of beer on the wall,Option 1,0.25379118707673,528,20603,24,50,93
10256,256 bottles of beer on the wall,Option 1,0.91665374763154,340,33728,92,65,18
10257,257 bottles of beer on the wall,Option 1,0.76795360016075,986,2750,46,80,97
10258,258 bottles of beer on the wall,Option 1,0.54184350210327,343,36848,56,32,90
10259,259 bottles of beer on the wall,Option 1,0.32811180051793,455,28710,88,44,88
10260,260 bottles of beer on the wall,Option 1,0.21353805913288,312,29544,13,52,11
10261,261 bottles of beer on the wall,Option 1,0.9443434551099,512,8527,20,62,6
10262,262 bottles of beer on the wall,Option 1,0.85606485691669,897,5860,30,57,8
10263,263 bottles of beer on the wall,Option 1,0.99083470878695,807,13039,86,67,60
10264,264 bottles of beer on the wall,Option 1,0.81836992586886,962,4598,39,30,45
10265,265 bottles of beer on the wall,Option 1,0.42497428805798,61,6536,89,38,44
10266,266 bottles of beer on the wall,Option 1,0.0560880252421312,251,6156,80,39,13
10267,267 bottles of beer on the wall,Option 1,0.62838333175908,976,41904,69,80,5
10268,268 bottles of beer on the wall,Option 1,0.86274688498244,801,38326,57,37,67
10269,269 bottles of beer on the wall,Option 1,0.90785965924517,430,4760,53,46,12
10270,270 bottles of beer on the wall,Option 1,0.96423306221339,881,13359,26,76,85
10271,271 bottles of beer on the wall,Option 1,0.4007478316318,386,9372,92,46,37
10272,272 bottles of beer on the wall,Option 1,0.1693538530587,770,30938,83,37,54
10273,273 bottles of beer on the wall,Option 1,0.31195034380627,685,24382,100,69,19
10274,274 bottles of beer on the wall,Option 1,0.76835356129722,187,47688,55,89,64
10275,275 bottles of beer on the wall,Option 1,0.55031902461793,584,3730,14,0,81
10276,276 bottles of beer on the wall,Option 1,0.95770672334251,363,3953,24,30,88
10277,277 bottles of beer on the wall,Option 1,0.6728389773857,420,8182,39,53,83
10278,278 bottles of beer on the wall,Option 1,0.89363865595946,704,46747,31,74,16
10279,279 bottles of beer on the wall,Option 1,0.40898148175747,924,47734,97,7,24
10280,280 bottles of beer on the wall,Option 1,0.66577262182988,64,20201,32,44,54
10281,281 bottles of beer on the wall,Option 1,0.51660140814101,280,12454,79,10,71
10282,282 bottles of beer on the wall,Option 1,0.53854070070131,104,43120,90,44,24
10283,283 bottles of beer on the wall,Option 1,0.23819732723673,558,15573,20,6,23
10284,284 bottles of beer on the wall,Option 1,0.47946875704427,243,36842,53,32,21
10285,285 bottles of beer on the wall,Option 1,0.77190031845676,651,28782,56,39,60
10286,286 bottles of beer on the wall,Option 1,0.32027244256822,383,42285,47,100,10
10287,287 bottles of beer on the wall,Option 1,0.74313893157203,31,16412,3,74,65
10288,288 bottles of beer on the wall,Option 1,0.76955895022002,602,446,96,3,76
10289,289 bottles of beer on the wall,Option 1,0.34185171050105,952,13939,62,5,36
10290,290 bottles of beer on the wall,Option 1,0.56766681958346,767,45844,22,63,94
10291,291 bottles of beer on the wall,Option 1,0.08876820145583,35,44015,18,67,75
10292,292 bottles of beer on the wall,Option 1,0.60991968662008,537,25458,62,97,31
10293,293 bottles of beer on the wall,Option 1,0.49679509200937,425,2032,71,57,28
10294,294 bottles of beer on the wall,Option 1,0.75629847392267,128,18192,74,4,18
10295,295 bottles of beer on the wall,Option 1,0.68437125379423,823,49500,26,26,27
10296,296 bottles of beer on the wall,Option 1,0.93925402124377,544,41748,5,35,80
10297,297 bottles of beer on the wall,Option 1,0.32460635729348,55,9662,69,4,43
10298,298 bottles of beer on the wall,Option 1,0.69933199170014,168,2056,58,37,59
10299,299 bottles of beer on the wall,Option 1,0.47544649638023,840,30210,53,53,68
10300,300 bottles of beer on the wall,Option 1,0.0061305039590832,271,12274,76,89,63
10301,301 bottles of beer on the wall,Option 1,0.48602948453558,62,326,17,10,61
10302,302 bottles of beer on the wall,Option 1,0.66281101091895,85,25075,34,20,0
10303,303 bottles of beer on the wall,Option 1,0.91012760247575,766,2167,24,10,59
10304,304 bottles of beer on the wall,Option 1,0.25942224276225,900,10747,64,56,26
10305,305 bottles of beer on the wall,Option 1,0.1962652361003,289,96,17,33,93
10306,306 bottles of beer on the wall,Option 1,0.43586940478341,29,13418,16,53,29
10307,307 bottles of beer on the wall,Option 1,0.59681117515862,118,27786,86,65,36
10308,308 bottles of beer on the wall,Option 1,0.74818741471887,206,4604,24,24,25
10309,309 bottles of beer on the wall,Option 1,0.08160290591493,312,21554,64,63,72
10310,310 bottles of beer on the wall,Option 1,0.93582592389351,242,10979,27,81,61
10311,311 bottles of beer on the wall,Option 1,0.80891675353465,209,5348,87,54,90
10312,312 bottles of beer on the wall,Option 1,0.60018050931402,439,38290,61,90,76
10313,313 bottles of beer on the wall,Option 1,0.24727975961159,881,20239,40,51,51
10314,314 bottles of beer on the wall,Option 1,0.38803865312972,653,24155,89,31,85
10315,315 bottles of beer on the wall,Option 1,0.87407688278429,313,37785,77,92,16
10316,316 bottles of beer on the wall,Option 1,0.56551623696718,547,21387,24,23,97
10317,317 bottles of beer on the wall,Option 1,0.76403702691385,58,9872,38,64,21
10318,318 bottles of beer on the wall,Option 1,0.90192810953684,602,11179,10,90,11
10319,319 bottles of beer on the wall,Option 1,0.19516248544452,214,4047,63,28,92
10320,320 bottles of beer on the wall,Option 1,0.94210496449009,873,18179,99,68,3
10321,321 bottles of beer on the wall,Option 1,0.38397014298661,768,6961,34,4,75
10322,322 bottles of beer on the wall,Option 1,0.48192969592378,241,40181,42,3,47
10323,323 bottles of beer on the wall,Option 1,0.9110809797007,103,40820,33,3,68
10324,324 bottles of beer on the wall,Option 1,0.87276527372783,826,32198,4,39,97
10325,325 bottles of beer on the wall,Option 1,0.79484101282192,372,7572,44,96,94
10326,326 bottles of beer on the wall,Option 1,0.14490672719893,292,7727,52,59,76
10327,327 bottles of beer on the wall,Option 1,0.39760627709217,61,39145,43,84,64
10328,328 bottles of beer on the wall,Option 1,0.59372476655697,986,45366,56,32,42
10329,329 bottles of beer on the wall,Option 1,0.84270271325609,730,48646,83,33,93
10330,330 bottles of beer on the wall,Option 1,0.97886023948847,579,12493,3,47,51
10331,331 bottles of beer on the wall,Option 1,0.06287532628647,13,33428,15,95,25
10332,332 bottles of beer on the wall,Option 1,0.0144214248351853,986,14183,40,42,55
10333,333 bottles of beer on the wall,Option 1,0.46513955689274,279,24669,74,6,96
10334,334 bottles of beer on the wall,Option 1,0.65515650233959,940,7983,58,90,50
10335,335 bottles of beer on the wall,Option 1,0.74576339346625,40,32933,42,66,64
10336,336 bottles of beer on the wall,Option 1,0.25071058620266,249,35506,55,38,21
10337,337 bottles of beer on the wall,Option 1,0.83827515358025,901,40729,55,96,40
10338,338 bottles of beer on the wall,Option 1,0.37835469487046,787,39991,85,24,78
10339,339 bottles of beer on the wall,Option 1,0.47124984649533,325,9386,13,46,83
10340,340 bottles of beer on the wall,Option 1,0.81143325092803,276,21424,20,35,49
10341,341 bottles of beer on the wall,Option 1,0.18923743590211,278,33884,35,66,56
10342,342 bottles of beer on the wall,Option 1,0.31555957641245,652,3104,43,41,96
10343,343 bottles of beer on the wall,Option 1,0.63393646135643,787,7242,50,79,80
10344,344 bottles of beer on the wall,Option 1,0.42426411873859,900,7126,3,47,55
10345,345 bottles of beer on the wall,Option 1,0.46336023717343,202,15278,8,27,22
10346,346 bottles of beer on the wall,Option 1,0.74511298199422,941,9263,62,12,8
10347,347 bottles of beer on the wall,Option 1,0.0509991273521442,175,17983,84,69,63
10348,348 bottles of beer on the wall,Option 1,0.73515439673101,104,44565,39,89,43
10349,349 bottles of beer on the wall,Option 1,0.54621437869324,419,43815,82,14,44
10350,350 bottles of beer on the wall,Option 1,0.67394142862127,565,15879,83,78,24
10351,351 bottles of beer on the wall,Option 1,0.14206720569267,724,48097,47,78,59
10352,352 bottles of beer on the wall,Option 1,0.77307720937443,542,8575,12,59,56
10353,353 bottles of beer on the wall,Option 1,0.30727765350941,969,2407,60,24,16
10354,354 bottles of beer on the wall,Option 1,0.0010556476195602,556,26857,10,10,14
10355,355 bottles of beer on the wall,Option 1,0.18200497244578,184,34597,36,44,73
10356,356 bottles of beer on the wall,Option 1,0.13798288029524,955,24751,69,56,11
10357,357 bottles of beer on the wall,Option 1,0.81430039406488,268,18672,62,91,35
10358,358 bottles of beer on the wall,Option 1,0.43832174522724,693,32350,29,44,16
10359,359 bottles of beer on the wall,Option 1,0.029728665030435,459,5440,18,15,73
10360,360 bottles of beer on the wall,Option 1,0.0315013211367192,722,16356,36,94,34
10361,361 bottles of beer on the wall,Option 1,0.5826698898257,689,39648,77,16,31
10362,362 bottles of beer on the wall,Option 1,0.6902719348158,482,34034,34,28,24
10363,363 bottles of beer on the wall,Option 1,0.31280953544788,122,8845,82,13,11
10364,364 bottles of beer on the wall,Option 1,0.40638104565738,59,17576,51,83,33
10365,365 bottles of beer on the wall,Option 1,0.0494814422211989,427,16863,86,58,83
10366,366 bottles of beer on the wall,Option 1,0.11973315715777,211,5076,50,91,7
10367,367 bottles of beer on the wall,Option 1,0.64716058859935,267,31744,84,38,0
10368,368 bottles of beer on the wall,Option 1,0.26110028115152,618,5356,52,14,45
10369,369 bottles of beer on the wall,Option 1,0.28273768829309,318,1330,93,89,55
10370,370 bottles of beer on the wall,Option 1,0.2922141674404,632,46096,5,81,23
10371,371 bottles of beer on the wall,Option 1,0.41764038541244,906,49463,57,1,62
10372,372 bottles of beer on the wall,Option 1,0.46991869503162,514,18143,97,74,74
10373,373 bottles of beer on the wall,Option 1,0.37822098302572,895,32283,70,48,12
10374,374 bottles of beer on the wall,Option 1,0.29593264744427,113,4983,7,27,41
10375,375 bottles of beer on the wall,Option 1,0.53441656172946,220,39018,54,89,65
10376,376 bottles of beer on the wall,Option 1,0.0352940624744138,109,20139,36,100,10
10377,377 bottles of beer on the wall,Option 1,0.20479777232035,608,6078,64,74,17
10378,378 bottles of beer on the wall,Option 1,0.50705856806927,135,49049,10,54,37
10379,379 bottles of beer on the wall,Option 1,0.66727866961959,412,46966,29,91,57
10380,380 bottles of beer on the wall,Option 1,0.92177499454551,580,26551,28,51,48
10381,381 bottles of beer on the wall,Option 1,0.38939245948074,78,4703,90,2,83
10382,382 bottles of beer on the wall,Option 1,0.61963193706219,174,43627,79,32,20
10383,383 bottles of beer on the wall,Option 1,0.28356101283969,199,30131,69,41,95
10384,384 bottles of beer on the wall,Option 1,0.31165435086547,77,14822,68,53,73
10385,385 bottles of beer on the wall,Option 1,0.31375717619143,905,21353,48,53,98
10386,386 bottles of beer on the wall,Option 1,0.49205248127321,25,43511,50,63,86
10387,387 bottles of beer on the wall,Option 1,0.0871032425608,546,41998,56,8,54
10388,388 bottles of beer on the wall,Option 1,0.58564706965612,707,32080,48,13,71
10389,389 bottles of beer on the wall,Option 1,0.11565735010227,962,23374,70,87,46
10390,390 bottles of beer on the wall,Option 1,0.67894278731147,712,3675,22,39,59
10391,391 bottles of beer on the wall,Option 1,0.55559360494631,485,35672,4,91,33
10392,392 bottles of beer on the wall,Option 1,0.19414928331698,181,5016,91,63,77
10393,393 bottles of beer on the wall,Option 1,0.35980724001294,784,45193,40,85,1
10394,394 bottles of beer on the wall,Option 1,0.56788968181604,558,29278,34,1,48
10395,395 bottles of beer on the wall,Option 1,0.443418078331,67,40850,25,96,88
10396,396 bottles of beer on the wall,Option 1,0.37440109084099,80,28866,54,92,41
10397,397 bottles of beer on the wall,Option 1,0.98865012265213,251,47673,91,46,37
10398,398 bottles of beer on the wall,Option 1,0.92300515804579,559,10806,54,44,62
10399,399 bottles of beer on the wall,Option 1,0.64376400301408,567,44649,57,61,58
10400,400 bottles of beer on the wall,Option 1,0.71294574752121,715,6570,31,26,3
10401,401 bottles of beer on the wall,Option 1,0.0256445333481042,635,9939,72,83,63
10402,402 bottles of beer on the wall,Option 1,0.29210200267476,328,35640,57,94,97
10403,403 bottles of beer on the wall,Option 1,0.6438509126398,426,17030,58,99,72
10404,404 bottles of beer on the wall,Option 1,0.72967141854095,719,23973,72,4,19
10405,405 bottles of beer on the wall,Option 1,0.64815993963189,589,16332,78,22,8
10406,406 bottles of beer on the wall,Option 1,0.68862963127374,792,19827,98,95,84
10407,407 bottles of beer on the wall,Option 1,0.57015705461155,315,8751,26,88,99
10408,408 bottles of beer on the wall,Option 1,0.37385381263394,936,22120,63,22,62
10409,409 bottles of beer on the wall,Option 1,0.42852969580727,575,4535,43,73,1
10410,410 bottles of beer on the wall,Option 1,0.09136778679274,974,6568,15,99,89
10411,411 bottles of beer on the wall,Option 1,0.35649286925629,150,8757,11,21,13
10412,412 bottles of beer on the wall,Option 1,0.78222061916357,343,22099,52,78,86
10413,413 bottles of beer on the wall,Option 1,0.14624287939921,416,38106,39,98,94
10414,414 bottles of beer on the wall,Option 1,0.90027753212502,496,20157,67,58,67
10415,415 bottles of beer on the wall,Option 1,0.33255961040619,752,49026,33,28,14
10416,416 bottles of beer on the wall,Option 1,0.77815227060492,640,35944,70,52,55
10417,417 bottles of beer on the wall,Option 1,0.0933360564957,758,15354,32,19,55
10418,418 bottles of beer on the wall,Option 1,0.0289132245950928,180,5242,85,50,98
10419,419 bottles of beer on the wall,Option 1,0.84686978945828,458,1258,80,25,73
10420,420 bottles of beer on the wall,Option 1,0.338352090371,509,42861,22,43,54
10421,421 bottles of beer on the wall,Option 1,0.86671940137945,577,8605,34,90,100
10422,422 bottles of beer on the wall,Option 1,0.62074221233871,60,22854,9,99,38
10423,423 bottles of beer on the wall,Option 1,0.33002009630669,355,5698,48,91,58
10424,424 bottles of beer on the wall,Option 1,0.74825180030812,425,17426,75,51,47
10425,425 bottles of beer on the wall,Option 1,0.15292107088161,413,42526,51,59,44
10426,426 bottles of beer on the wall,Option 1,0.94121787554641,513,31473,8,93,82
10427,427 bottles of beer on the wall,Option 1,0.30919636381286,556,31101,27,16,50
10428,428 bottles of beer on the wall,Option 1,0.4236965931131,398,29008,36,85,56
10429,429 bottles of beer on the wall,Option 1,0.75479524198677,249,47750,51,15,7
10430,430 bottles of beer on the wall,Option 1,0.49933161796039,918,42396,88,38,92
10431,431 bottles of beer on the wall,Option 1,0.93344558539495,45,43421,17,90,69
10432,432 bottles of beer on the wall,Option 1,0.9476499729546,937,16157,85,76,3
10433,433 bottles of beer on the wall,Option 1,0.74850770120905,311,40579,39,22,72
10434,434 bottles of beer on the wall,Option 1,0.73553585481622,817,15748,47,77,22
10435,435 bottles of beer on the wall,Option 1,0.3191975039985,383,22167,85,79,73
10436,436 bottles of beer on the wall,Option 1,0.30836578146944,849,12164,85,65,1
10437,437 bottles of beer on the wall,Option 1,0.24748317443182,80,12922,65,62,16
10438,438 bottles of beer on the wall,Option 1,0.81273083566349,246,18919,42,57,78
10439,439 bottles of beer on the wall,Option 1,0.23397017793449,549,49719,50,15,17
10440,440 bottles of beer on the wall,Option 1,0.52619479481419,742,35354,61,87,16
10441,441 bottles of beer on the wall,Option 1,0.52756361594775,100,42930,55,64,29
10442,442 bottles of beer on the wall,Option 1,0.65198407492227,782,42167,14,41,44
10443,443 bottles of beer on the wall,Option 1,0.0511230966314315,280,15886,87,31,52
10444,444 bottles of beer on the wall,Option 1,0.68976008365385,105,46257,66,37,6
10445,445 bottles of beer on the wall,Option 1,0.4041808938627,759,44435,63,71,69
10446,446 bottles of beer on the wall,Option 1,0.12014651304117,860,30110,54,61,64
10447,447 bottles of beer on the wall,Option 1,0.9186017284722,305,4246,75,84,61
10448,448 bottles of beer on the wall,Option 1,0.026245259226414,413,8816,67,79,12
10449,449 bottles of beer on the wall,Option 1,0.56787226887786,67,4407,31,5,8
10450,450 bottles of beer on the wall,Option 1,0.28620145064136,903,36836,25,77,29
10451,451 bottles of beer on the wall,Option 1,0.76012127975007,253,13863,59,65,36
10452,452 bottles of beer on the wall,Option 1,0.7600311770849,106,46566,99,57,79
10453,453 bottles of beer on the wall,Option 1,0.40851825634414,894,38655,14,34,57
10454,454 bottles of beer on the wall,Option 1,0.60583713725481,215,48030,77,9,82
10455,455 bottles of beer on the wall,Option 1,0.36183023097078,75,5740,13,76,95
10456,456 bottles of beer on the wall,Option 1,0.9295114483356,699,10234,52,74,92
10457,457 bottles of beer on the wall,Option 1,0.10465663303837,107,23068,27,59,18
10458,458 bottles of beer on the wall,Option 1,0.26722961909474,742,12522,12,50,38
10459,459 bottles of beer on the wall,Option 1,0.69828339372681,761,33853,42,31,59
10460,460 bottles of beer on the wall,Option 1,0.18323942002991,818,9662,0,84,61
10461,461 bottles of beer on the wall,Option 1,0.74397214257343,852,42889,46,56,59
10462,462 bottles of beer on the wall,Option 1,0.51641171915289,37,36520,76,3,21
10463,463 bottles of beer on the wall,Option 1,0.5330098092244,366,5617,11,29,54
10464,464 bottles of beer on the wall,Option 1,0.48579485178263,972,20268,70,91,72
10465,465 bottles of beer on the wall,Option 1,0.88459145179232,169,49656,62,31,95
10466,466 bottles of beer on the wall,Option 1,0.27047502681169,974,37531,63,98,68
10467,467 bottles of beer on the wall,Option 1,0.41628622888414,389,43579,89,23,60
10468,468 bottles of beer on the wall,Option 1,0.82779662722153,332,20692,50,28,57
10469,469 bottles of beer on the wall,Option 1,0.70954406247918,490,47399,57,81,14
10470,470 bottles of beer on the wall,Option 1,0.92123286515531,567,33351,22,98,86
10471,471 bottles of beer on the wall,Option 1,0.12892824091433,123,7334,0,31,68
10472,472 bottles of beer on the wall,Option 1,0.22435044833661,570,32382,22,95,74
10473,473 bottles of beer on the wall,Option 1,0.54821905705529,871,18921,6,94,44
10474,474 bottles of beer on the wall,Option 1,0.23450684651476,507,31401,81,72,16
10475,475 bottles of beer on the wall,Option 1,0.07117847123703,180,25282,58,96,16
10476,476 bottles of beer on the wall,Option 1,0.49323983792832,949,10498,11,82,84
10477,477 bottles of beer on the wall,Option 1,0.58254413054443,588,40694,82,40,79
10478,478 bottles of beer on the wall,Option 1,0.83353380106088,269,41193,66,92,15
10479,479 bottles of beer on the wall,Option 1,0.69655849351387,334,45349,22,14,93
10480,480 bottles of beer on the wall,Option 1,0.870674671545,80,18601,22,35,86
10481,481 bottles of beer on the wall,Option 1,0.17769934897203,913,4216,47,16,36
10482,482 bottles of beer on the wall,Option 1,0.62717400520442,518,35637,37,18,86
10483,483 bottles of beer on the wall,Option 1,0.86194469587036,1,28857,4,43,96
10484,484 bottles of beer on the wall,Option 1,0.44877002129739,724,7230,96,6,85
10485,485 bottles of beer on the wall,Option 1,0.50334470556273,743,10148,74,28,80
10486,486 bottles of beer on the wall,Option 1,0.90470263450625,278,20167,8,10,91
10487,487 bottles of beer on the wall,Option 1,0.0564905135224064,243,34667,74,23,33
10488,488 bottles of beer on the wall,Option 1,0.90503595858115,966,33336,51,73,40
10489,489 bottles of beer on the wall,Option 1,0.53766181996914,79,44104,70,11,12
10490,490 bottles of beer on the wall,Option 1,0.61526762722771,441,46213,85,55,10
10491,491 bottles of beer on the wall,Option 1,0.68691758796894,182,38795,93,78,62
10492,492 bottles of beer on the wall,Option 1,0.0052189598815604,231,18114,29,30,62
10493,493 bottles of beer on the wall,Option 1,0.87267877760933,213,31756,7,35,21
10494,494 bottles of beer on the wall,Option 1,0.49640192161146,534,47281,25,29,34
10495,495 bottles of beer on the wall,Option 1,0.71941438537063,152,34329,30,10,39
10496,496 bottles of beer on the wall,Option 1,0.65859091312558,965,11892,18,37,78
10497,497 bottles of beer on the wall,Option 1,0.72376093534927,598,21067,34,67,48
10498,498 bottles of beer on the wall,Option 1,0.98639214503876,299,43697,84,21,11
10499,499 bottles of beer on the wall,Option 1,0.13237802085111,838,146,80,23,45
10500,500 bottles of beer on the wall,Option 1,0.20127655621677,156,44782,60,99,19
0,this is dummy datass,Option 1,42,42,42,42,3,44
1,more dummy datass,Option 2,42,42,42,422,3,44
;;;;
`
// Generate CSV from the table data (data-driven, not hardcoded)
let csvLines = []
// Determine the table name from the `table` param (format: LIBREF.TABLE)
let tableName = ''
if (table) {
const parts = table.split('.')
tableName = parts[parts.length - 1]
}
const tableData = loadTableData(tableName)
if (tableData && tableData.columns && tableData.rows) {
// Build column ddtype lookup
const colDdtypes = {}
for (const col of tableData.columns) {
const fmt = (col.format || '').toLowerCase()
let ddtype = col.type === 'N' ? 'N' : 'C'
if (fmt.startsWith('datetime') || fmt.startsWith('e8601dt')) ddtype = 'DATETIME'
else if (fmt.startsWith('date')) ddtype = 'DATE'
else if (fmt.startsWith('time')) ddtype = 'TIME'
colDdtypes[col.name.toUpperCase()] = ddtype
}
for (const row of tableData.rows) {
const values = []
for (const col of tableData.columns) {
let val = row[col.name]
if (val === undefined) val = row[col.name.toLowerCase()]
if (val === undefined) {
const key = Object.keys(row).find(k => k.toLowerCase() === col.name.toLowerCase())
if (key) val = row[key]
}
if (val === null || val === undefined) {
val = ''
} else {
const ddtype = colDdtypes[col.name.toUpperCase()]
if (ddtype === 'DATE' || ddtype === 'DATETIME' || ddtype === 'TIME') {
val = formatSasValue(val, ddtype)
} else {
val = String(val)
}
// Quote if contains comma or quote
if (val.includes(',') || val.includes('"')) {
val = '"' + val.replace(/"/g, '""') + '"'
}
}
values.push(val)
}
csvLines.push(values.join(','))
}
}
_webout = csvLines.join('\n')
@@ -41,7 +41,7 @@ try {
}
try {
fs.writeFileSync(usersStore, JSON.stringify(newUsers))
fs.writeFileSync(usersStore, JSON.stringify(newUsers, null, 2))
} catch (err) {}
}
} catch(err) {
@@ -121,6 +121,7 @@ ${sasdatasetsJson}
[
{"DCLIB": "${dcLibref}",
"SAS9LINEAGE_ENABLED": 1,
"ISADMIN": 1,
"ISREGISTERED": ${users.ISREGISTERED},
"REGISTERCOUNT": ${users.REGISTERCOUNT},
"DC_ADMIN_GROUP": "${adminGroup}",
@@ -9,8 +9,8 @@ if (!fs.existsSync(sessionStoragePath)){
fs.mkdirSync(sessionStoragePath);
}
if (_WEBIN_FILENAME1.includes('filterquery')) iwantFileText = _WEBIN_FILEREF1.toString()
if (_WEBIN_FILENAME2.includes('filterquery')) iwantFileText = _WEBIN_FILEREF2.toString()
if (_webin_filename1.includes('filterquery')) iwantFileText = _webin_fileref1.toString()
if (_webin_filename2.includes('filterquery')) iwantFileText = _webin_fileref2.toString()
if (iwantFileText.length > 0) {
const filterStore = path.resolve(sessionStoragePath, 'filter.txt')
+46 -118
View File
@@ -6,45 +6,18 @@ const driveRoot = nodePath.resolve(sasjsRoot, 'drive')
const dcLibref = 'DC_JSLIB'
const dataDir = nodePath.resolve(driveRoot, 'files', appLoc, 'data', dcLibref)
// Helper: load a table JSON file
function loadTableData(tableName) {
try {
const file = nodePath.resolve(dataDir, tableName.toLowerCase() + '.json')
return JSON.parse(fs.readFileSync(file, {encoding:'utf8'}).toString())
} catch(err) { return null }
}
eval(fs.readFileSync(nodePath.resolve(driveRoot, 'files', appLoc, 'services', 'dcMockUtils.js'), 'utf8'))
const loadTableData = makeTableLoader(dataDir)
// Parse SASControlTable for LIBDS and FILTER_RK
let libds = ''
let filterText = ''
let sasControlTableFileText = ''
for (let i = 1; i <= 10; i++) {
const nameVar = '_WEBIN_NAME' + i
try {
const nameVal = eval(nameVar)
if (nameVal && nameVal.toLowerCase() === 'sascontroltable') {
const refVar = '_WEBIN_FILEREF' + i
sasControlTableFileText = eval(refVar).toString()
break
}
} catch(e) { break }
}
try {
const lines = sasControlTableFileText.split(/\r?\n/)
if (lines.length >= 2) {
const headers = lines[0].trim().split(/\s+/).map(h => h.split(':')[0].trim().toLowerCase())
const values = lines[1].trim().split(',')
const libdsIdx = headers.indexOf('libds')
if (libdsIdx >= 0) libds = values[libdsIdx] || ''
}
} catch(err) {}
// ─── Parse input ──────────────────────────────────────────────────────────────
const _sctRow = fetchTable('SASControlTable')[0] || {}
let libds = _sctRow.LIBDS || ''
const libref = libds.split('.')[0] || dcLibref
const dsn = libds.split('.')[1] || ''
// Load the requested table
// ─── Build response ──────────────────────────────────────────────────────────
const tableData = loadTableData(dsn)
let cols = []
@@ -53,32 +26,20 @@ let vars = {}
let nobs = 0
if (tableData && tableData.columns) {
// viewdata sends ALL columns (no MPE_TABLES filtering, no TX_FROM/TX_TO removal)
// cols format for viewdata is different from getdata - includes TYPE, LENGTH, FORMAT
cols = tableData.columns.map(col => {
const fmt = col.format || ''
let ddtype = col.type === 'N' ? 'N' : 'C'
if (fmt.startsWith('datetime') || fmt.startsWith('E8601DT')) ddtype = 'DATETIME'
else if (fmt.startsWith('date')) ddtype = 'DATE'
else if (fmt.startsWith('time')) ddtype = 'TIME'
const fmtname = fmt
? fmt.replace(/[\d.]+$/, '').replace('datetime', 'DATETIME').replace('date', 'DATE').replace('time', 'TIME').replace('best', 'BEST').replace('E8601DT', 'DATETIME')
const ddtype = getDdType(col)
const fmtname = col.format
? col.format.replace(/[\d.]+$/, '').replace('datetime', 'DATETIME').replace('date', 'DATE').replace('time', 'TIME').replace('best', 'BEST').replace('E8601DT', 'DATETIME')
: ' '
const formatStr = col.type === 'N'
? (fmt || (col.length === 4 ? '8.' : '8.'))
: '$' + col.length + '.'
const formatStr = col.type === 'N' ? (col.format || '8.') : ('$' + col.length + '.')
return {
NAME: col.name,
TYPE: col.type === 'N' ? 'N' : 'C',
LENGTH: col.length,
FORMAT: formatStr,
FMTNAME: fmtname || ' ',
DDTYPE: ddtype,
NAME: col.name, TYPE: col.type === 'N' ? 'N' : 'C', LENGTH: col.length,
FORMAT: formatStr, FMTNAME: fmtname || ' ', DDTYPE: ddtype,
LABEL: col.label || col.name
}
}).sort((a, b) => a.NAME.localeCompare(b.NAME))
// viewdata rows: all values as strings (SAS proc print style)
// viewdata rows: all values as strings (formatted, SAS proc-print style)
viewdata = (tableData.rows || []).map(r => {
const row = {}
for (const col of tableData.columns) {
@@ -89,22 +50,24 @@ if (tableData && tableData.columns) {
const key = Object.keys(r).find(k => k.toLowerCase() === lcName)
if (key) val = r[key]
}
// Format date/datetime/time values to SAS display format
const fmt = (col.format || '').toLowerCase()
const ddtype = getDdType(col)
if (val !== undefined && val !== null && val !== '') {
if (fmt.startsWith('datetime') || fmt.startsWith('e8601dt')) {
// Convert ISO datetime to SAS format: DDMMMYY:HH:MM:SS
const m = String(val).match(/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/)
if (m) {
const months = ['JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC']
val = `${parseInt(m[3])}${months[parseInt(m[2])-1]}${m[1].slice(2)}:${m[4]}:${m[5]}:${m[6]}`
}
} else if (fmt.startsWith('date')) {
// Convert ISO date to SAS format: DDMMMYYYY
const m = String(val).match(/^(\d{4})-(\d{2})-(\d{2})/)
if (m) {
const months = ['JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC']
val = `${parseInt(m[3])}${months[parseInt(m[2])-1]}${m[1]}`
if (typeof val === 'number') {
val = formatSasValue(val, ddtype)
} else {
// Try converting ISO/old-format strings to SAS display format
if (ddtype === 'DATETIME') {
const m = String(val).match(/^(\d{4})-(\d{2})-(\d{2})[ T](\d{2}):(\d{2}):(\d{2})/)
if (m) {
const mn = ['JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC']
val = `${parseInt(m[3])}${mn[parseInt(m[2])-1]}${m[1].slice(2)}:${m[4]}:${m[5]}:${m[6]}`
}
} else if (ddtype === 'DATE') {
const m = String(val).match(/^(\d{4})-(\d{2})-(\d{2})/)
if (m) {
const mn = ['JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC']
val = `${parseInt(m[3])}${mn[parseInt(m[2])-1]}${m[1]}`
}
}
}
}
@@ -113,33 +76,18 @@ if (tableData && tableData.columns) {
return row
})
// $viewdata vars - keeps original SAS types (num stays num, char stays char)
// $viewdata vars: keep original SAS types (num stays num, char stays char)
vars = {}
for (const col of tableData.columns) {
const fmt = col.format || ''
let formatStr
if (col.type === 'N') {
formatStr = fmt || 'best.'
} else {
formatStr = '$' + col.length + '.'
}
vars[col.name] = {
format: formatStr,
label: col.label || col.name,
length: String(col.length),
type: col.type === 'N' ? 'num' : 'char'
}
vars[col.name] = sasVarsEntry(col)
}
nobs = tableData.rows ? tableData.rows.length : 0
}
_webout = JSON.stringify({
SYSDATE: '27AUG26',
SYSTIME: '11:26',
cls_rules: [],
cols: cols,
dsmeta: [
SYSDATE: '26SEP22', SYSTIME: '08:43',
cls_rules: [], cols, dsmeta: [
{ ODS_TABLE: 'ATTRIBUTES', NAME: 'Data Set Name', VALUE: libref + '.' + dsn },
{ ODS_TABLE: 'ATTRIBUTES', NAME: 'Observations', VALUE: String(nobs) },
{ ODS_TABLE: 'ATTRIBUTES', NAME: 'Member Type', VALUE: 'DATA' },
@@ -148,36 +96,16 @@ _webout = JSON.stringify({
],
query: [],
sasparams: [{
TABLEURI: ' ',
TABLENAME: dsn,
FILTER_TEXT: filterText || ' ',
PK_FIELDS: ' ',
NOBS: nobs,
VARS: cols.length,
MAXROWS: 500
TABLEURI: ' ', TABLENAME: dsn, FILTER_TEXT: ' ',
PK_FIELDS: ' ', NOBS: nobs, VARS: cols.length, MAXROWS: 500
}],
versions: [],
viewdata: viewdata,
$viewdata: { vars: vars },
_DEBUG: '',
_METAUSER: 'sasdemo@SAS',
_METAPERSON: 'sasdemo',
_PROGRAM: _program,
AUTOEXEC: '',
MF_GETUSER: 'sasdemo',
SYSCC: '0',
SYSENCODING: 'utf-8',
SYSERRORTEXT: '',
SYSHOSTNAME: 'sasjs-server',
SYSPROCESSID: '0',
SYSPROCESSMODE: 'Stored Program',
SYSPROCESSNAME: '',
SYSJOBID: '0',
SYSSCPL: 'LINUX',
SYSSITE: '123',
SYSUSERID: 'sasdemo',
SYSVLONG: '9.04.01M7P080520',
SYSWARNINGTEXT: '',
END_DTTM: new Date().toISOString(),
MEMSIZE: '0KB'
versions: [], viewdata, $viewdata: { vars },
_DEBUG: '', _METAUSER: 'sasdemo@SAS', _METAPERSON: 'sasdemo',
_PROGRAM: _program, AUTOEXEC: '', MF_GETUSER: 'sasdemo',
SYSCC: '0', SYSENCODING: 'utf-8', SYSERRORTEXT: '',
SYSHOSTNAME: 'sasjs-server', SYSPROCESSID: '0',
SYSPROCESSMODE: 'Stored Program', SYSPROCESSNAME: '',
SYSJOBID: '0', SYSSCPL: 'LINUX', SYSSITE: '123',
SYSUSERID: 'sasdemo', SYSVLONG: '9.04.01M7P080520',
SYSWARNINGTEXT: '', END_DTTM: new Date().toISOString(), MEMSIZE: '0KB'
})
+1 -1
View File
@@ -11,7 +11,7 @@ let saslibs = [
LIBRARYID: 'DC_JSLIB',
LIBRARYNAME: 'Data Controller(' + dcLibref + ')',
LIBRARYREF: dcLibref,
ENGINE: 'BASE'
ENGINE: 'V9'
}
]