Merge lp:~tapaal-contributor/tapaal/engine-option-matrix-dev into lp:tapaal

Proposed by Peter Haahr Taankvist
Status: Merged
Approved by: Jiri Srba
Approved revision: 1084
Merged at revision: 1083
Proposed branch: lp:~tapaal-contributor/tapaal/engine-option-matrix-dev
Merge into: lp:tapaal
Diff against target: 398 lines (+232/-86)
4 files modified
src/dk/aau/cs/model/tapn/TimedArcPetriNet.java (+9/-4)
src/dk/aau/cs/model/tapn/TimedArcPetriNetNetwork.java (+7/-0)
src/pipe/gui/EngineSupportOptions.java (+51/-0)
src/pipe/gui/widgets/QueryDialog.java (+165/-82)
To merge this branch: bzr merge lp:~tapaal-contributor/tapaal/engine-option-matrix-dev
Reviewer Review Type Date Requested Status
Jiri Srba Approve
Peter Haahr Taankvist (community) Needs Resubmitting
Kenneth Yrke Jørgensen Approve
Review via email: mp+388561@code.launchpad.net

Commit message

Implement engine option matrix, which tells which engines are available given certain features. This replaces a large if-else tree and makes it easier to extend if the engines start supporting new features.

To post a comment you must log in.
1075. By Peter Taankvist <email address hidden>

merge with trunk

Revision history for this message
Kenneth Yrke Jørgensen (yrke) wrote :

In general think it looks good, a sound beginning, but there is defenitly more work that can be done.
Added a few notes to the implementation.

review: Needs Fixing
1076. By Peter Taankvist <email address hidden>

merge with trunk

1077. By Peter Taankvist <email address hidden>

merge with trunk

Revision history for this message
Jiri Srba (srba) wrote :

Kenneth, I saw your comments and it was actually me who suggested to add the comments
for the true/false values. I think they are necessary for checking and making sure that
there is not any mistake. In the future, they should get updated should there be any change.

1078. By Peter Haahr Taankvist

Clean up and making members final/static

1079. By Peter Haahr Taankvist

Use max function when finding highest degree

Revision history for this message
Peter Haahr Taankvist (ptaank) wrote :

Made the suggested changes, except for 2 comments. I left some comments in the diff.

Members are now static/final and I use the max function when calculating the highest degree.

review: Needs Resubmitting
Revision history for this message
Kenneth Yrke Jørgensen (yrke) :
review: Approve
1080. By Peter Taankvist <email address hidden>

add game as option for the engines and merge with trunk

1081. By Peter Taankvist <email address hidden>

Merge with trunk

Revision history for this message
Jiri Srba (srba) wrote :

Open Fisher's protocol from examples and make the query AF true.
This branch offers UPPAAL: Optimized Standard Reduction that should
not be offered - compare with e.g. 3.6.1 released version.

review: Needs Fixing
1082. By Peter Taankvist <email address hidden>

Add EngineOption for EG or AF with net degree > 2

1083. By Peter Taankvist <email address hidden>

Remove debug lines

Revision history for this message
Peter Haahr Taankvist (ptaank) wrote :

Added option for a query with AF or EG and with net degree > 2.

review: Needs Resubmitting
Revision history for this message
Jiri Srba (srba) wrote :

Please, remove the debugging information like:

4
UPPAAL: Optimized Broadcast Reduction
UPPAAL: Optimised Standard Reduction
4
UPPAAL: Standard Reduction
4
UPPAAL: Broadcast Reduction
4
UPPAAL: Broadcast Degree 2 Reduction
4
...

review: Needs Fixing
1084. By Peter Haahr Taankvist

Remove more debug lines

Revision history for this message
Jiri Srba (srba) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/dk/aau/cs/model/tapn/TimedArcPetriNet.java'
--- src/dk/aau/cs/model/tapn/TimedArcPetriNet.java 2020-08-10 06:46:22 +0000
+++ src/dk/aau/cs/model/tapn/TimedArcPetriNet.java 2020-08-14 09:31:36 +0000
@@ -1,13 +1,10 @@
1package dk.aau.cs.model.tapn;1package dk.aau.cs.model.tapn;
22
3import java.util.ArrayList;3import java.util.*;
4import java.util.Arrays;
5import java.util.List;
64
7import dk.aau.cs.model.tapn.Bound.InfBound;5import dk.aau.cs.model.tapn.Bound.InfBound;
8import dk.aau.cs.util.IntervalOperations;6import dk.aau.cs.util.IntervalOperations;
9import dk.aau.cs.util.Require;7import dk.aau.cs.util.Require;
10import java.util.HashSet;
118
12public class TimedArcPetriNet {9public class TimedArcPetriNet {
13 private String name;10 private String name;
@@ -371,6 +368,14 @@
371 }368 }
372 return true;369 return true;
373 }370 }
371
372 public int getHighestNetDegree(){
373 int currentHighestNetDegree = 0;
374 for (TimedTransition t : this.transitions()) {
375 currentHighestNetDegree = Collections.max(Arrays.asList(currentHighestNetDegree, t.presetSize(), t.postsetSize()));
376 }
377 return currentHighestNetDegree;
378 }
374 379
375 public boolean isActive() {380 public boolean isActive() {
376 return isActive;381 return isActive;
377382
=== modified file 'src/dk/aau/cs/model/tapn/TimedArcPetriNetNetwork.java'
--- src/dk/aau/cs/model/tapn/TimedArcPetriNetNetwork.java 2020-08-04 06:34:24 +0000
+++ src/dk/aau/cs/model/tapn/TimedArcPetriNetNetwork.java 2020-08-14 09:31:36 +0000
@@ -505,6 +505,13 @@
505 return composedModel.value1().isDegree2();505 return composedModel.value1().isDegree2();
506 }506 }
507507
508 public int getHighestNetDegree(){
509 ITAPNComposer composer = new TAPNComposer(new MessengerImpl(), false);
510 Tuple<TimedArcPetriNet,NameMapping> composedModel = composer.transformModel(this);
511
512 return composedModel.value1().getHighestNetDegree();
513 }
514
508 public boolean isSharedPlaceUsedInTemplates(SharedPlace place) {515 public boolean isSharedPlaceUsedInTemplates(SharedPlace place) {
509 for(TimedArcPetriNet tapn : this.activeTemplates()){516 for(TimedArcPetriNet tapn : this.activeTemplates()){
510 for(TimedPlace timedPlace : tapn.places()){517 for(TimedPlace timedPlace : tapn.places()){
511518
=== added file 'src/pipe/gui/EngineSupportOptions.java'
--- src/pipe/gui/EngineSupportOptions.java 1970-01-01 00:00:00 +0000
+++ src/pipe/gui/EngineSupportOptions.java 2020-08-14 09:31:36 +0000
@@ -0,0 +1,51 @@
1package pipe.gui;
2
3import java.util.ArrayList;
4
5public class EngineSupportOptions {
6 public final String nameString;
7 public final boolean supportFastestTrace;
8 public final boolean supportDeadlockNetdegree2EForAG;
9 public final boolean supportDeadlockWithInhib;
10 public final boolean supportWeights;
11 public final boolean supportInhibArcs;
12 public final boolean supportUrgentTransitions;
13 public final boolean supportEGorAF;
14 public final boolean supportStrictNets;
15 public final boolean supportTimedNets;
16 public final boolean supportDeadlockNetdegreeGreaterThan2;
17 public final boolean supportGames;
18 public final boolean supportEGorAFWithNetDegreeGreaterThan2;
19
20 public final boolean[] optionsArray;
21 public EngineSupportOptions(String nameString, boolean supportFastestTrace, boolean supportDeadlockNetdegree2EForAG, boolean supportDeadlockEGorAF, boolean supportDeadlockWithInhib,
22 boolean supportWeights, boolean supportInhibArcs, boolean supportUrgentTransitions, boolean supportEGorAF, boolean supportStrictNets, boolean supportTimedNets,
23 boolean supportDeadlockNetdegreeGreaterThan2, boolean supportGames, boolean supportEGorAFWithNetDegreeGreaterThan2){
24 this.nameString = nameString;
25 this.supportFastestTrace = supportFastestTrace;
26 this.supportDeadlockNetdegree2EForAG = supportDeadlockNetdegree2EForAG;
27 this.supportDeadlockWithInhib = supportDeadlockWithInhib;
28 this.supportWeights = supportWeights;
29 this.supportInhibArcs = supportInhibArcs;
30 this.supportUrgentTransitions = supportUrgentTransitions;
31 this.supportEGorAF = supportEGorAF;
32 this.supportStrictNets = supportStrictNets;
33 this.supportTimedNets = supportTimedNets;
34 this.supportDeadlockNetdegreeGreaterThan2 = supportDeadlockNetdegreeGreaterThan2;
35 this.supportGames = supportGames;
36 this.supportEGorAFWithNetDegreeGreaterThan2 = supportEGorAFWithNetDegreeGreaterThan2;
37 this.optionsArray = new boolean[]{supportFastestTrace, supportDeadlockNetdegree2EForAG, supportDeadlockEGorAF, supportDeadlockWithInhib,
38 supportWeights, supportInhibArcs, supportUrgentTransitions, supportEGorAF, supportStrictNets, supportTimedNets, supportDeadlockNetdegreeGreaterThan2,
39 supportGames, supportEGorAFWithNetDegreeGreaterThan2};
40 }
41
42 public boolean areOptionsSupported(boolean[] queryOptions){
43 for(int i = 0; i < optionsArray.length; i++){
44 if(queryOptions[i] == true && optionsArray[i] != true){
45 return false;
46 }
47 }
48 return true;
49 }
50
51}
052
=== modified file 'src/pipe/gui/widgets/QueryDialog.java'
--- src/pipe/gui/widgets/QueryDialog.java 2020-08-10 06:46:22 +0000
+++ src/pipe/gui/widgets/QueryDialog.java 2020-08-14 09:31:36 +0000
@@ -41,10 +41,7 @@
41import pipe.dataLayer.Template;41import pipe.dataLayer.Template;
42import pipe.dataLayer.TAPNQuery.SearchOption;42import pipe.dataLayer.TAPNQuery.SearchOption;
43import pipe.dataLayer.TAPNQuery.TraceOption;43import pipe.dataLayer.TAPNQuery.TraceOption;
44import pipe.gui.CreateGui;44import pipe.gui.*;
45import pipe.gui.MessengerImpl;
46import pipe.gui.Verifier;
47import pipe.gui.Zoomer;
48import dk.aau.cs.TCTL.StringPosition;45import dk.aau.cs.TCTL.StringPosition;
49import dk.aau.cs.TCTL.TCTLAFNode;46import dk.aau.cs.TCTL.TCTLAFNode;
50import dk.aau.cs.TCTL.TCTLAGNode;47import dk.aau.cs.TCTL.TCTLAGNode;
@@ -214,22 +211,139 @@
214 private final HashMap<TimedArcPetriNet, DataLayer> guiModels;211 private final HashMap<TimedArcPetriNet, DataLayer> guiModels;
215 private QueryConstructionUndoManager undoManager;212 private QueryConstructionUndoManager undoManager;
216 private UndoableEditSupport undoSupport;213 private UndoableEditSupport undoSupport;
217 private final boolean isNetDegree2;214 private boolean isNetDegree2;
218 private final boolean hasInhibitorArcs;215 private int highestNetDegree;
216 private boolean hasInhibitorArcs;
219 private InclusionPlaces inclusionPlaces;217 private InclusionPlaces inclusionPlaces;
220 private TabContent.TAPNLens lens;218 private TabContent.TAPNLens lens;
221219
222 private final String name_verifyTAPN = "TAPAAL: Continous Engine (verifytapn)";220 private static final String name_verifyTAPN = "TAPAAL: Continous Engine (verifytapn)";
223 private final String name_COMBI = "UPPAAL: Optimized Broadcast Reduction";221 private static final String name_COMBI = "UPPAAL: Optimized Broadcast Reduction";
224 private final String name_OPTIMIZEDSTANDARD = "UPPAAL: Optimised Standard Reduction";222 private static final String name_OPTIMIZEDSTANDARD = "UPPAAL: Optimised Standard Reduction";
225 private final String name_STANDARD = "UPPAAL: Standard Reduction";223 private static final String name_STANDARD = "UPPAAL: Standard Reduction";
226 private final String name_BROADCAST = "UPPAAL: Broadcast Reduction";224 private static final String name_BROADCAST = "UPPAAL: Broadcast Reduction";
227 private final String name_BROADCASTDEG2 = "UPPAAL: Broadcast Degree 2 Reduction";225 private static final String name_BROADCASTDEG2 = "UPPAAL: Broadcast Degree 2 Reduction";
228 private final String name_DISCRETE = "TAPAAL: Discrete Engine (verifydtapn)";226 private static final String name_DISCRETE = "TAPAAL: Discrete Engine (verifydtapn)";
229 private final String name_UNTIMED = "TAPAAL: Untimed Engine (verifypn)";227 private static final String name_UNTIMED = "TAPAAL: Untimed Engine (verifypn)";
230 private boolean userChangedAtomicPropSelection = true;228 private boolean userChangedAtomicPropSelection = true;
231229 //In order: name of engine, support fastest trace, support deadlock with net degree 2 and (EF or AG), support deadlock with EG or AF, support deadlock with inhibitor arcs
232 private TCTLAbstractProperty newProperty;230 //support weights, support inhibitor arcs, support urgent transitions, support EG or AF, support strict nets, support timed nets/time intervals, support deadlock with net degree > 2
231 private final static EngineSupportOptions verifyTAPNOptions= new EngineSupportOptions(
232 name_verifyTAPN, //name of engine
233 false, // support fastest trace
234 false, // support deadlock with net degree 2 and (EF or AG)
235 false, // support deadlock with EG or AF
236 false, // support deadlock with inhibitor arcs
237 false, //support weights
238 true, //support inhibitor arcs
239 false, // support urgent transitions
240 false, // support EG or AF
241 true, // support strict nets
242 true, // support timed nets/time intervals
243 false,// support deadlock with net degree > 2
244 false, //support games
245 false);//support EG or AF with net degree > 2
246
247 private final static EngineSupportOptions UPPAALCombiOptions= new EngineSupportOptions(
248 name_COMBI,//name of engine
249 false,// support fastest trace
250 true,// support deadlock with net degree 2 and (EF or AG)
251 false,// support deadlock with EG or AF
252 false,// support deadlock with inhibitor arcs
253 true, //support weights
254 true, //support inhibitor arcs
255 true,// support urgent transitions
256 true,// support EG or AF
257 true,// support strict nets
258 true,// support timed nets/time intervals
259 false,// support deadlock with net degree > 2
260 false, //support games
261 true);//support EG or AF with net degree > 2);
262
263 private final static EngineSupportOptions UPPAALOptimizedStandardOptions = new EngineSupportOptions(
264 name_OPTIMIZEDSTANDARD,//name of engine
265 false,// support fastest trace
266 false,// support deadlock with net degree 2 and (EF or AG)
267 false,// support deadlock with EG or AF
268 false,// support deadlock with inhibitor arcs
269 false, //support weights
270 false, //support inhibitor arcs
271 false,// support urgent transitions
272 true,// support EG or AF
273 true,// support strict nets
274 true,// support timed nets/time intervals
275 false,// support deadlock with net degree > 2
276 false, //support games
277 false);//support EG or AF with net degree > 2);
278
279 private final static EngineSupportOptions UPPAAALStandardOptions = new EngineSupportOptions(
280 name_STANDARD,//name of engine
281 false,// support fastest trace
282 false,// support deadlock with net degree 2 and (EF or AG)
283 false,// support deadlock with EG or AF
284 false,// support deadlock with inhibitor arcs
285 false, //support weights
286 false, //support inhibitor arcs
287 false,// support urgent transitions
288 false,// support EG or AF
289 true,// support strict nets
290 true,// support timed nets/time intervals
291 false,// support deadlock with net degree > 2
292 false, //support games
293 false);//support EG or AF with net degree > 2);
294
295 private final static EngineSupportOptions UPPAALBroadcastOptions = new EngineSupportOptions(
296 name_BROADCAST,//name of engine
297 false,// support fastest trace
298 true,// support deadlock with net degree 2 and (EF or AG)
299 false,// support deadlock with EG or AF
300 false,// support deadlock with inhibitor arcs
301 false, //support weights
302 true, //support inhibitor arcs
303 false,// support urgent transitions
304 true,// support EG or AF
305 true,// support strict nets
306 true,// support timed nets/time intervals
307 false,// support deadlock with net degree > 2
308 false, //support games
309 true);//support EG or AF with net degree > 2);
310
311 private final static EngineSupportOptions UPPAALBroadcastDegree2Options = new EngineSupportOptions(
312 name_BROADCASTDEG2,//name of engine
313 false,// support fastest trace
314 true,// support deadlock with net degree 2 and (EF or AG)
315 false,// support deadlock with EG or AF
316 false,// support deadlock with inhibitor arcs
317 false, //support weights
318 true, //support inhibitor arcs
319 false,// support urgent transitions
320 true,// support EG or AF
321 true,// support strict nets
322 true,// support timed nets/time intervals
323 false,// support deadlock with net degree > 2
324 false, //support games
325 true);//support EG or AF with net degree > 2);
326
327 private final static EngineSupportOptions verifyDTAPNOptions= new EngineSupportOptions(
328 name_DISCRETE,//name of engine
329 true,// support fastest trace
330 true,// support deadlock with net degree 2 and (EF or AG)
331 true,// support deadlock with EG or AF
332 true,// support deadlock with inhibitor arcs
333 true, //support weights
334 true, //support inhibitor arcs
335 true,// support urgent transitions
336 true,// support EG or AF
337 false,// support strict nets
338 true,// support timed nets/time intervals
339 true,// support deadlock with net degree > 2
340 true, //support games
341 true);//support EG or AF with net degree > 2);
342
343 //private final static EngineSupportOptions verifyPNOptions= new EngineSupportOptions(name_UNTIMED,false, true, true,true,true,true,false,true,false, false, false);
344 private final static EngineSupportOptions[] engineSupportOptions = new EngineSupportOptions[]{verifyDTAPNOptions,verifyTAPNOptions,UPPAALCombiOptions,UPPAALOptimizedStandardOptions,UPPAAALStandardOptions,UPPAALBroadcastOptions,UPPAALBroadcastDegree2Options,/*verifyPNOptions*/};
345
346 private TCTLAbstractProperty newProperty;
233 private JTextField queryName;347 private JTextField queryName;
234348
235 private static Boolean advancedView = false;349 private static Boolean advancedView = false;
@@ -333,6 +447,7 @@
333 newProperty = queryToCreateFrom == null ? new TCTLPathPlaceHolder() : queryToCreateFrom.getProperty();447 newProperty = queryToCreateFrom == null ? new TCTLPathPlaceHolder() : queryToCreateFrom.getProperty();
334 rootPane = me.getRootPane();448 rootPane = me.getRootPane();
335 isNetDegree2 = tapnNetwork.isDegree2();449 isNetDegree2 = tapnNetwork.isDegree2();
450 highestNetDegree = tapnNetwork.getHighestNetDegree();
336 hasInhibitorArcs = tapnNetwork.hasInhibitorArcs();451 hasInhibitorArcs = tapnNetwork.hasInhibitorArcs();
337452
338 setLayout(new GridBagLayout());453 setLayout(new GridBagLayout());
@@ -707,12 +822,24 @@
707 ArrayList<String> options = new ArrayList<String>();822 ArrayList<String> options = new ArrayList<String>();
708 823
709 disableSymmetryUpdate = true;824 disableSymmetryUpdate = true;
825 //The order here should be the same as in EngineSupportOptions
826 boolean[] queryOptions = new boolean[]{fastestTraceRadioButton.isSelected(),
827 (queryHasDeadlock() && (getQuantificationSelection().equals("E<>") || getQuantificationSelection().equals("A[]")) && highestNetDegree <= 2),
828 (queryHasDeadlock() && (getQuantificationSelection().equals("E[]") || getQuantificationSelection().equals("A<>"))),
829 (queryHasDeadlock() && hasInhibitorArcs),
830 tapnNetwork.hasWeights(),
831 hasInhibitorArcs,
832 tapnNetwork.hasUrgentTransitions(),
833 (getQuantificationSelection().equals("E[]") || getQuantificationSelection().equals("A<>")),
834 //we want to know if it is strict
835 !tapnNetwork.isNonStrict(),
836 //we want to know if it is timed
837 lens.isTimed(),
838 (queryHasDeadlock() && highestNetDegree > 2),
839 lens.isGame(),
840 (getQuantificationSelection().equals("E[]") || getQuantificationSelection().equals("A<>")) && highestNetDegree > 2
841 };
710842
711 /* The untimed engine is disabled for now. It is used in the CTL query dialog
712 if(!fastestTraceRadioButton.isSelected() && (getQuantificationSelection().equals("E<>") || getQuantificationSelection().equals("A[]") || getQuantificationSelection().equals("")) && tapnNetwork.isUntimed()){
713 options.add(name_UNTIMED);
714 }
715 */
716 843
717 if(useTimeDarts != null){844 if(useTimeDarts != null){
718 if(hasForcedDisabledTimeDarts){845 if(hasForcedDisabledTimeDarts){
@@ -738,68 +865,24 @@
738 useGCD.setEnabled(true); 865 useGCD.setEnabled(true);
739 }866 }
740867
741 if (lens.isGame()) {868 if (tapnNetwork.isNonStrict()) {
742 if (tapnNetwork.isNonStrict()) {869 // disable timedarts if liveness and deadlock prop
743 options.add(name_DISCRETE);870 if((getQuantificationSelection().equals("E[]") ||
744 }871 getQuantificationSelection().equals("A<>"))){
745 } else if (fastestTraceRadioButton.isSelected()) {872 if (useTimeDarts != null) {
746 options.add(name_DISCRETE);873 if(useTimeDarts.isSelected()){
747 } else if (queryHasDeadlock()) {874 hasForcedDisabledTimeDarts = true;
748 if (tapnNetwork.isNonStrict()) {
749 options.add(name_DISCRETE);
750 // disable timedarts if liveness and deadlock prop
751 if((getQuantificationSelection().equals("E[]") ||
752 getQuantificationSelection().equals("A<>"))){
753 if (useTimeDarts != null) {
754 if(useTimeDarts.isSelected()){
755 hasForcedDisabledTimeDarts = true;
756 }
757 useTimeDarts.setEnabled(false);
758 useTimeDarts.setSelected(false);
759 }875 }
760 }876 useTimeDarts.setEnabled(false);
761 }877 useTimeDarts.setSelected(false);
762 if (getQuantificationSelection().equals("E<>") || getQuantificationSelection().equals("A[]")) {878 }
763 if (isNetDegree2 && !hasInhibitorArcs) {879 }
764 options.add(name_COMBI);880 }
765 if(!tapnNetwork.hasWeights() && !hasInhibitorArcs) {881 for(EngineSupportOptions engine : engineSupportOptions){
766 options.addAll(Arrays.asList(name_BROADCAST, name_BROADCASTDEG2));882 if(engine.areOptionsSupported(queryOptions)){
767 }883 options.add(engine.nameString);
768 }884 }
769 }885 }
770
771 } else if(tapnNetwork.hasWeights()){
772 if(tapnNetwork.isNonStrict()){
773 options.add(name_DISCRETE);
774 }
775 options.add(name_COMBI);
776 } else if(tapnNetwork.hasUrgentTransitions()){
777 if(tapnNetwork.isNonStrict()){
778 options.add(name_DISCRETE);
779 }
780 options.add(name_COMBI);
781 } else if (getQuantificationSelection().equals("E[]") || getQuantificationSelection().equals("A<>")) {
782 if(tapnNetwork.isNonStrict()){
783 options.add(name_DISCRETE);
784 }
785 options.add(name_COMBI);
786 if(isNetDegree2 && !hasInhibitorArcs)
787 options.addAll(Arrays.asList( name_BROADCAST, name_BROADCASTDEG2, name_OPTIMIZEDSTANDARD));
788 else
789 options.addAll(Arrays.asList(name_BROADCAST, name_BROADCASTDEG2));
790 } else if(tapnNetwork.hasInhibitorArcs()) {
791 options.add( name_verifyTAPN );
792 if(tapnNetwork.isNonStrict()){
793 options.add(name_DISCRETE);
794 }
795 options.addAll(Arrays.asList(name_COMBI, name_BROADCAST, name_BROADCASTDEG2 ));
796 } else {
797 options.add( name_verifyTAPN);
798 if(tapnNetwork.isNonStrict()){
799 options.add(name_DISCRETE);
800 }
801 options.addAll(Arrays.asList(name_COMBI, name_OPTIMIZEDSTANDARD, name_STANDARD, name_BROADCAST, name_BROADCASTDEG2));
802 }
803886
804 reductionOption.removeAllItems();887 reductionOption.removeAllItems();
805888

Subscribers

People subscribed via source and target branches