theprogrammablemind 7.5.8-beta.6 → 7.5.8-beta.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/config.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // lookup = (name) => returns <config>
2
2
  const { Semantics, normalizeGenerator } = require('./semantics')
3
3
  const { Generators } = require('./generators')
4
- // const { uuid: uuidv4 } = require('uuidv4')
4
+ const { v4 : uuidv4 } = require('uuid');
5
5
  const client = require('../client')
6
6
  const DigraphInternal = require('./digraph_internal')
7
7
  const helpers = require('./helpers')
@@ -22,7 +22,144 @@ const indent = (string, indent) => {
22
22
  return string.replace(/^/gm, ' '.repeat(indent));
23
23
  }
24
24
 
25
- const handleBridgeProps = (config, bridge) => {
25
+ const config_toServer = (config) => {
26
+ if (config.contextual_priorities) {
27
+ config.contextual_priorities = config.contextual_priorities.map((cp) => {
28
+ return [cp.context, cp.choose]
29
+ })
30
+ }
31
+ }
32
+
33
+ const validConfigProps = (config) => {
34
+ const valid = [
35
+ 'hierarchy',
36
+ 'objects',
37
+ 'bridges',
38
+ 'operators',
39
+ 'words',
40
+ 'priorities',
41
+ 'contextual_priorities',
42
+ 'associations',
43
+ 'name',
44
+ 'version',
45
+ 'generatorp',
46
+ 'generators',
47
+ 'semantics',
48
+ 'where',
49
+ 'floaters',
50
+ 'debug',
51
+
52
+ // TODO Fix these from the test app
53
+ 'implicits',
54
+ 'convolution',
55
+ 'expected_generated',
56
+ 'expected_results',
57
+ 'skipSemantics',
58
+ 'description',
59
+ 'contexts',
60
+ 'utterances',
61
+ 'flatten',
62
+
63
+ 'namespaces',
64
+ 'eqClasses',
65
+ ]
66
+ helpers.validProps(valid, config, 'config')
67
+ }
68
+
69
+ const setupInitializerFNArgs = (config, args) => {
70
+ const aw = (word, def) => config.addWord(word, def, args.uuid)
71
+ const ag = (generator) => config.addGenerator(generator, args.uuid, config.name)
72
+ const km = (name) => config.getConfig(name)
73
+ const apis = (name) => config.getConfig(name).api
74
+
75
+ return {
76
+ ...args,
77
+ addWord: aw,
78
+ addGenerator: ag,
79
+ config: config.getPseudoConfig(args.uuid, args.currentConfig),
80
+ km,
81
+ baseConfig: config,
82
+ apis,
83
+ }
84
+ }
85
+
86
+ const contextual_priorities_toServer = (cp) => {
87
+ if (cp.context && cp.choose) {
88
+ return [cp.context, cp.choose]
89
+ }
90
+ return cp
91
+ }
92
+
93
+ const contextual_priorities_toClient = (cp) => {
94
+ if (cp.context && cp.choose) {
95
+ return cp
96
+ }
97
+ return { context: cp[0], choose: cp[1] }
98
+ }
99
+
100
+ const operatorKey_valid = (key) => {
101
+ if (
102
+ !_.isArray(key) ||
103
+ key.length != 2 ||
104
+ !_.isString(key[0]) ||
105
+ !_.isInteger(key[1]) ||
106
+ key[1] < 0
107
+ ) {
108
+
109
+ let details = ''
110
+ if (!_.isArray(key)) {
111
+ details = "Expected an array."
112
+ } else if (key.length != 2) {
113
+ details = "Expected an array of length two."
114
+ } else if (!_.isString(key[0])) {
115
+ details = "Expected element zero to be a string that is an operator id."
116
+ } else if (!_.isInteger(key[1])) {
117
+ details = "Expected element one to be a number that is an operator level."
118
+ } else if (key[1] < 0) {
119
+ details = "Expected element one to be a number that is an operator level which is greater than zero."
120
+ }
121
+ throw new Error(`${JSON.stringify(key)} is not a valid operator key. Values are of the form [<operatorId>, <operatorLevel>]. ${details}`)
122
+ }
123
+ }
124
+
125
+ const elist = (list, check, prefix) => {
126
+ for ([index, element] of list.entries()) {
127
+ try {
128
+ check(element)
129
+ } catch( e ) {
130
+ throw new Error(prefix(index, e))
131
+ }
132
+ }
133
+ }
134
+ const contextual_priorities_valid = (cps) => {
135
+ elist(cps, (cp) => contextual_priority_valid(cp), (index, e) => `contextual_priorities has an invalid contextual priority at position ${index}. ${e}`)
136
+ }
137
+
138
+ const contextual_priority_valid = (cp) => {
139
+ if (!cp.context) {
140
+ throw new Error(`The contextual priority ${JSON.stringify(cp)} is missing the "context" property. That is a list of the operator keys that are to be prioritized differently.`)
141
+ }
142
+ if (!_.isArray(cp.context)) {
143
+ throw new Error(`The contextual priority ${JSON.stringify(cp)} has an invalid "context" value. That is a list of the operator keys that are to be prioritized differently.`)
144
+ }
145
+ elist(cp.context, (element) => operatorKey_valid(element), (index, e) => `The contextual priority ${JSON.stringify(cp)} has an invalid operator key at position ${index}. ${e}`)
146
+ if (!_.isArray(cp.choose)) {
147
+ throw new Error(`The contextual priority ${JSON.stringify(cp)} has an invalid "choose" value. The value should be a list of the operators in the context to consider for prioritization.`)
148
+ }
149
+ elist(cp.choose,
150
+ (element) => {
151
+ if (!element && element !== 0) {
152
+ throw new Error(`The value should be an index into the "context" property of the operator that is to be considered for prioritization.`)
153
+ }
154
+ if (!_.isInteger(element) || element < 0 || element >= cp.context.length) {
155
+ throw new Error(`The value should be an index into the "context" property of the operator that is to be considered for prioritization. Valid values are between 0 and ${cp.context.length-1}.`)
156
+ }
157
+ },
158
+ (index, e) => `The choose property in the contextual priority ${JSON.stringify(cp)} has an invalid index at position ${index}. ${e}`
159
+ )
160
+ }
161
+
162
+ const handleBridgeProps = (config, bridge, addFirst) => {
26
163
  ecatch(`While processing the bridge for ${bridge.id}#${bridge.level}`,
27
164
  () => {
28
165
  if (!bridge.bridge) {
@@ -68,19 +205,29 @@ const handleBridgeProps = (config, bridge) => {
68
205
  config.addWordInternal(def, {"id": bridge.id, "initial": `{ value: "${def}"}` })
69
206
  } else {
70
207
  const word = def.word
71
- def = { initial: JSON.stringify(def), id: bridge.id, word: undefined }
208
+ def = { initial: JSON.stringify(def), id: bridge.id, word }
72
209
  config.addWordInternal(word, def)
73
210
  }
74
211
  }
75
212
  }
213
+ /*
76
214
  if (bridge.generator) {
77
- config.config.generators.unshift(bridge.generator)
215
+ if (addFirst) {
216
+ config.config.generators.unshift(bridge.generator)
217
+ } else {
218
+ config.config.generators.push(bridge.generator)
219
+ }
78
220
  }
221
+ */
79
222
  if (bridge.generators) {
80
223
  const generators = [...bridge.generators]
81
224
  generators.reverse()
82
225
  for (let generator of generators) {
83
- config.config.generators.unshift(generator)
226
+ if (addFirst) {
227
+ config.config.generators.unshift(generator)
228
+ } else {
229
+ config.config.generators.push(generator)
230
+ }
84
231
  }
85
232
  }
86
233
  if (bridge.generatorpr) {
@@ -91,66 +238,76 @@ const handleBridgeProps = (config, bridge) => {
91
238
  const match = bridge.generatorp.match || (() => true)
92
239
  const apply = typeof bridge.generatorp == 'function' ? bridge.generatorp : bridge.generatorp.apply || bridge.generatorp
93
240
  const level = bridge.generatorp.level >= 0 ? bridge.generatorp.level : bridge.level + 1
94
- config.config.generators.unshift({
241
+
242
+ const generator = {
95
243
  where: bridge.generatorp.where || bridge.where || client.where(4),
96
244
  match: (args) => bridge.id == args.context.marker && args.context.level == level && args.context.paraphrase && match(args),
97
245
  apply: (args) => apply(args),
98
246
  applyWrapped: apply,
99
247
  property: 'generatorp',
100
- })
248
+ }
249
+ if (addFirst) {
250
+ config.config.generators.unshift(generator)
251
+ } else {
252
+ config.config.generators.push(generator)
253
+ }
254
+
101
255
  }
102
256
  if (bridge.generatorr) {
103
257
  const match = bridge.generatorr.match || (() => true)
104
258
  const apply = typeof bridge.generatorr == 'function' ? bridge.generatorr : bridge.generatorr.apply || bridge.generatorr
105
259
  const level = bridge.generatorr.level >= 0 ? bridge.generatorr.level : bridge.level + 1
106
- config.config.generators.unshift({
260
+ const generator = {
107
261
  where: bridge.generatorr.where || bridge.where || client.where(4),
108
262
  match: (args) => bridge.id == args.context.marker && args.context.level == level && !args.context.paraphrase && (args.context.response || args.context.isResponse) && match(args),
109
263
  apply: (args) => apply(args),
110
264
  applyWrapped: apply,
111
265
  property: 'generatorr',
112
- })
113
- }
114
- /*
115
- if (bridge.generatorr) {
116
- config.config.generators.unshift({
117
- // TODO merge response and isResponse
118
- where: bridge.generatorr.where || bridge.where || client.where(3),
119
- match: ({context}) => bridge.id == context.marker && !context.paraphrase && (context.response || context.isResponse),
120
- apply: (args) => bridge.generatorr(args),
121
- applyWrapped: bridge.generatorr,
122
- property: 'generatorr',
123
- })
266
+ }
267
+ if (addFirst) {
268
+ config.config.generators.unshift(generator)
269
+ } else {
270
+ config.config.generators.push(generator)
271
+ }
124
272
  }
125
- */
126
273
  if (bridge.evaluator) {
127
- config.config.semantics.unshift({
274
+ const semantic = {
128
275
  where: bridge.evaluator.where || bridge.where || client.where(3),
129
276
  match: ({context}) => bridge.id == context.marker && context.evaluate,
130
277
  apply: (args) => bridge.evaluator(args),
131
278
  applyWrapped: bridge.evaluator,
132
279
  property: 'evaluator',
133
- })
280
+ }
281
+ if (addFirst) {
282
+ config.config.semantics.unshift(semantic)
283
+ } else {
284
+ config.config.semantics.push(semantic)
285
+ }
134
286
  }
135
287
  if (bridge.semantic) {
136
- config.config.semantics.unshift({
288
+ const semantic = {
137
289
  where: bridge.semantic.where || bridge.where || client.where(3),
138
290
  match: ({context}) => bridge.id == context.marker,
139
291
  apply: (args) => bridge.semantic(args),
140
292
  applyWrapped: bridge.semantic,
141
293
  property: 'semantic',
142
- })
294
+ }
295
+ if (addFirst) {
296
+ config.config.semantics.unshift(semantic)
297
+ } else {
298
+ config.config.semantics.push(semantic)
299
+ }
143
300
  }
144
301
  }
145
302
  )
146
303
  }
147
304
 
148
- const handleCalculatedProps = (baseConfig, moreConfig) => {
149
- for (let bridge of moreConfig.bridges) {
305
+ const handleCalculatedProps = (baseConfig, moreConfig, addFirst) => {
306
+ for (let bridge of (moreConfig.bridges || [])) {
150
307
  const valid = [ 'after', 'before', 'bridge', 'development', 'evaluator', 'generatorp', 'generatorr', 'generatorpr', 'generators', 'id', 'convolution', 'inverted', 'isA', 'children', 'parents',
151
- 'level', 'optional', 'selector', 'semantic', 'words', /Bridge$/, 'localHierarchy', 'levelSpecificHierarchy', 'where' ]
308
+ 'level', 'optional', 'selector', 'semantic', 'words', /Bridge$/, 'localHierarchy', 'levelSpecificHierarchy', 'where', 'uuid' ]
152
309
  helpers.validProps(valid, bridge, 'bridge')
153
- handleBridgeProps(baseConfig, bridge)
310
+ handleBridgeProps(baseConfig, bridge, addFirst)
154
311
  }
155
312
  if (moreConfig.operators) {
156
313
  moreConfig.operators = moreConfig.operators.map((operator) => {
@@ -171,6 +328,10 @@ if (runtime.process.env.DEBUG_PRIORITY) {
171
328
  global.entodictonDebugPriority = JSON.parse(runtime.process.env.DEBUG_PRIORITY)
172
329
  }
173
330
 
331
+ if (runtime.process.env.DEBUG_CONTEXTUAL_PRIORITY) {
332
+ global.entodictonDebugContextualPriority = JSON.parse(runtime.process.env.DEBUG_CONTEXTUAL_PRIORITY)
333
+ }
334
+
174
335
  if (runtime.process.env.DEBUG_ASSOCIATION) {
175
336
  global.entodictonDebugAssociation = JSON.parse(runtime.process.env.DEBUG_ASSOCIATION)
176
337
  }
@@ -252,6 +413,14 @@ const normalizeConfig = (config) => {
252
413
  }
253
414
  }
254
415
  }
416
+
417
+ if (config.semantics) {
418
+ for (let semantic of config.semantics) {
419
+ if (semantic.oneShot) {
420
+ semantic.id = uuid()
421
+ }
422
+ }
423
+ }
255
424
  }
256
425
  }
257
426
 
@@ -459,8 +628,8 @@ const multiApiImpl = (initializer) => {
459
628
  initializer(config, api)
460
629
  const name = api.getName()
461
630
  multiApi.apis[name] = api
462
- api.objects = config.get('objects')
463
- api.config = () => config
631
+ // api.objects = config.get('objects')
632
+ // api.config = () => config
464
633
  multiApi.current = name
465
634
  },
466
635
 
@@ -471,11 +640,13 @@ const multiApiImpl = (initializer) => {
471
640
  }
472
641
  },
473
642
 
643
+ /*
474
644
  set objects (value) {
475
645
  for (const key in Object.keys(this.apis)) {
476
646
  this.apis[key].objects = value
477
647
  }
478
648
  },
649
+ */
479
650
 
480
651
  // "product1": apiInstance(testData1),
481
652
  apis: {
@@ -489,6 +660,46 @@ const multiApiImpl = (initializer) => {
489
660
 
490
661
  class Config {
491
662
 
663
+ toServer (config) {
664
+ return config_toServer(config)
665
+ }
666
+
667
+ base () {
668
+ const base = new Config()
669
+ for (let km of this.configs.reverse()) {
670
+ if (km.isSelf) {
671
+ continue
672
+ }
673
+ base.add(km.config)
674
+ }
675
+ return base
676
+ }
677
+
678
+ getPseudoConfig (uuid, config) {
679
+ return {
680
+ description: "this is a pseudo config that has limited functionality due to being available in the initializer function context",
681
+ addAssociation: (...args) => this.addAssociation(...args),
682
+ addAssociations: (...args) => this.addAssociations(...args),
683
+ addBridge: (...args) => this.addBridge(...args, uuid),
684
+ addContextualPriority: (...args) => this.addContextualPriority(...args),
685
+ addGenerator: (...args) => this.addGenerator(...args, uuid, config.name),
686
+ addHierarchy: (...args) => this.addHierarchy(...args),
687
+ addOperator: (...args) => this.addOperator(...args, uuid),
688
+ addPriorities: (...args) => this.addPriorities(...args),
689
+ addSemantic: (...args) => this.addSemantic(...args, uuid, config.name),
690
+ removeSemantic: (...args) => this.removeSemantic(...args, uuid, config.name),
691
+ addWord: (...args) => this.addWord(...args, uuid),
692
+
693
+ getHierarchy: (...args) => this.config.hierarchy,
694
+ getBridges: (...args) => this.config.bridges,
695
+
696
+ addArgs: (...args) => this.addArgs(...args),
697
+ getBridge: (...args) => this.getBridge(...args),
698
+ fragment: (...args) => this.fragment(...args),
699
+ addAPI: (...args) => this.addAPI(...args),
700
+ }
701
+ }
702
+
492
703
  inDevelopmentMode (call) {
493
704
  config.developmentModeOn += 1
494
705
  try {
@@ -527,9 +738,6 @@ class Config {
527
738
  }
528
739
 
529
740
  setTestConfig(testConfig) {
530
- if (this.name == 'ui') {
531
- console.log('ui setting testConfig')
532
- }
533
741
  this.testConfig = testConfig
534
742
  }
535
743
 
@@ -548,6 +756,7 @@ class Config {
548
756
  },
549
757
  eqClasses: [],
550
758
  priorities: [], // Done
759
+ contextual_priorities: [],
551
760
  version: '3',
552
761
  debug: false,
553
762
  associations: { // Done
@@ -586,6 +795,7 @@ class Config {
586
795
  'namespaces',
587
796
  'eqClasses',
588
797
  'priorities',
798
+ 'contextual_priorities',
589
799
  'associations',
590
800
  'words',
591
801
  'floaters',
@@ -709,7 +919,8 @@ class Config {
709
919
  }
710
920
  }
711
921
 
712
- needsRebuild(template, instance, options = { rebuild: false }) {
922
+ // { rebuild: false, isModule: false }
923
+ needsRebuild(template, instance, options) {
713
924
  if (options.rebuild) {
714
925
  return true
715
926
  }
@@ -723,7 +934,41 @@ class Config {
723
934
  const instanceFragments = (instance.fragments || []).map((fragment) => fragment.key || fragment.query).map( toCanonical )
724
935
  const templateFragments = (template.fragments || []).concat(this.dynamicFragments).map( toCanonical )
725
936
  const sameFragments = helpers.safeEquals(templateFragments, instanceFragments)
726
- const sameQueries = helpers.safeEquals((template.queries || []).map(helpers.updateQueries), (instance.queries || []))
937
+ const toCanonicalQuery = (queryOrConfig) => {
938
+ if (typeof queryOrConfig == 'string') {
939
+ const query = queryOrConfig
940
+ return query
941
+ } else {
942
+ const config = { ...queryOrConfig }
943
+ delete config.where
944
+ if (options.isModule) {
945
+ // things like webpack rewrite the functions if there are constants so this compare does not work
946
+ delete config.generators
947
+ delete config.semantics
948
+ } else {
949
+ config.generators = (config.generators || []).map((generator) => {
950
+ generator = {...generator}
951
+ delete generator.where
952
+ generator.match = generator.match.toString()
953
+ generator.apply = generator.apply.toString()
954
+ return generator
955
+ })
956
+ config.semantics = (config.semantics || []).map((semantic) => {
957
+ semantic = {...semantic}
958
+ delete semantic.where
959
+ semantic.match = semantic.match.toString()
960
+ semantic.apply = semantic.apply.toString()
961
+ return semantic
962
+ })
963
+ }
964
+ return config
965
+ }
966
+ }
967
+ const toCanonicalQueries = (elements) => {
968
+ return elements.map( toCanonicalQuery )
969
+ }
970
+
971
+ const sameQueries = helpers.safeEquals(toCanonicalQueries(template.queries || []).map(helpers.updateQueries), toCanonicalQueries(instance.queries || []))
727
972
  return !(instance && sameQueries && sameFragments)
728
973
  }
729
974
 
@@ -739,6 +984,12 @@ class Config {
739
984
  }
740
985
  }
741
986
 
987
+ toData (data) {
988
+ Object.assign(data, this.config)
989
+ config_toServer(data)
990
+ }
991
+
992
+ // loadTemplate
742
993
  load (template, instance, options = { rebuild: false } ) {
743
994
  this.validifyTemplate(template)
744
995
  instance.template = template
@@ -750,7 +1001,7 @@ class Config {
750
1001
  // TODO fix beforeQuery
751
1002
  template = { fragments: [], queries: [], ...template }
752
1003
  template.fragments = template.fragments.concat(this.dynamicFragments)
753
- client.build({ config: this, target: this.name, beforeQuery: () => {}, template, ...options })
1004
+ client.rebuildTemplate({ config: this, target: this.name, beforeQuery: () => {}, template, ...options })
754
1005
  } else {
755
1006
  // no change
756
1007
  // this.initInstances.push({ ...instance, name: config.name })
@@ -768,7 +1019,7 @@ class Config {
768
1019
  instance.name = this.name
769
1020
  this.initInstances.push(instance)
770
1021
  this.instances.push(instance)
771
- client.processInstance(this, instance)
1022
+ client.loadInstance(this, instance)
772
1023
  }
773
1024
  }
774
1025
  }
@@ -825,6 +1076,22 @@ class Config {
825
1076
  this._delta.json.priorities.push({ action: 'add', priorities })
826
1077
  }
827
1078
 
1079
+ // [ operators: <list of [id, level]>, select: <index of prioritized operator> ]
1080
+ addContextualPriority(contextual_priority) {
1081
+ if (!this.config.contextual_priorities) {
1082
+ this.config.contextual_priorities = []
1083
+ }
1084
+ if (global.entodictonDebugContextualPriority) {
1085
+ if (helpers.safeEquals(entodictonDebugContextualPriority, contextual_priorities)) {
1086
+ debugger; // debug hierarchy hit
1087
+ }
1088
+ }
1089
+ contextual_priority_valid(contextual_priority)
1090
+ this.config.contextual_priorities.push(contextual_priority)
1091
+ const cpServer = contextual_priorities_toServer(contextual_priority)
1092
+ this._delta.json.contextual_priorities.push({ action: 'add', contextual_priority: cpServer })
1093
+ }
1094
+
828
1095
  addHierarchy (child, parent) {
829
1096
  if (child && parent || !child || Array.isArray(child) || (typeof child == 'string' && !parent)) {
830
1097
  this.addHierarchyChildParent(child, parent)
@@ -881,15 +1148,19 @@ class Config {
881
1148
  }
882
1149
 
883
1150
  getBridge (id, level) {
884
- return this.config.bridges.find( (bridge) => bridge.id == id && bridge.level == level )
1151
+ if (level) {
1152
+ return this.config.bridges.find( (bridge) => bridge.id == id && bridge.level == level )
1153
+ } else {
1154
+ return this.config.bridges.find( (bridge) => bridge.id == id)
1155
+ }
885
1156
  }
886
1157
 
887
- addBridge (bridge) {
1158
+ addBridge (bridge, uuid) {
888
1159
  if (!this.config.bridges) {
889
1160
  this.config.bridges = []
890
1161
  }
891
1162
  const bridges = this.config.bridges
892
- const def = Object.assign({}, bridge, { uuid: this._uuid })
1163
+ const def = Object.assign({}, bridge, { uuid: uuid || this._uuid })
893
1164
 
894
1165
  if (global.entodictonDebugBridge) {
895
1166
  if (global.entodictonDebugBridge[0] == bridge.id && global.entodictonDebugBridge[1] == bridge.level) {
@@ -911,12 +1182,7 @@ class Config {
911
1182
  this._delta.json.bridges.push({ action: 'add', bridge: def })
912
1183
  }
913
1184
 
914
- addGenerator (match, apply) {
915
- let generator = match
916
- if ((typeof match === 'function') && (typeof apply === 'function')) {
917
- generator = { match, apply }
918
- }
919
-
1185
+ addGenerator (generator, uuid, name) {
920
1186
  if (!(typeof generator.match === 'function')) {
921
1187
  throw new Error('addGenerator: Expected matcher to be a function')
922
1188
  }
@@ -933,20 +1199,16 @@ class Config {
933
1199
  }
934
1200
 
935
1201
  const generators = this.config.generators
936
- Object.assign(generator, { uuid: this._uuid, km: this.name, index: generators.length })
1202
+ Object.assign(generator, { uuid: uuid || this._uuid, km: name || this.name, index: generators.length })
937
1203
  // used to be unshift
938
1204
  generators.unshift(generator)
939
1205
  }
940
1206
 
941
- addSemantic (match, apply) {
942
- let semantic = match
943
- if ((typeof match === 'function') && (typeof apply === 'function')) {
944
- semantic = { match, apply }
945
- }
946
-
1207
+ addSemantic (semantic, uuid, name) {
947
1208
  if (!(typeof semantic.match === 'function')) {
948
1209
  throw new Error('addSemantic: Expected match to be a function')
949
1210
  }
1211
+
950
1212
  if (!(typeof semantic.apply === 'function')) {
951
1213
  throw new Error('addSemantic: Expected apply to be a function')
952
1214
  }
@@ -960,11 +1222,18 @@ class Config {
960
1222
  }
961
1223
 
962
1224
  const semantics = this.config.semantics
963
- Object.assign(semantic, { uuid: this._uuid, km: this.name, index: semantics.length })
1225
+ Object.assign(semantic, { uuid: uuid || semantic.uuid || this._uuid, km: name || this.name, index: semantics.length, id: semantic.id || uuidv4() })
964
1226
  semantics.unshift(semantic)
965
1227
  }
966
1228
 
967
- addOperator (objectOrPattern) {
1229
+ removeSemantic(deleteSemantic) {
1230
+ const index = this.config.semantics.findIndex( (semantic) => semantic.id === deleteSemantic.id )
1231
+ if (index >= 0) {
1232
+ this.config.semantics.splice(index, 1)
1233
+ }
1234
+ }
1235
+
1236
+ addOperator (objectOrPattern, uuid) {
968
1237
  if (!this.config.operators) {
969
1238
  this.config.operators = []
970
1239
  }
@@ -973,9 +1242,9 @@ class Config {
973
1242
 
974
1243
  let operator;
975
1244
  if (typeof objectOrPattern === 'string') {
976
- operator = { pattern: objectOrPattern, uuid: this._uuid }
1245
+ operator = { pattern: objectOrPattern, uuid: uuid || this._uuid }
977
1246
  } else {
978
- operator = Object.assign({}, objectOrPattern, { uuid: this._uuid })
1247
+ operator = Object.assign({}, objectOrPattern, { uuid: uuid || this._uuid })
979
1248
  }
980
1249
 
981
1250
  if (global.entodictonDebugOperator) {
@@ -996,16 +1265,16 @@ class Config {
996
1265
  this._delta.json.operators.push({ action: 'add', operator })
997
1266
  }
998
1267
 
999
- addWord (word, def) {
1000
- this.addWordInternal(word, def)
1268
+ addWord (word, def, uuid) {
1269
+ this.addWordInternal(word, def, uuid)
1001
1270
  }
1002
1271
 
1003
- addWordInternal (word, def) {
1272
+ addWordInternal (word, def, uuid) {
1004
1273
  if (!this.config.words) {
1005
1274
  this.config.words = {}
1006
1275
  }
1007
1276
  const words = this.config.words
1008
- def = Object.assign({}, def, { uuid: this._uuid })
1277
+ def = Object.assign({}, def, { uuid: uuid || this._uuid })
1009
1278
  if (words[word]) {
1010
1279
  if (!words[word].some((e) => helpers.safeEquals(e, def))) {
1011
1280
  words[word].unshift(def)
@@ -1226,33 +1495,7 @@ class Config {
1226
1495
  }
1227
1496
 
1228
1497
  if (config) {
1229
- const valid = [
1230
- 'hierarchy',
1231
- 'objects',
1232
- 'bridges',
1233
- 'operators',
1234
- 'words',
1235
- 'priorities',
1236
- 'associations',
1237
- 'name',
1238
- 'version',
1239
- 'generators',
1240
- 'semantics',
1241
- 'floaters',
1242
- 'debug',
1243
-
1244
- // TODO Fix these from the test app
1245
- 'implicits',
1246
- 'convolution',
1247
- 'expected_generated',
1248
- 'expected_results',
1249
- 'skipSemantics',
1250
- 'description',
1251
- 'contexts',
1252
- 'utterances',
1253
- 'flatten',
1254
- ]
1255
- helpers.validProps(valid, config, 'config')
1498
+ validConfigProps(config)
1256
1499
 
1257
1500
  config.operators = config.operators || []
1258
1501
  config.bridges = config.bridges || []
@@ -1262,6 +1505,7 @@ class Config {
1262
1505
  config.hierarchy = config.hierarchy || []
1263
1506
  config.associations = config.associations || { negative: [], positive: [] }
1264
1507
  config.priorities = config.priorities || []
1508
+ config.contextual_priorities = config.contextual_priorities || []
1265
1509
  }
1266
1510
 
1267
1511
  this.maxDepth = 20 // for generators and semantics
@@ -1315,6 +1559,10 @@ class Config {
1315
1559
  }
1316
1560
  }
1317
1561
 
1562
+ if (config && config.contextual_priorities) {
1563
+ contextual_priorities_valid(config.contextual_priorities)
1564
+ }
1565
+
1318
1566
  normalizeConfig(config)
1319
1567
 
1320
1568
  // set the default server so stuff just works
@@ -1330,7 +1578,6 @@ class Config {
1330
1578
  if (config) {
1331
1579
  this.name = config.name
1332
1580
  }
1333
- this.motivations = []
1334
1581
  this.loadOrder = new DigraphInternal()
1335
1582
  this.wasInitialized = false
1336
1583
  this.configs = []
@@ -1385,7 +1632,10 @@ class Config {
1385
1632
  }
1386
1633
 
1387
1634
  delta () {
1388
- return { cacheKey: this._delta.cacheKey, json: this._delta.json }
1635
+ return {
1636
+ cacheKey: this._delta.cacheKey,
1637
+ json: this._delta.json
1638
+ }
1389
1639
  }
1390
1640
 
1391
1641
  resetDelta (cacheKey) {
@@ -1397,6 +1647,7 @@ class Config {
1397
1647
  bridges: [],
1398
1648
  associations: [],
1399
1649
  priorities: [],
1650
+ contextual_priorities: [],
1400
1651
  hierarchy: [],
1401
1652
  }
1402
1653
  }
@@ -1431,11 +1682,13 @@ class Config {
1431
1682
  this._api.add(this, this._api, value)
1432
1683
  } else {
1433
1684
  this._api = _.cloneDeep(value)
1685
+ /*
1434
1686
  if (this._api) {
1435
- this._api.objects = this.config.objects
1436
- this._api.config = () => this
1437
- this._api.uuid = this._uuid
1687
+ // this._api.objects = this.config.objects
1688
+ // this._api.config = () => this
1689
+ // this._api.uuid = this._uuid
1438
1690
  }
1691
+ */
1439
1692
  this.rebuild()
1440
1693
  }
1441
1694
  }
@@ -1478,40 +1731,6 @@ class Config {
1478
1731
  // this.valid() init was not run because the kms are not all setup yet
1479
1732
  }
1480
1733
 
1481
- // motivation === { match, apply, uuid }
1482
- addMotivation (motivation) {
1483
- if (!motivation.uuid) {
1484
- motivation.uuid = this.uuid
1485
- }
1486
- this.motivations.push(motivation)
1487
- }
1488
-
1489
- resetMotivations () {
1490
- this.motivations = []
1491
- }
1492
-
1493
- doMotivations (args, context) {
1494
- args = Object.assign({}, args, { context, api: this.api })
1495
- // console.log('src/config doMotivations this.uuid', this.uuid)
1496
- // args.objects = args.getObjects(this.uuid)
1497
- const motivations = this.motivations
1498
- this.motivations = []
1499
- let done = false
1500
- for (const motivation of motivations) {
1501
- args.objects = args.getObjects(motivation.uuid)
1502
- if (!done && motivation.match(args)) {
1503
- motivation.apply(args)
1504
- if (args.context.controlKeepMotivation || motivation.repeat) {
1505
- this.motivations.push(motivation)
1506
- }
1507
- done = true
1508
- } else {
1509
- this.motivations.push(motivation)
1510
- }
1511
- }
1512
- return done
1513
- }
1514
-
1515
1734
  // TODO add more details
1516
1735
  equal(config) {
1517
1736
  if (JSON.stringify(this.config) != JSON.stringify(config.config)) {
@@ -1525,6 +1744,9 @@ class Config {
1525
1744
  runtime.fs.writeFileSync(fn, JSON.stringify(this.config, 0, 2))
1526
1745
  }
1527
1746
 
1747
+ copy (options = { callInitializers: true }) {
1748
+ }
1749
+
1528
1750
  copy (options = { callInitializers: true }) {
1529
1751
  this.valid()
1530
1752
  const cp = new Config()
@@ -1534,15 +1756,14 @@ class Config {
1534
1756
  cp.transitoryMode = this.transitoryMode
1535
1757
  cp.configs = this.configs.map((km) => km.copy2(Object.assign({}, options, { getCounter: (name) => cp.getCounter(name), callInitializers: false })))
1536
1758
  cp._uuid = cp.configs[0]._uuid
1759
+ // update uuid here set the uuid in the objects and add error checking
1537
1760
  cp.initializerFn = this.initializerFn
1538
- cp.initAfterApi = this.initAfterApi
1539
1761
  cp._api = _.cloneDeep(this._api)
1540
1762
  cp._namespace = this._namespace
1541
1763
  cp._eqClasses = this._eqClasses
1542
1764
  cp.name = this.name
1543
1765
  cp.description = this.description
1544
1766
  cp.tests = this.tests
1545
- cp.motivations = [...this.motivations]
1546
1767
  cp.isModule = this.isModule
1547
1768
  cp.loadedForTesting = this.loadedForTesting
1548
1769
  cp.initInstances = this.initInstances.slice()
@@ -1567,25 +1788,38 @@ class Config {
1567
1788
  }
1568
1789
  cp.mapUUIDs(map)
1569
1790
 
1791
+ if (cp._uuid == 'concept2') {
1792
+ // debugger
1793
+ }
1570
1794
  if (options.callInitializers) {
1571
1795
  cp.rebuild(options)
1572
- }
1573
- if (cp._api) {
1574
- cp._api.objects = cp.config.objects
1575
- cp._api.config = () => (cp instanceof Config) ? cp : cp.config
1576
- cp._api.uuid = cp._uuid
1577
- }
1796
+ } else {
1797
+ // this mess is for duplicate into a KM after resetToOne was called
1798
+ /*
1799
+ if (cp._api) {
1800
+ // cp._api.objects = cp.config.objects
1801
+ // cp._api.config = () => (cp instanceof Config) ? cp : cp.config
1802
+ // cp._api.uuid = cp._uuid
1803
+ }
1804
+ */
1578
1805
 
1579
- if (!cp.config.objects) {
1580
- cp.config.objects = { namespaced: {} }
1581
- } else if (!cp.config.objects.namespaced) {
1582
- cp.config.objects.namespaced = {}
1806
+ if (!cp.config.objects) {
1807
+ cp.config.objects = { namespaced: {} }
1808
+ } else if (!cp.config.objects.namespaced) {
1809
+ cp.config.objects.namespaced = {}
1810
+ }
1811
+ cp.configs.forEach((km) => {
1812
+ // const namespace = km.namespace
1813
+ cp.config.objects.namespaced[km._uuid] = {}
1814
+ })
1815
+ /*
1816
+ if (cp._uuid == 'concept2') {
1817
+ if (!cp.api.objects.defaultTypesForHierarchy) {
1818
+ debugger
1819
+ }
1820
+ }
1821
+ */
1583
1822
  }
1584
- cp.configs.forEach((km) => {
1585
- // const namespace = km.namespace
1586
- cp.config.objects.namespaced[km._uuid] = {}
1587
- })
1588
-
1589
1823
  cp.valid()
1590
1824
  return cp
1591
1825
  }
@@ -1685,38 +1919,33 @@ class Config {
1685
1919
  }
1686
1920
  */
1687
1921
  const objects = {}
1688
- const km = (name) => this.getConfig(name)
1689
1922
  if (config instanceof Config) {
1690
- // const aw = addWord(this.config, config.uuid)
1691
- const aw = (word, def) => this.addWord(word, def)
1692
1923
  this.get('objects').namespaced[config._uuid] = objects
1924
+ /*
1693
1925
  if (config._api) {
1694
- config._api.objects = objects
1695
- config._api.config = () => this
1926
+ // config._api.objects = objects
1927
+ // config._api.config = () => this
1696
1928
  }
1697
- config.initializerFn({ addWord: aw, km, config, baseConfig: this, currentConfig: config, objects, namespace, uuid, api: config.api })
1929
+ */
1930
+ config.initializerFn(setupInitializerFNArgs(this, { testConfig: config, currentConfig: config, objects, namespace, uuid }))
1698
1931
  } else {
1699
- // const aw = addWord(this.config, this.uuid)
1700
- const aw = (word, def) => this.addWord(word, def)
1701
1932
  this.get('objects').namespaced[this._uuid] = objects
1933
+ /*
1702
1934
  if (config._api) {
1703
- config._api.objects = objects
1704
- config._api.config = () => this
1935
+ // config._api.objects = objects
1936
+ // config._api.config = () => this
1705
1937
  }
1706
- this.initializerFn({ addWord: aw, km, config: this, baseConfig: this, currentConfig: this, objects, namespace, uuid, api: this.api })
1938
+ */
1939
+ this.initializerFn(setupInitializerFNArgs(this, { testConfig: this, currentConfig: this, objects, namespace, uuid }))
1707
1940
  }
1708
1941
  })
1709
- this.instances.forEach((instance) => client.processInstance(this, instance))
1942
+ this.instances.forEach((instance) => client.loadInstance(this, instance))
1710
1943
  }
1711
1944
 
1712
1945
  initialize ({ force = true } = {}) {
1713
1946
  if (force || !this.wasInitialized) {
1714
- // const aw = addWord(this.config, this.uuid)
1715
- const aw = (word, def) => this.addWord(word, def)
1716
- const km = (name) => this.getConfig(name)
1717
- // this.initializerFn({ addWord: aw, km, config: this, baseConfig: this, currentConfig: this, objects: this.get('objects'), uuid: this._uuid, namespace: '', api: this.api })
1718
1947
  const objects = this.config.objects.namespaced[this._uuid]
1719
- this.initializerFn({ addWord: aw, km, config: this, baseConfig: this, currentConfig: this, objects, uuid: this._uuid, namespace: '', api: this.api })
1948
+ this.initializerFn(setupInitializerFNArgs(this, { testConfig: this, currentConfig: this, objects, uuid: this._uuid, namespace: '' }))
1720
1949
  this.wasInitialized = true
1721
1950
  }
1722
1951
  }
@@ -1724,29 +1953,22 @@ class Config {
1724
1953
  initializer (fn, options = {}) {
1725
1954
  if (options) {
1726
1955
  for (let option of Object.keys(options)) {
1727
- const validOptions = ['initAfterApi']
1728
- if (!['initAfterApi'].includes(option)) {
1956
+ const validOptions = []
1957
+ if (!validOptions.includes(option)) {
1729
1958
  throw new Error(`For Config.initializer, unrecognized option ${option}. The valid options are ${validOptions}`)
1730
1959
  }
1731
1960
  }
1732
1961
  }
1733
- const { initAfterApi = false } = options;
1734
1962
  this.wasInitialized = false
1735
- this.initAfterApi = initAfterApi
1736
- this.initializerFn = (args) => {
1963
+ this.initializerFn = (args, { dontCallFn } = {}) => {
1737
1964
  const transitoryMode = global.transitoryMode
1738
1965
  global.transitoryMode = false
1739
1966
  // const baseConfig = args.baseConfig
1740
1967
  const currentConfig = args.currentConfig
1741
1968
 
1742
- if (currentConfig.api) {
1743
- currentConfig.api.objects = args.objects
1744
- // GREG42 currentConfig.api.config = () => this
1745
- currentConfig.api.config = () => args.baseConfig
1746
- currentConfig.api.uuid = currentConfig._uuid
1969
+ if (args.isAfterApi) {
1970
+ fn(args)
1747
1971
  }
1748
- // this.instances.forEach( (instance) => client.processInstance(this, instance) )
1749
- fn(args)
1750
1972
  currentConfig.wasInitialized = true
1751
1973
  global.transitoryMode = transitoryMode
1752
1974
  }
@@ -1913,7 +2135,6 @@ class Config {
1913
2135
  }
1914
2136
  this.config.objects.namespaced = {}
1915
2137
  this.resetWasInitialized()
1916
- this.resetMotivations()
1917
2138
 
1918
2139
  // reorder configs base on load ordering
1919
2140
  {
@@ -1939,8 +2160,8 @@ class Config {
1939
2160
  this.config.objects.namespaced[km._uuid] = {}
1940
2161
  const namespacedObjects = this.config.objects.namespaced[km._uuid]
1941
2162
  this.setupNamespace(km)
1942
- // const aw = addWord(km.config.config ? km.config.config : km.config, km.config.uuid)
1943
- const aw = (word, def) => this.addWord(word, def)
2163
+ // const aw = (word, def) => this.addWord(word, def)
2164
+ // const ag = (matchOrGenerator, applyOrNothing) => this.addGenerator(matchOrGenerator, applyOrNothing)
1944
2165
  let config = km.config
1945
2166
 
1946
2167
  if (config.addedArgss) {
@@ -1961,45 +2182,51 @@ class Config {
1961
2182
  }
1962
2183
  config.wasInitialized = false
1963
2184
  // TODO change name of config: to baseConfig:
1964
- const kmFn = (name) => this.getConfig(name)
2185
+ const kmFn = (name) => {
2186
+ const config = this.getConfig(name)
2187
+ return config
2188
+ }
1965
2189
  // const hierarchy = new DigraphInternal((config.config || {}).hierarchy)
1966
- const args = {
2190
+ const args = new Object(setupInitializerFNArgs(this, {
1967
2191
  isModule,
1968
- addWord: aw,
1969
- km: kmFn,
1970
2192
  hierarchy: this.hierarchy,
1971
- config,
1972
- baseConfig: this,
2193
+ testConfig: config,
1973
2194
  currentConfig: config,
1974
2195
  uuid: config._uuid,
1975
2196
  objects: namespacedObjects,
1976
2197
  namespace,
1977
- motivation: (m) => config.addMotivation(m),
1978
- api: config.api
2198
+ api: config.api,
2199
+ }))
2200
+
2201
+ const currentConfig = args.currentConfig
2202
+
2203
+ /*
2204
+ if (args.currentConfig.api) {
2205
+ // args.currentConfig.api.objects = args.objects
2206
+ // TODO assign pseudo config?
2207
+ // args.currentConfig.api.config = () => args.baseConfig
2208
+ // args.currentConfig.api.uuid = args.currentConfig._uuid
2209
+ args.currentConfig.wasInitialized = true
1979
2210
  }
1980
- config.initializerFn(args)
1981
- if (config.initAfterApi) {
1982
- // reverse the list
2211
+ */
2212
+ // debugger
2213
+ // greg55
2214
+ config.initializerFn(args, { dontCallFn: true })
1983
2215
  initAfterApis.unshift({ config, args })
1984
- } else {
1985
- if (interleaved) {
1986
- initAfterApis.unshift(null)
1987
- }
1988
- }
1989
- // greg
1990
2216
  if (config._api) {
1991
2217
  if (config._api.initialize) {
1992
2218
  // reverse the list
1993
- inits.unshift( () => config._api.initialize({ config: this, km: kmFn, api: config._api }) )
2219
+ // TODO sync up the args with initialize of config
2220
+ inits.unshift( () => config._api.initialize({ config: this, km: kmFn, ...args, api: config._api }) )
1994
2221
  // config._api.initialize({ config, api: config._api })
1995
2222
  } else {
1996
2223
  if (interleaved) {
1997
2224
  inits.unshift(null)
1998
2225
  }
1999
2226
  }
2000
- config._api.objects = namespacedObjects
2001
- config._api.config = () => this
2002
- config._api.uuid = config._uuid
2227
+ // config._api.objects = namespacedObjects
2228
+ // config._api.config = () => this
2229
+ // config._api.uuid = config._uuid
2003
2230
  } else {
2004
2231
  if (interleaved) {
2005
2232
  inits.unshift(null)
@@ -2041,16 +2268,16 @@ class Config {
2041
2268
  init()
2042
2269
  }
2043
2270
  for (let init of initAfterApis) {
2044
- // init.args.isAfterApi = true
2045
2271
  init.config.initializerFn({ ...init.args, kms: this.getConfigs(), isAfterApi: true })
2046
2272
  }
2047
- this.instances.forEach((instance) => client.processInstance(this, instance))
2273
+ this.instances.forEach((instance) => client.loadInstance(this, instance))
2048
2274
  } else {
2049
2275
  const base = {
2050
2276
  operators: this.config.operators,
2051
2277
  bridges: this.config.bridges,
2052
2278
  hierarchy: this.config.hierarchy,
2053
2279
  priorities: this.config.priorities,
2280
+ contextual_priorities: this.config.contextual_priorities,
2054
2281
  associations: this.config.associations,
2055
2282
  words: this.config.words
2056
2283
  }
@@ -2059,6 +2286,7 @@ class Config {
2059
2286
  this.config.bridges = []
2060
2287
  this.config.hierarchy = []
2061
2288
  this.config.priorities = []
2289
+ this.config.contextual_priorities = []
2062
2290
  this.config.associations = { positive: [], negative: [] }
2063
2291
  this.config.words = {}
2064
2292
 
@@ -2073,19 +2301,19 @@ class Config {
2073
2301
  }
2074
2302
  // console.log('name -------------', name)
2075
2303
  if (inits[i]) {
2304
+ // greg55
2076
2305
  inits[i]()
2077
2306
  }
2078
2307
  if (initAfterApis[i]) {
2079
2308
  const init = initAfterApis[i]
2080
- init.config.initializerFn({ ...init.args, kms: this.getConfigs(), isAfterApi: true })
2309
+ init.config.initializerFn({ ...init.args, kms: this.getConfigs(), isAfterApi: true})
2081
2310
  }
2082
2311
  const instance = this.instances.find((instance) => instance.name == name)
2083
2312
  if (instance) {
2084
- client.processInstance(this, instance)
2313
+ client.loadInstance(this, instance)
2085
2314
  }
2086
2315
  this.hierarchy.edges = this.config.hierarchy
2087
2316
  }
2088
- // this.instances.forEach((instance) => client.processInstance(this, instance))
2089
2317
  }
2090
2318
 
2091
2319
  if (reverseIt) {
@@ -2208,13 +2436,9 @@ class Config {
2208
2436
  }
2209
2437
  const km = (name) => this.getConfig(name)
2210
2438
  if (config instanceof Config) {
2211
- // const aw = addWord(this.config, config.uuid)
2212
- const aw = (word, def) => this.addWord(word, def)
2213
- config.initializerFn({ isModule: this.isModule, addWord: aw, baseConfig: this, km, currentConfig: config, config, objects: nsobjects, namespace, uuid, api: config.api })
2439
+ config.initializerFn(setupInitializerFNArgs(this, { isModule: this.isModule, currentConfig: config, testConfig: config, objects: nsobjects, namespace, uuid }))
2214
2440
  } else {
2215
- // const aw = addWord(this.config, this.uuid)
2216
- const aw = (word, def) => this.addWord(word, def)
2217
- this.initializerFn({ isModule: this.isModule, addWord: aw, baseConfig: this, km, currentConfig: this, config: this, objects: nsobjects, namespace, uuid, api: this.api })
2441
+ this.initializerFn(setupInitializerFNArgs(this, { isModule: this.isModule, currentConfig: this, testConfig: this, objects: nsobjects, namespace, uuid }))
2218
2442
  }
2219
2443
  })
2220
2444
  }
@@ -2279,6 +2503,20 @@ class Config {
2279
2503
  config.priorities = priorities
2280
2504
  }
2281
2505
 
2506
+ if (config.contextual_priorities) {
2507
+ let contextual_priorities = config.contextual_priorities
2508
+ contextual_priorities = contextual_priorities.map((cp) => {
2509
+ const { context, choose } = cp
2510
+ return {
2511
+ context: context.map((id) => {
2512
+ return [toNS(id[0]), id[1]]
2513
+ }),
2514
+ choose
2515
+ }
2516
+ })
2517
+ config.contextual_priorities = contextual_priorities
2518
+ }
2519
+
2282
2520
  for (const bag of bags) {
2283
2521
  if (config[bag]) {
2284
2522
  config[bag] = config[bag].map((b) => {
@@ -2473,7 +2711,8 @@ class Config {
2473
2711
  }
2474
2712
 
2475
2713
  // TODO get rid of useOldVersion arg
2476
- addInternal (more, { useOldVersion = true, skipObjects = false, includeNamespaces = true, allowNameToBeNull = false, handleCalculatedProps : hcps = false } = {}) {
2714
+ addInternal (more, { addFirst = false, useOldVersion = true, skipObjects = false, includeNamespaces = true, allowNameToBeNull = false, handleCalculatedProps : hcps = false } = {}) {
2715
+ validConfigProps(more)
2477
2716
  if (more instanceof Config) {
2478
2717
  more.initialize({ force: false })
2479
2718
  if (useOldVersion) {
@@ -2484,7 +2723,7 @@ class Config {
2484
2723
  }
2485
2724
  }
2486
2725
  if (hcps) {
2487
- handleCalculatedProps(this, more)
2726
+ handleCalculatedProps(this, more, addFirst)
2488
2727
  applyUUID(more, this._uuid)
2489
2728
  }
2490
2729
  for (const key of Object.keys(more)) {
@@ -2509,7 +2748,11 @@ class Config {
2509
2748
  if (!configWords[word]) {
2510
2749
  configWords[word] = []
2511
2750
  }
2512
- configWords[word] = configWords[word].concat(moreWords[word])
2751
+ if (addFirst) {
2752
+ configWords[word] = moreWords[word].concat(configWords[word])
2753
+ } else {
2754
+ configWords[word] = configWords[word].concat(moreWords[word])
2755
+ }
2513
2756
  }
2514
2757
  } else if (key === 'name') {
2515
2758
  /*
@@ -2571,13 +2814,17 @@ class Config {
2571
2814
  this.config[key].splice(iOldOne, 1)
2572
2815
  break;
2573
2816
  }
2574
- }
2817
+ }
2575
2818
  }
2576
2819
  }
2577
2820
  }
2578
2821
  // console.log('key', key, 'XXX')
2579
2822
  // console.log('more', JSON.stringify(more, null, 2))
2580
- this.config[key] = this.config[key].concat(more[key])
2823
+ if (addFirst) {
2824
+ this.config[key] = more[key].concat(this.config[key])
2825
+ } else {
2826
+ this.config[key] = this.config[key].concat(more[key])
2827
+ }
2581
2828
  } else {
2582
2829
  if (!(key in this.config)) {
2583
2830
  throw new Error(`Unexpected property in config ${key}`)
@@ -2708,5 +2955,8 @@ class Config {
2708
2955
  }
2709
2956
 
2710
2957
  module.exports = {
2711
- Config
2958
+ Config,
2959
+ config_toServer,
2960
+ operatorKey_valid,
2961
+ handleBridgeProps,
2712
2962
  }