theprogrammablemind 7.5.8-beta.5 → 7.5.8-beta.51

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',
@@ -723,7 +933,39 @@ class Config {
723
933
  const instanceFragments = (instance.fragments || []).map((fragment) => fragment.key || fragment.query).map( toCanonical )
724
934
  const templateFragments = (template.fragments || []).concat(this.dynamicFragments).map( toCanonical )
725
935
  const sameFragments = helpers.safeEquals(templateFragments, instanceFragments)
726
- const sameQueries = helpers.safeEquals((template.queries || []).map(helpers.updateQueries), (instance.queries || []))
936
+ const toCanonicalQuery = (queryOrConfig) => {
937
+ if (typeof queryOrConfig == 'string') {
938
+ const query = queryOrConfig
939
+ return query
940
+ } else {
941
+ const config = { ...queryOrConfig }
942
+ delete config.where
943
+ config.generators = (config.generators || []).map((generator) => {
944
+ generator = {...generator}
945
+ delete generator.where
946
+ generator.match = generator.match.toString()
947
+ generator.apply = generator.apply.toString()
948
+ return generator
949
+ })
950
+ config.semantics = (config.semantics || []).map((semantic) => {
951
+ semantic = {...semantic}
952
+ delete semantic.where
953
+ semantic.match = semantic.match.toString()
954
+ semantic.apply = semantic.apply.toString()
955
+ return semantic
956
+ })
957
+ return config
958
+ }
959
+ }
960
+ const toCanonicalQueries = (elements) => {
961
+ return elements.map( toCanonicalQuery )
962
+ }
963
+
964
+ const sameQueries = helpers.safeEquals(toCanonicalQueries(template.queries || []).map(helpers.updateQueries), toCanonicalQueries(instance.queries || []))
965
+ // greg99
966
+ console.log("sameQueries", sameQueries)
967
+ console.log('template.queries', toCanonicalQueries(template.queries || []).map(helpers.updateQueries))
968
+ console.log('instance.queries', toCanonicalQueries(instance.queries || []))
727
969
  return !(instance && sameQueries && sameFragments)
728
970
  }
729
971
 
@@ -739,6 +981,12 @@ class Config {
739
981
  }
740
982
  }
741
983
 
984
+ toData (data) {
985
+ Object.assign(data, this.config)
986
+ config_toServer(data)
987
+ }
988
+
989
+ // loadTemplate
742
990
  load (template, instance, options = { rebuild: false } ) {
743
991
  this.validifyTemplate(template)
744
992
  instance.template = template
@@ -750,7 +998,7 @@ class Config {
750
998
  // TODO fix beforeQuery
751
999
  template = { fragments: [], queries: [], ...template }
752
1000
  template.fragments = template.fragments.concat(this.dynamicFragments)
753
- client.build({ config: this, target: this.name, beforeQuery: () => {}, template, ...options })
1001
+ client.rebuildTemplate({ config: this, target: this.name, beforeQuery: () => {}, template, ...options })
754
1002
  } else {
755
1003
  // no change
756
1004
  // this.initInstances.push({ ...instance, name: config.name })
@@ -768,7 +1016,7 @@ class Config {
768
1016
  instance.name = this.name
769
1017
  this.initInstances.push(instance)
770
1018
  this.instances.push(instance)
771
- client.processInstance(this, instance)
1019
+ client.loadInstance(this, instance)
772
1020
  }
773
1021
  }
774
1022
  }
@@ -825,6 +1073,22 @@ class Config {
825
1073
  this._delta.json.priorities.push({ action: 'add', priorities })
826
1074
  }
827
1075
 
1076
+ // [ operators: <list of [id, level]>, select: <index of prioritized operator> ]
1077
+ addContextualPriority(contextual_priority) {
1078
+ if (!this.config.contextual_priorities) {
1079
+ this.config.contextual_priorities = []
1080
+ }
1081
+ if (global.entodictonDebugContextualPriority) {
1082
+ if (helpers.safeEquals(entodictonDebugContextualPriority, contextual_priorities)) {
1083
+ debugger; // debug hierarchy hit
1084
+ }
1085
+ }
1086
+ contextual_priority_valid(contextual_priority)
1087
+ this.config.contextual_priorities.push(contextual_priority)
1088
+ const cpServer = contextual_priorities_toServer(contextual_priority)
1089
+ this._delta.json.contextual_priorities.push({ action: 'add', contextual_priority: cpServer })
1090
+ }
1091
+
828
1092
  addHierarchy (child, parent) {
829
1093
  if (child && parent || !child || Array.isArray(child) || (typeof child == 'string' && !parent)) {
830
1094
  this.addHierarchyChildParent(child, parent)
@@ -881,15 +1145,19 @@ class Config {
881
1145
  }
882
1146
 
883
1147
  getBridge (id, level) {
884
- return this.config.bridges.find( (bridge) => bridge.id == id && bridge.level == level )
1148
+ if (level) {
1149
+ return this.config.bridges.find( (bridge) => bridge.id == id && bridge.level == level )
1150
+ } else {
1151
+ return this.config.bridges.find( (bridge) => bridge.id == id)
1152
+ }
885
1153
  }
886
1154
 
887
- addBridge (bridge) {
1155
+ addBridge (bridge, uuid) {
888
1156
  if (!this.config.bridges) {
889
1157
  this.config.bridges = []
890
1158
  }
891
1159
  const bridges = this.config.bridges
892
- const def = Object.assign({}, bridge, { uuid: this._uuid })
1160
+ const def = Object.assign({}, bridge, { uuid: uuid || this._uuid })
893
1161
 
894
1162
  if (global.entodictonDebugBridge) {
895
1163
  if (global.entodictonDebugBridge[0] == bridge.id && global.entodictonDebugBridge[1] == bridge.level) {
@@ -911,12 +1179,7 @@ class Config {
911
1179
  this._delta.json.bridges.push({ action: 'add', bridge: def })
912
1180
  }
913
1181
 
914
- addGenerator (match, apply) {
915
- let generator = match
916
- if ((typeof match === 'function') && (typeof apply === 'function')) {
917
- generator = { match, apply }
918
- }
919
-
1182
+ addGenerator (generator, uuid, name) {
920
1183
  if (!(typeof generator.match === 'function')) {
921
1184
  throw new Error('addGenerator: Expected matcher to be a function')
922
1185
  }
@@ -933,20 +1196,16 @@ class Config {
933
1196
  }
934
1197
 
935
1198
  const generators = this.config.generators
936
- Object.assign(generator, { uuid: this._uuid, km: this.name, index: generators.length })
1199
+ Object.assign(generator, { uuid: uuid || this._uuid, km: name || this.name, index: generators.length })
937
1200
  // used to be unshift
938
1201
  generators.unshift(generator)
939
1202
  }
940
1203
 
941
- addSemantic (match, apply) {
942
- let semantic = match
943
- if ((typeof match === 'function') && (typeof apply === 'function')) {
944
- semantic = { match, apply }
945
- }
946
-
1204
+ addSemantic (semantic, uuid, name) {
947
1205
  if (!(typeof semantic.match === 'function')) {
948
1206
  throw new Error('addSemantic: Expected match to be a function')
949
1207
  }
1208
+
950
1209
  if (!(typeof semantic.apply === 'function')) {
951
1210
  throw new Error('addSemantic: Expected apply to be a function')
952
1211
  }
@@ -960,11 +1219,18 @@ class Config {
960
1219
  }
961
1220
 
962
1221
  const semantics = this.config.semantics
963
- Object.assign(semantic, { uuid: this._uuid, km: this.name, index: semantics.length })
1222
+ Object.assign(semantic, { uuid: uuid || semantic.uuid || this._uuid, km: name || this.name, index: semantics.length, id: semantic.id || uuidv4() })
964
1223
  semantics.unshift(semantic)
965
1224
  }
966
1225
 
967
- addOperator (objectOrPattern) {
1226
+ removeSemantic(deleteSemantic) {
1227
+ const index = this.config.semantics.findIndex( (semantic) => semantic.id === deleteSemantic.id )
1228
+ if (index >= 0) {
1229
+ this.config.semantics.splice(index, 1)
1230
+ }
1231
+ }
1232
+
1233
+ addOperator (objectOrPattern, uuid) {
968
1234
  if (!this.config.operators) {
969
1235
  this.config.operators = []
970
1236
  }
@@ -973,9 +1239,9 @@ class Config {
973
1239
 
974
1240
  let operator;
975
1241
  if (typeof objectOrPattern === 'string') {
976
- operator = { pattern: objectOrPattern, uuid: this._uuid }
1242
+ operator = { pattern: objectOrPattern, uuid: uuid || this._uuid }
977
1243
  } else {
978
- operator = Object.assign({}, objectOrPattern, { uuid: this._uuid })
1244
+ operator = Object.assign({}, objectOrPattern, { uuid: uuid || this._uuid })
979
1245
  }
980
1246
 
981
1247
  if (global.entodictonDebugOperator) {
@@ -996,16 +1262,16 @@ class Config {
996
1262
  this._delta.json.operators.push({ action: 'add', operator })
997
1263
  }
998
1264
 
999
- addWord (word, def) {
1000
- this.addWordInternal(word, def)
1265
+ addWord (word, def, uuid) {
1266
+ this.addWordInternal(word, def, uuid)
1001
1267
  }
1002
1268
 
1003
- addWordInternal (word, def) {
1269
+ addWordInternal (word, def, uuid) {
1004
1270
  if (!this.config.words) {
1005
1271
  this.config.words = {}
1006
1272
  }
1007
1273
  const words = this.config.words
1008
- def = Object.assign({}, def, { uuid: this._uuid })
1274
+ def = Object.assign({}, def, { uuid: uuid || this._uuid })
1009
1275
  if (words[word]) {
1010
1276
  if (!words[word].some((e) => helpers.safeEquals(e, def))) {
1011
1277
  words[word].unshift(def)
@@ -1226,33 +1492,7 @@ class Config {
1226
1492
  }
1227
1493
 
1228
1494
  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')
1495
+ validConfigProps(config)
1256
1496
 
1257
1497
  config.operators = config.operators || []
1258
1498
  config.bridges = config.bridges || []
@@ -1262,6 +1502,7 @@ class Config {
1262
1502
  config.hierarchy = config.hierarchy || []
1263
1503
  config.associations = config.associations || { negative: [], positive: [] }
1264
1504
  config.priorities = config.priorities || []
1505
+ config.contextual_priorities = config.contextual_priorities || []
1265
1506
  }
1266
1507
 
1267
1508
  this.maxDepth = 20 // for generators and semantics
@@ -1315,6 +1556,10 @@ class Config {
1315
1556
  }
1316
1557
  }
1317
1558
 
1559
+ if (config && config.contextual_priorities) {
1560
+ contextual_priorities_valid(config.contextual_priorities)
1561
+ }
1562
+
1318
1563
  normalizeConfig(config)
1319
1564
 
1320
1565
  // set the default server so stuff just works
@@ -1330,7 +1575,6 @@ class Config {
1330
1575
  if (config) {
1331
1576
  this.name = config.name
1332
1577
  }
1333
- this.motivations = []
1334
1578
  this.loadOrder = new DigraphInternal()
1335
1579
  this.wasInitialized = false
1336
1580
  this.configs = []
@@ -1385,7 +1629,10 @@ class Config {
1385
1629
  }
1386
1630
 
1387
1631
  delta () {
1388
- return { cacheKey: this._delta.cacheKey, json: this._delta.json }
1632
+ return {
1633
+ cacheKey: this._delta.cacheKey,
1634
+ json: this._delta.json
1635
+ }
1389
1636
  }
1390
1637
 
1391
1638
  resetDelta (cacheKey) {
@@ -1397,6 +1644,7 @@ class Config {
1397
1644
  bridges: [],
1398
1645
  associations: [],
1399
1646
  priorities: [],
1647
+ contextual_priorities: [],
1400
1648
  hierarchy: [],
1401
1649
  }
1402
1650
  }
@@ -1431,11 +1679,13 @@ class Config {
1431
1679
  this._api.add(this, this._api, value)
1432
1680
  } else {
1433
1681
  this._api = _.cloneDeep(value)
1682
+ /*
1434
1683
  if (this._api) {
1435
- this._api.objects = this.config.objects
1436
- this._api.config = () => this
1437
- this._api.uuid = this._uuid
1684
+ // this._api.objects = this.config.objects
1685
+ // this._api.config = () => this
1686
+ // this._api.uuid = this._uuid
1438
1687
  }
1688
+ */
1439
1689
  this.rebuild()
1440
1690
  }
1441
1691
  }
@@ -1478,40 +1728,6 @@ class Config {
1478
1728
  // this.valid() init was not run because the kms are not all setup yet
1479
1729
  }
1480
1730
 
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
1731
  // TODO add more details
1516
1732
  equal(config) {
1517
1733
  if (JSON.stringify(this.config) != JSON.stringify(config.config)) {
@@ -1525,6 +1741,9 @@ class Config {
1525
1741
  runtime.fs.writeFileSync(fn, JSON.stringify(this.config, 0, 2))
1526
1742
  }
1527
1743
 
1744
+ copy (options = { callInitializers: true }) {
1745
+ }
1746
+
1528
1747
  copy (options = { callInitializers: true }) {
1529
1748
  this.valid()
1530
1749
  const cp = new Config()
@@ -1534,15 +1753,14 @@ class Config {
1534
1753
  cp.transitoryMode = this.transitoryMode
1535
1754
  cp.configs = this.configs.map((km) => km.copy2(Object.assign({}, options, { getCounter: (name) => cp.getCounter(name), callInitializers: false })))
1536
1755
  cp._uuid = cp.configs[0]._uuid
1756
+ // update uuid here set the uuid in the objects and add error checking
1537
1757
  cp.initializerFn = this.initializerFn
1538
- cp.initAfterApi = this.initAfterApi
1539
1758
  cp._api = _.cloneDeep(this._api)
1540
1759
  cp._namespace = this._namespace
1541
1760
  cp._eqClasses = this._eqClasses
1542
1761
  cp.name = this.name
1543
1762
  cp.description = this.description
1544
1763
  cp.tests = this.tests
1545
- cp.motivations = [...this.motivations]
1546
1764
  cp.isModule = this.isModule
1547
1765
  cp.loadedForTesting = this.loadedForTesting
1548
1766
  cp.initInstances = this.initInstances.slice()
@@ -1567,25 +1785,38 @@ class Config {
1567
1785
  }
1568
1786
  cp.mapUUIDs(map)
1569
1787
 
1788
+ if (cp._uuid == 'concept2') {
1789
+ // debugger
1790
+ }
1570
1791
  if (options.callInitializers) {
1571
1792
  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
- }
1793
+ } else {
1794
+ // this mess is for duplicate into a KM after resetToOne was called
1795
+ /*
1796
+ if (cp._api) {
1797
+ // cp._api.objects = cp.config.objects
1798
+ // cp._api.config = () => (cp instanceof Config) ? cp : cp.config
1799
+ // cp._api.uuid = cp._uuid
1800
+ }
1801
+ */
1578
1802
 
1579
- if (!cp.config.objects) {
1580
- cp.config.objects = { namespaced: {} }
1581
- } else if (!cp.config.objects.namespaced) {
1582
- cp.config.objects.namespaced = {}
1803
+ if (!cp.config.objects) {
1804
+ cp.config.objects = { namespaced: {} }
1805
+ } else if (!cp.config.objects.namespaced) {
1806
+ cp.config.objects.namespaced = {}
1807
+ }
1808
+ cp.configs.forEach((km) => {
1809
+ // const namespace = km.namespace
1810
+ cp.config.objects.namespaced[km._uuid] = {}
1811
+ })
1812
+ /*
1813
+ if (cp._uuid == 'concept2') {
1814
+ if (!cp.api.objects.defaultTypesForHierarchy) {
1815
+ debugger
1816
+ }
1817
+ }
1818
+ */
1583
1819
  }
1584
- cp.configs.forEach((km) => {
1585
- // const namespace = km.namespace
1586
- cp.config.objects.namespaced[km._uuid] = {}
1587
- })
1588
-
1589
1820
  cp.valid()
1590
1821
  return cp
1591
1822
  }
@@ -1685,38 +1916,33 @@ class Config {
1685
1916
  }
1686
1917
  */
1687
1918
  const objects = {}
1688
- const km = (name) => this.getConfig(name)
1689
1919
  if (config instanceof Config) {
1690
- // const aw = addWord(this.config, config.uuid)
1691
- const aw = (word, def) => this.addWord(word, def)
1692
1920
  this.get('objects').namespaced[config._uuid] = objects
1921
+ /*
1693
1922
  if (config._api) {
1694
- config._api.objects = objects
1695
- config._api.config = () => this
1923
+ // config._api.objects = objects
1924
+ // config._api.config = () => this
1696
1925
  }
1697
- config.initializerFn({ addWord: aw, km, config, baseConfig: this, currentConfig: config, objects, namespace, uuid, api: config.api })
1926
+ */
1927
+ config.initializerFn(setupInitializerFNArgs(this, { testConfig: config, currentConfig: config, objects, namespace, uuid }))
1698
1928
  } else {
1699
- // const aw = addWord(this.config, this.uuid)
1700
- const aw = (word, def) => this.addWord(word, def)
1701
1929
  this.get('objects').namespaced[this._uuid] = objects
1930
+ /*
1702
1931
  if (config._api) {
1703
- config._api.objects = objects
1704
- config._api.config = () => this
1932
+ // config._api.objects = objects
1933
+ // config._api.config = () => this
1705
1934
  }
1706
- this.initializerFn({ addWord: aw, km, config: this, baseConfig: this, currentConfig: this, objects, namespace, uuid, api: this.api })
1935
+ */
1936
+ this.initializerFn(setupInitializerFNArgs(this, { testConfig: this, currentConfig: this, objects, namespace, uuid }))
1707
1937
  }
1708
1938
  })
1709
- this.instances.forEach((instance) => client.processInstance(this, instance))
1939
+ this.instances.forEach((instance) => client.loadInstance(this, instance))
1710
1940
  }
1711
1941
 
1712
1942
  initialize ({ force = true } = {}) {
1713
1943
  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
1944
  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 })
1945
+ this.initializerFn(setupInitializerFNArgs(this, { testConfig: this, currentConfig: this, objects, uuid: this._uuid, namespace: '' }))
1720
1946
  this.wasInitialized = true
1721
1947
  }
1722
1948
  }
@@ -1724,29 +1950,22 @@ class Config {
1724
1950
  initializer (fn, options = {}) {
1725
1951
  if (options) {
1726
1952
  for (let option of Object.keys(options)) {
1727
- const validOptions = ['initAfterApi']
1728
- if (!['initAfterApi'].includes(option)) {
1953
+ const validOptions = []
1954
+ if (!validOptions.includes(option)) {
1729
1955
  throw new Error(`For Config.initializer, unrecognized option ${option}. The valid options are ${validOptions}`)
1730
1956
  }
1731
1957
  }
1732
1958
  }
1733
- const { initAfterApi = false } = options;
1734
1959
  this.wasInitialized = false
1735
- this.initAfterApi = initAfterApi
1736
- this.initializerFn = (args) => {
1960
+ this.initializerFn = (args, { dontCallFn } = {}) => {
1737
1961
  const transitoryMode = global.transitoryMode
1738
1962
  global.transitoryMode = false
1739
1963
  // const baseConfig = args.baseConfig
1740
1964
  const currentConfig = args.currentConfig
1741
1965
 
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
1966
+ if (args.isAfterApi) {
1967
+ fn(args)
1747
1968
  }
1748
- // this.instances.forEach( (instance) => client.processInstance(this, instance) )
1749
- fn(args)
1750
1969
  currentConfig.wasInitialized = true
1751
1970
  global.transitoryMode = transitoryMode
1752
1971
  }
@@ -1913,7 +2132,6 @@ class Config {
1913
2132
  }
1914
2133
  this.config.objects.namespaced = {}
1915
2134
  this.resetWasInitialized()
1916
- this.resetMotivations()
1917
2135
 
1918
2136
  // reorder configs base on load ordering
1919
2137
  {
@@ -1939,8 +2157,8 @@ class Config {
1939
2157
  this.config.objects.namespaced[km._uuid] = {}
1940
2158
  const namespacedObjects = this.config.objects.namespaced[km._uuid]
1941
2159
  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)
2160
+ // const aw = (word, def) => this.addWord(word, def)
2161
+ // const ag = (matchOrGenerator, applyOrNothing) => this.addGenerator(matchOrGenerator, applyOrNothing)
1944
2162
  let config = km.config
1945
2163
 
1946
2164
  if (config.addedArgss) {
@@ -1961,45 +2179,51 @@ class Config {
1961
2179
  }
1962
2180
  config.wasInitialized = false
1963
2181
  // TODO change name of config: to baseConfig:
1964
- const kmFn = (name) => this.getConfig(name)
2182
+ const kmFn = (name) => {
2183
+ const config = this.getConfig(name)
2184
+ return config
2185
+ }
1965
2186
  // const hierarchy = new DigraphInternal((config.config || {}).hierarchy)
1966
- const args = {
2187
+ const args = new Object(setupInitializerFNArgs(this, {
1967
2188
  isModule,
1968
- addWord: aw,
1969
- km: kmFn,
1970
2189
  hierarchy: this.hierarchy,
1971
- config,
1972
- baseConfig: this,
2190
+ testConfig: config,
1973
2191
  currentConfig: config,
1974
2192
  uuid: config._uuid,
1975
2193
  objects: namespacedObjects,
1976
2194
  namespace,
1977
- motivation: (m) => config.addMotivation(m),
1978
- api: config.api
2195
+ api: config.api,
2196
+ }))
2197
+
2198
+ const currentConfig = args.currentConfig
2199
+
2200
+ /*
2201
+ if (args.currentConfig.api) {
2202
+ // args.currentConfig.api.objects = args.objects
2203
+ // TODO assign pseudo config?
2204
+ // args.currentConfig.api.config = () => args.baseConfig
2205
+ // args.currentConfig.api.uuid = args.currentConfig._uuid
2206
+ args.currentConfig.wasInitialized = true
1979
2207
  }
1980
- config.initializerFn(args)
1981
- if (config.initAfterApi) {
1982
- // reverse the list
2208
+ */
2209
+ // debugger
2210
+ // greg55
2211
+ config.initializerFn(args, { dontCallFn: true })
1983
2212
  initAfterApis.unshift({ config, args })
1984
- } else {
1985
- if (interleaved) {
1986
- initAfterApis.unshift(null)
1987
- }
1988
- }
1989
- // greg
1990
2213
  if (config._api) {
1991
2214
  if (config._api.initialize) {
1992
2215
  // reverse the list
1993
- inits.unshift( () => config._api.initialize({ config: this, km: kmFn, api: config._api }) )
2216
+ // TODO sync up the args with initialize of config
2217
+ inits.unshift( () => config._api.initialize({ config: this, km: kmFn, ...args, api: config._api }) )
1994
2218
  // config._api.initialize({ config, api: config._api })
1995
2219
  } else {
1996
2220
  if (interleaved) {
1997
2221
  inits.unshift(null)
1998
2222
  }
1999
2223
  }
2000
- config._api.objects = namespacedObjects
2001
- config._api.config = () => this
2002
- config._api.uuid = config._uuid
2224
+ // config._api.objects = namespacedObjects
2225
+ // config._api.config = () => this
2226
+ // config._api.uuid = config._uuid
2003
2227
  } else {
2004
2228
  if (interleaved) {
2005
2229
  inits.unshift(null)
@@ -2041,16 +2265,16 @@ class Config {
2041
2265
  init()
2042
2266
  }
2043
2267
  for (let init of initAfterApis) {
2044
- // init.args.isAfterApi = true
2045
2268
  init.config.initializerFn({ ...init.args, kms: this.getConfigs(), isAfterApi: true })
2046
2269
  }
2047
- this.instances.forEach((instance) => client.processInstance(this, instance))
2270
+ this.instances.forEach((instance) => client.loadInstance(this, instance))
2048
2271
  } else {
2049
2272
  const base = {
2050
2273
  operators: this.config.operators,
2051
2274
  bridges: this.config.bridges,
2052
2275
  hierarchy: this.config.hierarchy,
2053
2276
  priorities: this.config.priorities,
2277
+ contextual_priorities: this.config.contextual_priorities,
2054
2278
  associations: this.config.associations,
2055
2279
  words: this.config.words
2056
2280
  }
@@ -2059,6 +2283,7 @@ class Config {
2059
2283
  this.config.bridges = []
2060
2284
  this.config.hierarchy = []
2061
2285
  this.config.priorities = []
2286
+ this.config.contextual_priorities = []
2062
2287
  this.config.associations = { positive: [], negative: [] }
2063
2288
  this.config.words = {}
2064
2289
 
@@ -2073,19 +2298,19 @@ class Config {
2073
2298
  }
2074
2299
  // console.log('name -------------', name)
2075
2300
  if (inits[i]) {
2301
+ // greg55
2076
2302
  inits[i]()
2077
2303
  }
2078
2304
  if (initAfterApis[i]) {
2079
2305
  const init = initAfterApis[i]
2080
- init.config.initializerFn({ ...init.args, kms: this.getConfigs(), isAfterApi: true })
2306
+ init.config.initializerFn({ ...init.args, kms: this.getConfigs(), isAfterApi: true})
2081
2307
  }
2082
2308
  const instance = this.instances.find((instance) => instance.name == name)
2083
2309
  if (instance) {
2084
- client.processInstance(this, instance)
2310
+ client.loadInstance(this, instance)
2085
2311
  }
2086
2312
  this.hierarchy.edges = this.config.hierarchy
2087
2313
  }
2088
- // this.instances.forEach((instance) => client.processInstance(this, instance))
2089
2314
  }
2090
2315
 
2091
2316
  if (reverseIt) {
@@ -2208,13 +2433,9 @@ class Config {
2208
2433
  }
2209
2434
  const km = (name) => this.getConfig(name)
2210
2435
  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 })
2436
+ config.initializerFn(setupInitializerFNArgs(this, { isModule: this.isModule, currentConfig: config, testConfig: config, objects: nsobjects, namespace, uuid }))
2214
2437
  } 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 })
2438
+ this.initializerFn(setupInitializerFNArgs(this, { isModule: this.isModule, currentConfig: this, testConfig: this, objects: nsobjects, namespace, uuid }))
2218
2439
  }
2219
2440
  })
2220
2441
  }
@@ -2279,6 +2500,20 @@ class Config {
2279
2500
  config.priorities = priorities
2280
2501
  }
2281
2502
 
2503
+ if (config.contextual_priorities) {
2504
+ let contextual_priorities = config.contextual_priorities
2505
+ contextual_priorities = contextual_priorities.map((cp) => {
2506
+ const { context, choose } = cp
2507
+ return {
2508
+ context: context.map((id) => {
2509
+ return [toNS(id[0]), id[1]]
2510
+ }),
2511
+ choose
2512
+ }
2513
+ })
2514
+ config.contextual_priorities = contextual_priorities
2515
+ }
2516
+
2282
2517
  for (const bag of bags) {
2283
2518
  if (config[bag]) {
2284
2519
  config[bag] = config[bag].map((b) => {
@@ -2473,7 +2708,8 @@ class Config {
2473
2708
  }
2474
2709
 
2475
2710
  // TODO get rid of useOldVersion arg
2476
- addInternal (more, { useOldVersion = true, skipObjects = false, includeNamespaces = true, allowNameToBeNull = false, handleCalculatedProps : hcps = false } = {}) {
2711
+ addInternal (more, { addFirst = false, useOldVersion = true, skipObjects = false, includeNamespaces = true, allowNameToBeNull = false, handleCalculatedProps : hcps = false } = {}) {
2712
+ validConfigProps(more)
2477
2713
  if (more instanceof Config) {
2478
2714
  more.initialize({ force: false })
2479
2715
  if (useOldVersion) {
@@ -2484,7 +2720,7 @@ class Config {
2484
2720
  }
2485
2721
  }
2486
2722
  if (hcps) {
2487
- handleCalculatedProps(this, more)
2723
+ handleCalculatedProps(this, more, addFirst)
2488
2724
  applyUUID(more, this._uuid)
2489
2725
  }
2490
2726
  for (const key of Object.keys(more)) {
@@ -2509,7 +2745,11 @@ class Config {
2509
2745
  if (!configWords[word]) {
2510
2746
  configWords[word] = []
2511
2747
  }
2512
- configWords[word] = configWords[word].concat(moreWords[word])
2748
+ if (addFirst) {
2749
+ configWords[word] = moreWords[word].concat(configWords[word])
2750
+ } else {
2751
+ configWords[word] = configWords[word].concat(moreWords[word])
2752
+ }
2513
2753
  }
2514
2754
  } else if (key === 'name') {
2515
2755
  /*
@@ -2571,13 +2811,17 @@ class Config {
2571
2811
  this.config[key].splice(iOldOne, 1)
2572
2812
  break;
2573
2813
  }
2574
- }
2814
+ }
2575
2815
  }
2576
2816
  }
2577
2817
  }
2578
2818
  // console.log('key', key, 'XXX')
2579
2819
  // console.log('more', JSON.stringify(more, null, 2))
2580
- this.config[key] = this.config[key].concat(more[key])
2820
+ if (addFirst) {
2821
+ this.config[key] = more[key].concat(this.config[key])
2822
+ } else {
2823
+ this.config[key] = this.config[key].concat(more[key])
2824
+ }
2581
2825
  } else {
2582
2826
  if (!(key in this.config)) {
2583
2827
  throw new Error(`Unexpected property in config ${key}`)
@@ -2708,5 +2952,8 @@ class Config {
2708
2952
  }
2709
2953
 
2710
2954
  module.exports = {
2711
- Config
2955
+ Config,
2956
+ config_toServer,
2957
+ operatorKey_valid,
2958
+ handleBridgeProps,
2712
2959
  }