camunda-bpmn-js 5.14.0 → 5.14.1
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.
|
@@ -135574,518 +135574,518 @@
|
|
|
135574
135574
|
});
|
|
135575
135575
|
};
|
|
135576
135576
|
|
|
135577
|
-
class CachedValue {
|
|
135578
|
-
constructor(generatorFunction) {
|
|
135579
|
-
this._generate = generatorFunction;
|
|
135580
|
-
this.value = null;
|
|
135581
|
-
this.valid = false;
|
|
135582
|
-
}
|
|
135583
|
-
|
|
135584
|
-
invalidate() {
|
|
135585
|
-
this.valid = false;
|
|
135586
|
-
}
|
|
135587
|
-
|
|
135588
|
-
get() {
|
|
135589
|
-
if (!this.valid) {
|
|
135590
|
-
this.value = this._generate();
|
|
135591
|
-
this.valid = true;
|
|
135592
|
-
}
|
|
135593
|
-
|
|
135594
|
-
return this.value;
|
|
135595
|
-
}
|
|
135577
|
+
class CachedValue {
|
|
135578
|
+
constructor(generatorFunction) {
|
|
135579
|
+
this._generate = generatorFunction;
|
|
135580
|
+
this.value = null;
|
|
135581
|
+
this.valid = false;
|
|
135582
|
+
}
|
|
135583
|
+
|
|
135584
|
+
invalidate() {
|
|
135585
|
+
this.valid = false;
|
|
135586
|
+
}
|
|
135587
|
+
|
|
135588
|
+
get() {
|
|
135589
|
+
if (!this.valid) {
|
|
135590
|
+
this.value = this._generate();
|
|
135591
|
+
this.valid = true;
|
|
135592
|
+
}
|
|
135593
|
+
|
|
135594
|
+
return this.value;
|
|
135595
|
+
}
|
|
135596
135596
|
}
|
|
135597
135597
|
|
|
135598
|
-
function hasOutputMappings(element) {
|
|
135599
|
-
return !!getOutputParameters(element).length;
|
|
135600
|
-
}
|
|
135601
|
-
|
|
135602
|
-
function hasInputParameter(element, name) {
|
|
135603
|
-
return getInputParameters(element).find(function(input) {
|
|
135604
|
-
return (
|
|
135605
|
-
input.target === name || // zeebe
|
|
135606
|
-
input.name === name // camunda
|
|
135607
|
-
);
|
|
135608
|
-
});
|
|
135609
|
-
}
|
|
135610
|
-
|
|
135611
|
-
// helpers //////////
|
|
135612
|
-
|
|
135613
|
-
function getInputParameters(element) {
|
|
135614
|
-
return getParameters(element, 'inputParameters');
|
|
135615
|
-
}
|
|
135616
|
-
|
|
135617
|
-
function getOutputParameters(element) {
|
|
135618
|
-
return getParameters(element, 'outputParameters');
|
|
135619
|
-
}
|
|
135620
|
-
|
|
135621
|
-
function getInputOutput(element) {
|
|
135622
|
-
return (
|
|
135623
|
-
(getExtensionElements(element, 'zeebe:IoMapping'))[0] ||
|
|
135624
|
-
(getExtensionElements(element, 'camunda:InputOutput'))[0]
|
|
135625
|
-
);
|
|
135626
|
-
}
|
|
135627
|
-
|
|
135628
|
-
function getParameters(element, property) {
|
|
135629
|
-
var inputOutput = getInputOutput(element);
|
|
135630
|
-
|
|
135631
|
-
return (inputOutput && inputOutput.get(property)) || [];
|
|
135632
|
-
}
|
|
135633
|
-
|
|
135634
|
-
function getExtensionElements(element, type) {
|
|
135635
|
-
var elements = [];
|
|
135636
|
-
var extensionElements = element.get('extensionElements');
|
|
135637
|
-
|
|
135638
|
-
if (typeof extensionElements !== 'undefined') {
|
|
135639
|
-
var extensionValues = extensionElements.get('values');
|
|
135640
|
-
|
|
135641
|
-
if (typeof extensionValues !== 'undefined') {
|
|
135642
|
-
elements = filter(extensionValues, function(value) {
|
|
135643
|
-
return is$4(value, type);
|
|
135644
|
-
});
|
|
135645
|
-
}
|
|
135646
|
-
}
|
|
135647
|
-
|
|
135648
|
-
return elements;
|
|
135598
|
+
function hasOutputMappings(element) {
|
|
135599
|
+
return !!getOutputParameters(element).length;
|
|
135649
135600
|
}
|
|
135650
135601
|
|
|
135651
|
-
function
|
|
135652
|
-
|
|
135653
|
-
|
|
135654
|
-
|
|
135655
|
-
|
|
135656
|
-
|
|
135657
|
-
|
|
135658
|
-
var scopedParent = parents.find(function(parent) {
|
|
135659
|
-
return (
|
|
135660
|
-
is$4(parent, 'bpmn:SubProcess') && hasInputParameter(parent, variableName)
|
|
135661
|
-
);
|
|
135662
|
-
});
|
|
135663
|
-
|
|
135664
|
-
return scopedParent ? scopedParent : globalScope;
|
|
135665
|
-
}
|
|
135666
|
-
|
|
135667
|
-
function getParents(element) {
|
|
135668
|
-
var parents = [];
|
|
135669
|
-
var current = element;
|
|
135670
|
-
|
|
135671
|
-
while (current.$parent) {
|
|
135672
|
-
parents.push(current.$parent);
|
|
135673
|
-
current = current.$parent;
|
|
135674
|
-
}
|
|
135675
|
-
|
|
135676
|
-
return parents;
|
|
135602
|
+
function hasInputParameter(element, name) {
|
|
135603
|
+
return getInputParameters(element).find(function(input) {
|
|
135604
|
+
return (
|
|
135605
|
+
input.target === name || // zeebe
|
|
135606
|
+
input.name === name // camunda
|
|
135607
|
+
);
|
|
135608
|
+
});
|
|
135677
135609
|
}
|
|
135678
135610
|
|
|
135679
|
-
|
|
135680
|
-
|
|
135681
|
-
|
|
135682
|
-
|
|
135683
|
-
* @property {string} [info] A description of the variable displayed as a tooltip
|
|
135684
|
-
* @property {boolean} [isList] whether the variable is a list
|
|
135685
|
-
* @property {Array<AdditionalVariable>} [entries] If the variable is a context, this contains the entries of the context
|
|
135686
|
-
* @property {djs.model.Base} [scope] The scope of the variable, by default it is the container element of the element the variable is created from
|
|
135687
|
-
*/
|
|
135688
|
-
|
|
135689
|
-
/**
|
|
135690
|
-
* @typedef {AdditionalVariable} ProcessVariable
|
|
135691
|
-
* @property {Array<ModdleElement>} origin
|
|
135692
|
-
* @property {ModdleElement} scope
|
|
135693
|
-
* @property {Array<Object>} provider
|
|
135694
|
-
*/
|
|
135695
|
-
|
|
135696
|
-
/**
|
|
135697
|
-
* Base Class that handles additional variable extractors, variable parsing and caching.
|
|
135698
|
-
*/
|
|
135699
|
-
class BaseVariableResolver {
|
|
135700
|
-
constructor(eventBus, bpmnjs) {
|
|
135701
|
-
this.providers = [];
|
|
135702
|
-
this._eventBus = eventBus;
|
|
135703
|
-
this._bpmnjs = bpmnjs;
|
|
135704
|
-
|
|
135705
|
-
this.rawVariables = new CachedValue(this._generateRawVariables.bind(this));
|
|
135706
|
-
this.parsedVariables = new CachedValue(async () => {
|
|
135707
|
-
|
|
135708
|
-
const rawVariables = await this.getRawVariables();
|
|
135709
|
-
const context = { variables: rawVariables };
|
|
135710
|
-
|
|
135711
|
-
eventBus.fire('variableResolver.parseVariables', context);
|
|
135712
|
-
|
|
135713
|
-
return context.variables;
|
|
135714
|
-
});
|
|
135715
|
-
|
|
135716
|
-
eventBus.on([ 'commandStack.changed', 'diagram.clear', 'import.done', 'variables.changed' ], () => {
|
|
135717
|
-
this.invalidateCache();
|
|
135718
|
-
});
|
|
135719
|
-
|
|
135720
|
-
eventBus.on('variableResolver.parseVariables', (e, context) => {
|
|
135721
|
-
context.variables = this._parseVariables(context.variables);
|
|
135722
|
-
});
|
|
135723
|
-
}
|
|
135724
|
-
|
|
135725
|
-
/**
|
|
135726
|
-
* To be implemented by a subclass. This should be an instance of `getProcessVariables` from `@bpmn-io/extract-process-variables`,
|
|
135727
|
-
* either C7 or C8.
|
|
135728
|
-
*
|
|
135729
|
-
* @returns {Promise<Array<ProcessVariable>>}
|
|
135730
|
-
*/
|
|
135731
|
-
_baseExtractor() {
|
|
135732
|
-
return [];
|
|
135733
|
-
}
|
|
135734
|
-
|
|
135735
|
-
|
|
135736
|
-
/**
|
|
135737
|
-
* Returns an Object of all variables that are available in the current diagram,
|
|
135738
|
-
* mapped to the respective scope.
|
|
135739
|
-
* Variables with the same name are NOT merged together. Use this function to
|
|
135740
|
-
* run linting, e.g. to check for conflicting variable schemas.
|
|
135741
|
-
*
|
|
135742
|
-
* The result is cached until the diagram changes.
|
|
135743
|
-
*
|
|
135744
|
-
* @async
|
|
135745
|
-
* @returns {Object} rawVariables
|
|
135746
|
-
* @returns {Array<ProcessVariable>} rawVariables.<scope>
|
|
135747
|
-
*/
|
|
135748
|
-
async getRawVariables() {
|
|
135749
|
-
return await this.rawVariables.get();
|
|
135750
|
-
}
|
|
135751
|
-
|
|
135752
|
-
/**
|
|
135753
|
-
* Returns an array of all variables that are available in the current diagram.
|
|
135754
|
-
* Variables with the same name are NOT merged together. Use this function to
|
|
135755
|
-
* run linting, e.g. to check for conflicting variable schemas.
|
|
135756
|
-
*
|
|
135757
|
-
* Use this function if you need all availables for all root elements. To filter for scope,
|
|
135758
|
-
* use `getProcessVariables` or `getVariablesForElement`
|
|
135759
|
-
*
|
|
135760
|
-
* The result is cached until the diagram changes.
|
|
135761
|
-
*
|
|
135762
|
-
* @async
|
|
135763
|
-
* @returns {Object} rawVariables
|
|
135764
|
-
* @returns {Array<ProcessVariable>} rawVariables.<rootElement>
|
|
135765
|
-
*/
|
|
135766
|
-
async getVariables() {
|
|
135767
|
-
return await this.parsedVariables.get();
|
|
135768
|
-
}
|
|
135769
|
-
|
|
135770
|
-
/**
|
|
135771
|
-
* Force the cache to be invalidated an the variable extractors to be called
|
|
135772
|
-
* again the next time `getVariables` is called.
|
|
135773
|
-
*/
|
|
135774
|
-
invalidateCache() {
|
|
135775
|
-
this.rawVariables.invalidate();
|
|
135776
|
-
this.parsedVariables.invalidate();
|
|
135777
|
-
}
|
|
135778
|
-
|
|
135779
|
-
/**
|
|
135780
|
-
* Calls the baseExtractor and maps variables to the respective root element.
|
|
135781
|
-
* Cf. `getRawVariables`
|
|
135782
|
-
*
|
|
135783
|
-
* @async
|
|
135784
|
-
* @returns {Object} rawVariables
|
|
135785
|
-
* @returns {Array<ProcessVariable>} rawVariables.<scope>
|
|
135786
|
-
*/
|
|
135787
|
-
async _generateRawVariables() {
|
|
135788
|
-
const bpmnjs = this._bpmnjs;
|
|
135789
|
-
|
|
135790
|
-
const variables = {};
|
|
135791
|
-
|
|
135792
|
-
const workerTasks = bpmnjs.getDefinitions().get('rootElements').map(async element => {
|
|
135793
|
-
|
|
135794
|
-
const elementVariables = await this._baseExtractor(element, [ this._extractor.bind(this) ]);
|
|
135795
|
-
|
|
135796
|
-
// Annotate variables with extractor information
|
|
135797
|
-
variables[element.id] = elementVariables.map(variable => {
|
|
135798
|
-
if (!variable.provider) {
|
|
135799
|
-
variable.provider = [ this._baseExtractor ];
|
|
135800
|
-
}
|
|
135801
|
-
|
|
135802
|
-
return variable;
|
|
135803
|
-
});
|
|
135804
|
-
});
|
|
135805
|
-
|
|
135806
|
-
await Promise.all(workerTasks);
|
|
135807
|
-
|
|
135808
|
-
return variables;
|
|
135809
|
-
}
|
|
135810
|
-
|
|
135811
|
-
|
|
135812
|
-
/**
|
|
135813
|
-
* Parses the list of all variables and checks for duplicates. If duplicates are found, the schemas are merged
|
|
135814
|
-
* into a single variable.
|
|
135815
|
-
* Also maps the attribute `variable.type` to `variable.detail` for the feel editor to display it.
|
|
135816
|
-
*
|
|
135817
|
-
* Cf. `getVariables`
|
|
135818
|
-
*
|
|
135819
|
-
* @async
|
|
135820
|
-
* @param {Object} rawVariables
|
|
135821
|
-
* @param {Array<ProcessVariable>} rawVariables[scope]
|
|
135822
|
-
* @returns {Object} parsedVariables
|
|
135823
|
-
* @returns {Array<ProcessVariable>} parsedVariables[scope]
|
|
135824
|
-
*/
|
|
135825
|
-
_parseVariables(rawVariables) {
|
|
135826
|
-
const parsedVariables = {};
|
|
135827
|
-
for (const key in rawVariables) {
|
|
135828
|
-
const variables = rawVariables[key];
|
|
135829
|
-
|
|
135830
|
-
const mergedVariables = [];
|
|
135831
|
-
|
|
135832
|
-
variables.forEach(variable => {
|
|
135833
|
-
const existingVariable = mergedVariables.find(v =>
|
|
135834
|
-
v.name === variable.name && v.scope === variable.scope
|
|
135835
|
-
);
|
|
135836
|
-
|
|
135837
|
-
if (existingVariable) {
|
|
135838
|
-
merge('origin', existingVariable, variable);
|
|
135839
|
-
merge('provider', existingVariable, variable);
|
|
135840
|
-
mergeEntries(existingVariable, variable);
|
|
135841
|
-
} else {
|
|
135842
|
-
mergedVariables.push(variable);
|
|
135843
|
-
}
|
|
135844
|
-
});
|
|
135845
|
-
|
|
135846
|
-
mapToEditorFormat(mergedVariables);
|
|
135847
|
-
|
|
135848
|
-
parsedVariables[key] = mergedVariables;
|
|
135849
|
-
}
|
|
135850
|
-
|
|
135851
|
-
return parsedVariables;
|
|
135852
|
-
}
|
|
135853
|
-
|
|
135854
|
-
/**
|
|
135855
|
-
* Callback used by `@bpmn-io/extract-process-variables`. It adds additional information from the <AdditionalVariable>
|
|
135856
|
-
* returned from the providers to the <ProcessVariable> that is used by the resolver.
|
|
135857
|
-
*
|
|
135858
|
-
* It does not have a return value, the variables are added as a side effect to the `context.processVariables` array
|
|
135859
|
-
*
|
|
135860
|
-
* @async
|
|
135861
|
-
* @param {Object} context
|
|
135862
|
-
* @param {Array<ModdleElement>} context.elements
|
|
135863
|
-
* @param {ModdleElement} context.containerElement
|
|
135864
|
-
* @param {Array<ProcessVariable>} context.processVariables
|
|
135865
|
-
*/
|
|
135866
|
-
async _extractor(context) {
|
|
135867
|
-
const {
|
|
135868
|
-
elements,
|
|
135869
|
-
containerElement,
|
|
135870
|
-
processVariables
|
|
135871
|
-
} = context;
|
|
135872
|
-
|
|
135873
|
-
const self = this;
|
|
135874
|
-
|
|
135875
|
-
const workerTasks = elements.flatMap((element) => {
|
|
135876
|
-
return self.providers.map(async (provider) => {
|
|
135877
|
-
const newVariables = await provider.getVariables(element);
|
|
135878
|
-
|
|
135879
|
-
if (!newVariables) {
|
|
135880
|
-
return;
|
|
135881
|
-
}
|
|
135882
|
-
|
|
135883
|
-
// add scope and origin to variables
|
|
135884
|
-
newVariables.forEach(variable => {
|
|
135885
|
-
processVariables.push({
|
|
135886
|
-
...cloneVariable(variable),
|
|
135887
|
-
origin: [ element ],
|
|
135888
|
-
scope: variable.scope || getScope(element, containerElement, variable.name),
|
|
135889
|
-
provider: [ provider ]
|
|
135890
|
-
});
|
|
135891
|
-
});
|
|
135892
|
-
});
|
|
135893
|
-
});
|
|
135894
|
-
|
|
135895
|
-
await Promise.all(workerTasks);
|
|
135896
|
-
}
|
|
135897
|
-
|
|
135898
|
-
/**
|
|
135899
|
-
* Add a new VariableProvider. This will be used the next time `getVariables` is called.
|
|
135900
|
-
*
|
|
135901
|
-
* @param {VariableProvider} provider
|
|
135902
|
-
*/
|
|
135903
|
-
registerProvider(provider) {
|
|
135904
|
-
this.providers.push(provider);
|
|
135905
|
-
this.invalidateCache();
|
|
135906
|
-
}
|
|
135907
|
-
|
|
135908
|
-
/**
|
|
135909
|
-
* Returns all variables for the given root element.
|
|
135910
|
-
*
|
|
135911
|
-
* @async
|
|
135912
|
-
* @param {ModdleElement} element
|
|
135913
|
-
* @returns {Array<ProcessVariable>} variables
|
|
135914
|
-
*/
|
|
135915
|
-
async getProcessVariables(element) {
|
|
135916
|
-
const bo = getBusinessObject$1(element);
|
|
135917
|
-
|
|
135918
|
-
const allVariables = await this.getVariables();
|
|
135919
|
-
return allVariables[bo.id] || [];
|
|
135920
|
-
}
|
|
135921
|
-
|
|
135922
|
-
/**
|
|
135923
|
-
* Returns all variables in the scope of the given element.
|
|
135924
|
-
*
|
|
135925
|
-
* @async
|
|
135926
|
-
* @param {ModdleElement} element
|
|
135927
|
-
* @returns {Array<ProcessVariable>} variables
|
|
135928
|
-
*/
|
|
135929
|
-
async getVariablesForElement(element) {
|
|
135930
|
-
const bo = getBusinessObject$1(element);
|
|
135931
|
-
|
|
135932
|
-
const root = getRootElement(bo);
|
|
135933
|
-
const allVariables = await this.getProcessVariables(root);
|
|
135934
|
-
|
|
135935
|
-
// (1) get variables for given scope
|
|
135936
|
-
var scopeVariables = allVariables.filter(function(variable) {
|
|
135937
|
-
return variable.scope.id === bo.id;
|
|
135938
|
-
});
|
|
135939
|
-
|
|
135940
|
-
// (2) get variables for parent scopes
|
|
135941
|
-
var parents = getParents(bo);
|
|
135942
|
-
|
|
135943
|
-
var parentsScopeVariables = allVariables.filter(function(variable) {
|
|
135944
|
-
return parents.find(function(parent) {
|
|
135945
|
-
return parent.id === variable.scope.id;
|
|
135946
|
-
});
|
|
135947
|
-
});
|
|
135948
|
-
|
|
135949
|
-
const reversedVariables = [ ...scopeVariables, ...parentsScopeVariables ].reverse();
|
|
135950
|
-
|
|
135951
|
-
const seenNames = new Set();
|
|
135952
|
-
|
|
135953
|
-
return reversedVariables.filter(variable => {
|
|
135954
|
-
|
|
135955
|
-
// if external variable, keep
|
|
135956
|
-
if (variable.provider.find(extractor => extractor !== this._baseExtractor)) {
|
|
135957
|
-
return true;
|
|
135958
|
-
}
|
|
135959
|
-
|
|
135960
|
-
// if not external, keep only the first occurrence of each name
|
|
135961
|
-
if (!seenNames.has(variable.name)) {
|
|
135962
|
-
seenNames.add(variable.name);
|
|
135963
|
-
|
|
135964
|
-
return true;
|
|
135965
|
-
}
|
|
135966
|
-
|
|
135967
|
-
return false;
|
|
135968
|
-
});
|
|
135969
|
-
}
|
|
135970
|
-
}
|
|
135971
|
-
|
|
135972
|
-
BaseVariableResolver.$inject = [ 'eventBus', 'bpmnjs' ];
|
|
135973
|
-
|
|
135974
|
-
|
|
135975
|
-
// helpers //////////////////////
|
|
135976
|
-
|
|
135977
|
-
function getRootElement(element) {
|
|
135978
|
-
const businessObject = getBusinessObject$1(element);
|
|
135979
|
-
|
|
135980
|
-
if (is$4(businessObject, 'bpmn:Participant')) {
|
|
135981
|
-
return businessObject.processRef;
|
|
135982
|
-
}
|
|
135983
|
-
|
|
135984
|
-
if (is$4(businessObject, 'bpmn:Process')) {
|
|
135985
|
-
return businessObject;
|
|
135986
|
-
}
|
|
135987
|
-
|
|
135988
|
-
let parent = businessObject;
|
|
135989
|
-
|
|
135990
|
-
while (parent.$parent && !is$4(parent, 'bpmn:Process')) {
|
|
135991
|
-
parent = parent.$parent;
|
|
135992
|
-
}
|
|
135993
|
-
|
|
135994
|
-
return parent;
|
|
135995
|
-
}
|
|
135996
|
-
|
|
135997
|
-
function merge(property, target, source) {
|
|
135998
|
-
if (!source[property]) {
|
|
135999
|
-
source[property] = [];
|
|
136000
|
-
}
|
|
136001
|
-
|
|
136002
|
-
if (!target[property]) {
|
|
136003
|
-
target[property] = [];
|
|
136004
|
-
}
|
|
136005
|
-
|
|
136006
|
-
const propertiesToAdd = source[property].filter(o => !target[property].includes(o));
|
|
136007
|
-
|
|
136008
|
-
target[property].push(...propertiesToAdd);
|
|
136009
|
-
}
|
|
136010
|
-
|
|
136011
|
-
function mergeEntries(target, source, visited = []) {
|
|
136012
|
-
if (visited.includes(source) || visited.includes(target)) {
|
|
136013
|
-
return;
|
|
136014
|
-
}
|
|
136015
|
-
visited.push(source);
|
|
136016
|
-
visited.push(target);
|
|
136017
|
-
|
|
136018
|
-
target.type = extendList(target.type, source.type, '|');
|
|
136019
|
-
target.info = extendList(target.info, source.info, '\n');
|
|
136020
|
-
target.isList = !!target.isList === !!source.isList ? target.isList : 'optional';
|
|
136021
|
-
|
|
136022
|
-
if (!source.entries) {
|
|
136023
|
-
return;
|
|
136024
|
-
}
|
|
136025
|
-
|
|
136026
|
-
if (!target.entries) {
|
|
136027
|
-
target.entries = [];
|
|
136028
|
-
}
|
|
136029
|
-
|
|
136030
|
-
source.entries.forEach(variable => {
|
|
136031
|
-
const existingEntry = target.entries.find(e => e.name === variable.name);
|
|
136032
|
-
|
|
136033
|
-
if (existingEntry) {
|
|
136034
|
-
mergeEntries(existingEntry, variable, visited);
|
|
136035
|
-
} else {
|
|
136036
|
-
target.entries.push(variable);
|
|
136037
|
-
}
|
|
136038
|
-
});
|
|
136039
|
-
}
|
|
136040
|
-
|
|
136041
|
-
const extendList = (target, source, separator) => {
|
|
136042
|
-
if (!target || target === source) {
|
|
136043
|
-
return source;
|
|
136044
|
-
} else {
|
|
136045
|
-
const existingTypes = target.split(separator);
|
|
136046
|
-
if (!existingTypes.includes(source)) {
|
|
136047
|
-
existingTypes.push(source);
|
|
136048
|
-
}
|
|
136049
|
-
return existingTypes.join(separator);
|
|
136050
|
-
}
|
|
136051
|
-
};
|
|
136052
|
-
|
|
136053
|
-
function mapToEditorFormat(variables) {
|
|
136054
|
-
if (!variables) {
|
|
136055
|
-
return;
|
|
136056
|
-
}
|
|
136057
|
-
|
|
136058
|
-
variables.forEach(variable => {
|
|
136059
|
-
variable.detail = variable.type;
|
|
136060
|
-
mapToEditorFormat(variable.entries);
|
|
136061
|
-
});
|
|
136062
|
-
}
|
|
136063
|
-
|
|
136064
|
-
function cloneVariable(variable) {
|
|
136065
|
-
const newVariable = { ...variable };
|
|
136066
|
-
|
|
136067
|
-
if (newVariable.entries) {
|
|
136068
|
-
newVariable.entries = newVariable.entries.map(cloneVariable);
|
|
136069
|
-
}
|
|
136070
|
-
|
|
136071
|
-
return newVariable;
|
|
135611
|
+
// helpers //////////
|
|
135612
|
+
|
|
135613
|
+
function getInputParameters(element) {
|
|
135614
|
+
return getParameters(element, 'inputParameters');
|
|
136072
135615
|
}
|
|
136073
135616
|
|
|
136074
|
-
|
|
136075
|
-
|
|
136076
|
-
*/
|
|
136077
|
-
class CamundaVariableResolver extends BaseVariableResolver {
|
|
136078
|
-
constructor(eventBus, bpmnjs) {
|
|
136079
|
-
super(eventBus, bpmnjs);
|
|
136080
|
-
this._baseExtractor = getProcessVariables;
|
|
136081
|
-
}
|
|
135617
|
+
function getOutputParameters(element) {
|
|
135618
|
+
return getParameters(element, 'outputParameters');
|
|
136082
135619
|
}
|
|
136083
135620
|
|
|
136084
|
-
|
|
136085
|
-
|
|
136086
|
-
'
|
|
136087
|
-
|
|
136088
|
-
|
|
135621
|
+
function getInputOutput(element) {
|
|
135622
|
+
return (
|
|
135623
|
+
(getExtensionElements(element, 'zeebe:IoMapping'))[0] ||
|
|
135624
|
+
(getExtensionElements(element, 'camunda:InputOutput'))[0]
|
|
135625
|
+
);
|
|
135626
|
+
}
|
|
135627
|
+
|
|
135628
|
+
function getParameters(element, property) {
|
|
135629
|
+
var inputOutput = getInputOutput(element);
|
|
135630
|
+
|
|
135631
|
+
return (inputOutput && inputOutput.get(property)) || [];
|
|
135632
|
+
}
|
|
135633
|
+
|
|
135634
|
+
function getExtensionElements(element, type) {
|
|
135635
|
+
var elements = [];
|
|
135636
|
+
var extensionElements = element.get('extensionElements');
|
|
135637
|
+
|
|
135638
|
+
if (typeof extensionElements !== 'undefined') {
|
|
135639
|
+
var extensionValues = extensionElements.get('values');
|
|
135640
|
+
|
|
135641
|
+
if (typeof extensionValues !== 'undefined') {
|
|
135642
|
+
elements = filter(extensionValues, function(value) {
|
|
135643
|
+
return is$4(value, type);
|
|
135644
|
+
});
|
|
135645
|
+
}
|
|
135646
|
+
}
|
|
135647
|
+
|
|
135648
|
+
return elements;
|
|
135649
|
+
}
|
|
135650
|
+
|
|
135651
|
+
function getScope(element, globalScope, variableName) {
|
|
135652
|
+
var parents = getParents(element);
|
|
135653
|
+
|
|
135654
|
+
if (hasOutputMappings(element)) {
|
|
135655
|
+
return element;
|
|
135656
|
+
}
|
|
135657
|
+
|
|
135658
|
+
var scopedParent = parents.find(function(parent) {
|
|
135659
|
+
return (
|
|
135660
|
+
is$4(parent, 'bpmn:SubProcess') && hasInputParameter(parent, variableName)
|
|
135661
|
+
);
|
|
135662
|
+
});
|
|
135663
|
+
|
|
135664
|
+
return scopedParent ? scopedParent : globalScope;
|
|
135665
|
+
}
|
|
135666
|
+
|
|
135667
|
+
function getParents(element) {
|
|
135668
|
+
var parents = [];
|
|
135669
|
+
var current = element;
|
|
135670
|
+
|
|
135671
|
+
while (current.$parent) {
|
|
135672
|
+
parents.push(current.$parent);
|
|
135673
|
+
current = current.$parent;
|
|
135674
|
+
}
|
|
135675
|
+
|
|
135676
|
+
return parents;
|
|
135677
|
+
}
|
|
135678
|
+
|
|
135679
|
+
/**
|
|
135680
|
+
* @typedef {Object} AdditionalVariable
|
|
135681
|
+
* @property {string} name The name of the variable
|
|
135682
|
+
* @property {string} [type] The type of the variable
|
|
135683
|
+
* @property {string} [info] A description of the variable displayed as a tooltip
|
|
135684
|
+
* @property {boolean} [isList] whether the variable is a list
|
|
135685
|
+
* @property {Array<AdditionalVariable>} [entries] If the variable is a context, this contains the entries of the context
|
|
135686
|
+
* @property {djs.model.Base} [scope] The scope of the variable, by default it is the container element of the element the variable is created from
|
|
135687
|
+
*/
|
|
135688
|
+
|
|
135689
|
+
/**
|
|
135690
|
+
* @typedef {AdditionalVariable} ProcessVariable
|
|
135691
|
+
* @property {Array<ModdleElement>} origin
|
|
135692
|
+
* @property {ModdleElement} scope
|
|
135693
|
+
* @property {Array<Object>} provider
|
|
135694
|
+
*/
|
|
135695
|
+
|
|
135696
|
+
/**
|
|
135697
|
+
* Base Class that handles additional variable extractors, variable parsing and caching.
|
|
135698
|
+
*/
|
|
135699
|
+
class BaseVariableResolver {
|
|
135700
|
+
constructor(eventBus, bpmnjs) {
|
|
135701
|
+
this.providers = [];
|
|
135702
|
+
this._eventBus = eventBus;
|
|
135703
|
+
this._bpmnjs = bpmnjs;
|
|
135704
|
+
|
|
135705
|
+
this.rawVariables = new CachedValue(this._generateRawVariables.bind(this));
|
|
135706
|
+
this.parsedVariables = new CachedValue(async () => {
|
|
135707
|
+
|
|
135708
|
+
const rawVariables = await this.getRawVariables();
|
|
135709
|
+
const context = { variables: rawVariables };
|
|
135710
|
+
|
|
135711
|
+
eventBus.fire('variableResolver.parseVariables', context);
|
|
135712
|
+
|
|
135713
|
+
return context.variables;
|
|
135714
|
+
});
|
|
135715
|
+
|
|
135716
|
+
eventBus.on([ 'commandStack.changed', 'diagram.clear', 'import.done', 'variables.changed' ], () => {
|
|
135717
|
+
this.invalidateCache();
|
|
135718
|
+
});
|
|
135719
|
+
|
|
135720
|
+
eventBus.on('variableResolver.parseVariables', (e, context) => {
|
|
135721
|
+
context.variables = this._parseVariables(context.variables);
|
|
135722
|
+
});
|
|
135723
|
+
}
|
|
135724
|
+
|
|
135725
|
+
/**
|
|
135726
|
+
* To be implemented by a subclass. This should be an instance of `getProcessVariables` from `@bpmn-io/extract-process-variables`,
|
|
135727
|
+
* either C7 or C8.
|
|
135728
|
+
*
|
|
135729
|
+
* @returns {Promise<Array<ProcessVariable>>}
|
|
135730
|
+
*/
|
|
135731
|
+
_baseExtractor() {
|
|
135732
|
+
return [];
|
|
135733
|
+
}
|
|
135734
|
+
|
|
135735
|
+
|
|
135736
|
+
/**
|
|
135737
|
+
* Returns an Object of all variables that are available in the current diagram,
|
|
135738
|
+
* mapped to the respective scope.
|
|
135739
|
+
* Variables with the same name are NOT merged together. Use this function to
|
|
135740
|
+
* run linting, e.g. to check for conflicting variable schemas.
|
|
135741
|
+
*
|
|
135742
|
+
* The result is cached until the diagram changes.
|
|
135743
|
+
*
|
|
135744
|
+
* @async
|
|
135745
|
+
* @returns {Object} rawVariables
|
|
135746
|
+
* @returns {Array<ProcessVariable>} rawVariables.<scope>
|
|
135747
|
+
*/
|
|
135748
|
+
async getRawVariables() {
|
|
135749
|
+
return await this.rawVariables.get();
|
|
135750
|
+
}
|
|
135751
|
+
|
|
135752
|
+
/**
|
|
135753
|
+
* Returns an array of all variables that are available in the current diagram.
|
|
135754
|
+
* Variables with the same name are NOT merged together. Use this function to
|
|
135755
|
+
* run linting, e.g. to check for conflicting variable schemas.
|
|
135756
|
+
*
|
|
135757
|
+
* Use this function if you need all availables for all root elements. To filter for scope,
|
|
135758
|
+
* use `getProcessVariables` or `getVariablesForElement`
|
|
135759
|
+
*
|
|
135760
|
+
* The result is cached until the diagram changes.
|
|
135761
|
+
*
|
|
135762
|
+
* @async
|
|
135763
|
+
* @returns {Object} rawVariables
|
|
135764
|
+
* @returns {Array<ProcessVariable>} rawVariables.<rootElement>
|
|
135765
|
+
*/
|
|
135766
|
+
async getVariables() {
|
|
135767
|
+
return await this.parsedVariables.get();
|
|
135768
|
+
}
|
|
135769
|
+
|
|
135770
|
+
/**
|
|
135771
|
+
* Force the cache to be invalidated an the variable extractors to be called
|
|
135772
|
+
* again the next time `getVariables` is called.
|
|
135773
|
+
*/
|
|
135774
|
+
invalidateCache() {
|
|
135775
|
+
this.rawVariables.invalidate();
|
|
135776
|
+
this.parsedVariables.invalidate();
|
|
135777
|
+
}
|
|
135778
|
+
|
|
135779
|
+
/**
|
|
135780
|
+
* Calls the baseExtractor and maps variables to the respective root element.
|
|
135781
|
+
* Cf. `getRawVariables`
|
|
135782
|
+
*
|
|
135783
|
+
* @async
|
|
135784
|
+
* @returns {Object} rawVariables
|
|
135785
|
+
* @returns {Array<ProcessVariable>} rawVariables.<scope>
|
|
135786
|
+
*/
|
|
135787
|
+
async _generateRawVariables() {
|
|
135788
|
+
const bpmnjs = this._bpmnjs;
|
|
135789
|
+
|
|
135790
|
+
const variables = {};
|
|
135791
|
+
|
|
135792
|
+
const workerTasks = bpmnjs.getDefinitions().get('rootElements').map(async element => {
|
|
135793
|
+
|
|
135794
|
+
const elementVariables = await this._baseExtractor(element, [ this._extractor.bind(this) ]);
|
|
135795
|
+
|
|
135796
|
+
// Annotate variables with extractor information
|
|
135797
|
+
variables[element.id] = elementVariables.map(variable => {
|
|
135798
|
+
if (!variable.provider) {
|
|
135799
|
+
variable.provider = [ this._baseExtractor ];
|
|
135800
|
+
}
|
|
135801
|
+
|
|
135802
|
+
return variable;
|
|
135803
|
+
});
|
|
135804
|
+
});
|
|
135805
|
+
|
|
135806
|
+
await Promise.all(workerTasks);
|
|
135807
|
+
|
|
135808
|
+
return variables;
|
|
135809
|
+
}
|
|
135810
|
+
|
|
135811
|
+
|
|
135812
|
+
/**
|
|
135813
|
+
* Parses the list of all variables and checks for duplicates. If duplicates are found, the schemas are merged
|
|
135814
|
+
* into a single variable.
|
|
135815
|
+
* Also maps the attribute `variable.type` to `variable.detail` for the feel editor to display it.
|
|
135816
|
+
*
|
|
135817
|
+
* Cf. `getVariables`
|
|
135818
|
+
*
|
|
135819
|
+
* @async
|
|
135820
|
+
* @param {Object} rawVariables
|
|
135821
|
+
* @param {Array<ProcessVariable>} rawVariables[scope]
|
|
135822
|
+
* @returns {Object} parsedVariables
|
|
135823
|
+
* @returns {Array<ProcessVariable>} parsedVariables[scope]
|
|
135824
|
+
*/
|
|
135825
|
+
_parseVariables(rawVariables) {
|
|
135826
|
+
const parsedVariables = {};
|
|
135827
|
+
for (const key in rawVariables) {
|
|
135828
|
+
const variables = rawVariables[key];
|
|
135829
|
+
|
|
135830
|
+
const mergedVariables = [];
|
|
135831
|
+
|
|
135832
|
+
variables.forEach(variable => {
|
|
135833
|
+
const existingVariable = mergedVariables.find(v =>
|
|
135834
|
+
v.name === variable.name && v.scope === variable.scope
|
|
135835
|
+
);
|
|
135836
|
+
|
|
135837
|
+
if (existingVariable) {
|
|
135838
|
+
merge('origin', existingVariable, variable);
|
|
135839
|
+
merge('provider', existingVariable, variable);
|
|
135840
|
+
mergeEntries(existingVariable, variable);
|
|
135841
|
+
} else {
|
|
135842
|
+
mergedVariables.push(variable);
|
|
135843
|
+
}
|
|
135844
|
+
});
|
|
135845
|
+
|
|
135846
|
+
mapToEditorFormat(mergedVariables);
|
|
135847
|
+
|
|
135848
|
+
parsedVariables[key] = mergedVariables;
|
|
135849
|
+
}
|
|
135850
|
+
|
|
135851
|
+
return parsedVariables;
|
|
135852
|
+
}
|
|
135853
|
+
|
|
135854
|
+
/**
|
|
135855
|
+
* Callback used by `@bpmn-io/extract-process-variables`. It adds additional information from the <AdditionalVariable>
|
|
135856
|
+
* returned from the providers to the <ProcessVariable> that is used by the resolver.
|
|
135857
|
+
*
|
|
135858
|
+
* It does not have a return value, the variables are added as a side effect to the `context.processVariables` array
|
|
135859
|
+
*
|
|
135860
|
+
* @async
|
|
135861
|
+
* @param {Object} context
|
|
135862
|
+
* @param {Array<ModdleElement>} context.elements
|
|
135863
|
+
* @param {ModdleElement} context.containerElement
|
|
135864
|
+
* @param {Array<ProcessVariable>} context.processVariables
|
|
135865
|
+
*/
|
|
135866
|
+
async _extractor(context) {
|
|
135867
|
+
const {
|
|
135868
|
+
elements,
|
|
135869
|
+
containerElement,
|
|
135870
|
+
processVariables
|
|
135871
|
+
} = context;
|
|
135872
|
+
|
|
135873
|
+
const self = this;
|
|
135874
|
+
|
|
135875
|
+
const workerTasks = elements.flatMap((element) => {
|
|
135876
|
+
return self.providers.map(async (provider) => {
|
|
135877
|
+
const newVariables = await provider.getVariables(element);
|
|
135878
|
+
|
|
135879
|
+
if (!newVariables) {
|
|
135880
|
+
return;
|
|
135881
|
+
}
|
|
135882
|
+
|
|
135883
|
+
// add scope and origin to variables
|
|
135884
|
+
newVariables.forEach(variable => {
|
|
135885
|
+
processVariables.push({
|
|
135886
|
+
...cloneVariable(variable),
|
|
135887
|
+
origin: [ element ],
|
|
135888
|
+
scope: variable.scope || getScope(element, containerElement, variable.name),
|
|
135889
|
+
provider: [ provider ]
|
|
135890
|
+
});
|
|
135891
|
+
});
|
|
135892
|
+
});
|
|
135893
|
+
});
|
|
135894
|
+
|
|
135895
|
+
await Promise.all(workerTasks);
|
|
135896
|
+
}
|
|
135897
|
+
|
|
135898
|
+
/**
|
|
135899
|
+
* Add a new VariableProvider. This will be used the next time `getVariables` is called.
|
|
135900
|
+
*
|
|
135901
|
+
* @param {VariableProvider} provider
|
|
135902
|
+
*/
|
|
135903
|
+
registerProvider(provider) {
|
|
135904
|
+
this.providers.push(provider);
|
|
135905
|
+
this.invalidateCache();
|
|
135906
|
+
}
|
|
135907
|
+
|
|
135908
|
+
/**
|
|
135909
|
+
* Returns all variables for the given root element.
|
|
135910
|
+
*
|
|
135911
|
+
* @async
|
|
135912
|
+
* @param {ModdleElement} element
|
|
135913
|
+
* @returns {Array<ProcessVariable>} variables
|
|
135914
|
+
*/
|
|
135915
|
+
async getProcessVariables(element) {
|
|
135916
|
+
const bo = getBusinessObject$1(element);
|
|
135917
|
+
|
|
135918
|
+
const allVariables = await this.getVariables();
|
|
135919
|
+
return allVariables[bo.id] || [];
|
|
135920
|
+
}
|
|
135921
|
+
|
|
135922
|
+
/**
|
|
135923
|
+
* Returns all variables in the scope of the given element.
|
|
135924
|
+
*
|
|
135925
|
+
* @async
|
|
135926
|
+
* @param {ModdleElement} element
|
|
135927
|
+
* @returns {Array<ProcessVariable>} variables
|
|
135928
|
+
*/
|
|
135929
|
+
async getVariablesForElement(element) {
|
|
135930
|
+
const bo = getBusinessObject$1(element);
|
|
135931
|
+
|
|
135932
|
+
const root = getRootElement(bo);
|
|
135933
|
+
const allVariables = await this.getProcessVariables(root);
|
|
135934
|
+
|
|
135935
|
+
// (1) get variables for given scope
|
|
135936
|
+
var scopeVariables = allVariables.filter(function(variable) {
|
|
135937
|
+
return variable.scope.id === bo.id;
|
|
135938
|
+
});
|
|
135939
|
+
|
|
135940
|
+
// (2) get variables for parent scopes
|
|
135941
|
+
var parents = getParents(bo);
|
|
135942
|
+
|
|
135943
|
+
var parentsScopeVariables = allVariables.filter(function(variable) {
|
|
135944
|
+
return parents.find(function(parent) {
|
|
135945
|
+
return parent.id === variable.scope.id;
|
|
135946
|
+
});
|
|
135947
|
+
});
|
|
135948
|
+
|
|
135949
|
+
const reversedVariables = [ ...scopeVariables, ...parentsScopeVariables ].reverse();
|
|
135950
|
+
|
|
135951
|
+
const seenNames = new Set();
|
|
135952
|
+
|
|
135953
|
+
return reversedVariables.filter(variable => {
|
|
135954
|
+
|
|
135955
|
+
// if external variable, keep
|
|
135956
|
+
if (variable.provider.find(extractor => extractor !== this._baseExtractor)) {
|
|
135957
|
+
return true;
|
|
135958
|
+
}
|
|
135959
|
+
|
|
135960
|
+
// if not external, keep only the first occurrence of each name
|
|
135961
|
+
if (!seenNames.has(variable.name)) {
|
|
135962
|
+
seenNames.add(variable.name);
|
|
135963
|
+
|
|
135964
|
+
return true;
|
|
135965
|
+
}
|
|
135966
|
+
|
|
135967
|
+
return false;
|
|
135968
|
+
});
|
|
135969
|
+
}
|
|
135970
|
+
}
|
|
135971
|
+
|
|
135972
|
+
BaseVariableResolver.$inject = [ 'eventBus', 'bpmnjs' ];
|
|
135973
|
+
|
|
135974
|
+
|
|
135975
|
+
// helpers //////////////////////
|
|
135976
|
+
|
|
135977
|
+
function getRootElement(element) {
|
|
135978
|
+
const businessObject = getBusinessObject$1(element);
|
|
135979
|
+
|
|
135980
|
+
if (is$4(businessObject, 'bpmn:Participant')) {
|
|
135981
|
+
return businessObject.processRef;
|
|
135982
|
+
}
|
|
135983
|
+
|
|
135984
|
+
if (is$4(businessObject, 'bpmn:Process')) {
|
|
135985
|
+
return businessObject;
|
|
135986
|
+
}
|
|
135987
|
+
|
|
135988
|
+
let parent = businessObject;
|
|
135989
|
+
|
|
135990
|
+
while (parent.$parent && !is$4(parent, 'bpmn:Process')) {
|
|
135991
|
+
parent = parent.$parent;
|
|
135992
|
+
}
|
|
135993
|
+
|
|
135994
|
+
return parent;
|
|
135995
|
+
}
|
|
135996
|
+
|
|
135997
|
+
function merge(property, target, source) {
|
|
135998
|
+
if (!source[property]) {
|
|
135999
|
+
source[property] = [];
|
|
136000
|
+
}
|
|
136001
|
+
|
|
136002
|
+
if (!target[property]) {
|
|
136003
|
+
target[property] = [];
|
|
136004
|
+
}
|
|
136005
|
+
|
|
136006
|
+
const propertiesToAdd = source[property].filter(o => !target[property].includes(o));
|
|
136007
|
+
|
|
136008
|
+
target[property].push(...propertiesToAdd);
|
|
136009
|
+
}
|
|
136010
|
+
|
|
136011
|
+
function mergeEntries(target, source, visited = []) {
|
|
136012
|
+
if (visited.includes(source) || visited.includes(target)) {
|
|
136013
|
+
return;
|
|
136014
|
+
}
|
|
136015
|
+
visited.push(source);
|
|
136016
|
+
visited.push(target);
|
|
136017
|
+
|
|
136018
|
+
target.type = extendList(target.type, source.type, '|');
|
|
136019
|
+
target.info = extendList(target.info, source.info, '\n');
|
|
136020
|
+
target.isList = !!target.isList === !!source.isList ? target.isList : 'optional';
|
|
136021
|
+
|
|
136022
|
+
if (!source.entries) {
|
|
136023
|
+
return;
|
|
136024
|
+
}
|
|
136025
|
+
|
|
136026
|
+
if (!target.entries) {
|
|
136027
|
+
target.entries = [];
|
|
136028
|
+
}
|
|
136029
|
+
|
|
136030
|
+
source.entries.forEach(variable => {
|
|
136031
|
+
const existingEntry = target.entries.find(e => e.name === variable.name);
|
|
136032
|
+
|
|
136033
|
+
if (existingEntry) {
|
|
136034
|
+
mergeEntries(existingEntry, variable, visited);
|
|
136035
|
+
} else {
|
|
136036
|
+
target.entries.push(variable);
|
|
136037
|
+
}
|
|
136038
|
+
});
|
|
136039
|
+
}
|
|
136040
|
+
|
|
136041
|
+
const extendList = (target, source, separator) => {
|
|
136042
|
+
if (!target || target === source) {
|
|
136043
|
+
return source;
|
|
136044
|
+
} else {
|
|
136045
|
+
const existingTypes = target.split(separator);
|
|
136046
|
+
if (!existingTypes.includes(source)) {
|
|
136047
|
+
existingTypes.push(source);
|
|
136048
|
+
}
|
|
136049
|
+
return existingTypes.join(separator);
|
|
136050
|
+
}
|
|
136051
|
+
};
|
|
136052
|
+
|
|
136053
|
+
function mapToEditorFormat(variables) {
|
|
136054
|
+
if (!variables) {
|
|
136055
|
+
return;
|
|
136056
|
+
}
|
|
136057
|
+
|
|
136058
|
+
variables.forEach(variable => {
|
|
136059
|
+
variable.detail = variable.type;
|
|
136060
|
+
mapToEditorFormat(variable.entries);
|
|
136061
|
+
});
|
|
136062
|
+
}
|
|
136063
|
+
|
|
136064
|
+
function cloneVariable(variable) {
|
|
136065
|
+
const newVariable = { ...variable };
|
|
136066
|
+
|
|
136067
|
+
if (newVariable.entries) {
|
|
136068
|
+
newVariable.entries = newVariable.entries.map(cloneVariable);
|
|
136069
|
+
}
|
|
136070
|
+
|
|
136071
|
+
return newVariable;
|
|
136072
|
+
}
|
|
136073
|
+
|
|
136074
|
+
/**
|
|
136075
|
+
* The Camunda 7 Implementation for the VariableResolver.
|
|
136076
|
+
*/
|
|
136077
|
+
class CamundaVariableResolver extends BaseVariableResolver {
|
|
136078
|
+
constructor(eventBus, bpmnjs) {
|
|
136079
|
+
super(eventBus, bpmnjs);
|
|
136080
|
+
this._baseExtractor = getProcessVariables;
|
|
136081
|
+
}
|
|
136082
|
+
}
|
|
136083
|
+
|
|
136084
|
+
const CamundaVariableResolverModule = {
|
|
136085
|
+
__init__: [
|
|
136086
|
+
'variableResolver',
|
|
136087
|
+
],
|
|
136088
|
+
variableResolver: [ 'type', CamundaVariableResolver ],
|
|
136089
136089
|
};
|
|
136090
136090
|
|
|
136091
136091
|
var name = "Camunda";
|