Skip to content
Snippets Groups Projects
Commit 52f37bd5 authored by Eddie Groh's avatar Eddie Groh
Browse files

Merge remote-tracking branch 'origin/master' into 4310

parents daf4e1da c5387333
No related branches found
No related tags found
1 merge request!210Setting up Metric extraction plugin for AF3 : Issue 4310
Showing
with 203 additions and 33 deletions
......@@ -2,6 +2,6 @@ AdvancedTreeViewerEditorBase.java 9d9eded6848ee78991d1416592d1136efd71d2b7 GREEN
FormsEditorBase.java b113501b98ffffcac362ca9f474ad02a42bde186 GREEN
GEFEditorBase.java e668f596f45f07215994cbbd3929a9438331718f GREEN
SourceEditorBase.java 47e69e2e6788b9897339c384cd03f9a22755037c GREEN
SourceEditorConfigurationBase.java e8b810c0d974c475f0a8e6f21aa5b6fd9e17c33a GREEN
SourceEditorConfigurationBase.java 67c674248e31d467937ed33e455c07587ad0b3b1 GREEN
SourceEditorUndoRedo.java 08127a8e0afb4f9c2f4c21294ca3220282c25bf0 GREEN
TreeViewerEditorBase.java 1c59689ff57c4f3cc180d85f13021fc03461ecb0 GREEN
/*-------------------------------------------------------------------------+
| Copyright 2012 fortiss GmbH |
| Copyright 2023 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
......@@ -19,6 +19,7 @@ import static java.lang.Character.isLetterOrDigit;
import static org.eclipse.jface.text.IDocument.DEFAULT_CONTENT_TYPE;
import static org.eclipse.wb.swt.SWTResourceManager.getColor;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.emf.ecore.EObject;
......@@ -29,6 +30,7 @@ import org.eclipse.jface.text.rules.IRule;
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.ITokenScanner;
import org.eclipse.jface.text.rules.IWordDetector;
import org.eclipse.jface.text.rules.PatternRule;
import org.eclipse.jface.text.rules.RuleBasedScanner;
import org.eclipse.jface.text.rules.WordRule;
import org.eclipse.jface.text.source.IAnnotationHover;
......@@ -53,12 +55,21 @@ public abstract class SourceEditorConfigurationBase<T extends EObject>
this.editor = editor;
}
/** Color constant used to display code dark red. */
/** Color constant used to display code in dark red. */
protected Color DARK_RED = getColor(128, 0, 0);
/** Color constant used to display code dark blue. */
/** Color constant used to display code in dark blue. */
protected Color DARK_BLUE = getColor(0, 0, 128);
/** Color constant used to display comments (green). */
protected Color COMMENT_COLOR = getColor(0, 148, 0);
/** Identifier for the start of a comment. */
public static final String COMMENT_START_IDENTIFIER = "/*";
/** Identifier for the end of a comment. */
public static final String COMMENT_END_IDENTIFIER = "*/";
/** Detector used to create the scanners. */
protected IWordDetector detector = new IWordDetector() {
/** {@inheritDoc} */
......@@ -99,10 +110,17 @@ public abstract class SourceEditorConfigurationBase<T extends EObject>
/** Returns the rule based scanner. */
private RuleBasedScanner getScannerForSyntaxHighlighting() {
List<WordRule> rules = getCommonRules();
rules.add(getRuleSpecificToEditor());
List<IRule> allRules = new ArrayList<IRule>();
allRules.addAll(getCommonRules());
allRules.add(getRuleSpecificToEditor());
allRules.add(getCommentRuleSpecificToEditor());
IRule[] rules = allRules.toArray(new IRule[0]);
RuleBasedScanner scanner = new RuleBasedScanner();
scanner.setRules(rules.toArray(new IRule[0]));
scanner.setRules(rules);
return scanner;
}
......@@ -112,6 +130,9 @@ public abstract class SourceEditorConfigurationBase<T extends EObject>
/** Returns a rule specific to the editor. */
abstract protected WordRule getRuleSpecificToEditor();
/** Returns the comment rule specific to the editor. */
abstract protected PatternRule getCommentRuleSpecificToEditor();
/** Adds the words to the rule with the given token. */
protected void addWordsToRule(List<String> words, WordRule rule, IToken token) {
for(String word : words) {
......
......@@ -5,7 +5,7 @@ DynamicTextFieldTreeTableCell.java 62fa0c08b11d87e0eed41f84be85505c2740e75d GREE
DynamicTreeContentProviderBase.java 91896b1fb5104d126544c44c1ff8c30f2a13a8d6 GREEN
DynamicTreeItem.java 7e81ea98038b5eca90df583e0268d4e8f37aaf25 GREEN
DynamicTreeItemBase.java d883066ecc181120302ca32f328538de7a45b093 GREEN
DynamicTreeTableUIProviderBase.java 360df9d5114c5d4a391a7a7afe70a5b8ad584490 GREEN
DynamicTreeTableUIProviderBase.java c52a1f9598de25874f83c133a8cbbcddc86442e9 GREEN
DynamicTreeTableViewer.java 77e9995a3bee37d57578dad9434a53c702128efa YELLOW
DynamicTreeUIProviderBase.java 82d3c051213f0147f4c67ad247a08696cee73110 GREEN
DynamicTreeViewer.java 33066062a82101cf28410e4d04f85bb9c24251db GREEN
......
......@@ -15,6 +15,8 @@ package org.fortiss.tooling.common.ui.javafx.control.treetableview;
import static java.util.stream.Collectors.toMap;
import static javafx.collections.FXCollections.observableArrayList;
import static javafx.scene.text.Font.font;
import static javafx.util.Duration.seconds;
import static org.apache.commons.lang3.SystemUtils.IS_OS_LINUX;
import java.util.Map;
......@@ -28,6 +30,7 @@ import javafx.scene.Node;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableColumn;
......@@ -40,6 +43,8 @@ import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.util.Callback;
import javafx.util.converter.DefaultStringConverter;
......@@ -64,6 +69,22 @@ public abstract class DynamicTreeTableUIProviderBase<T> {
return "";
}
/**
* Retrieves the tooltip text which shall be displayed for the given element in the given
* column.
*
* No tooltip will be displayed, if this method return 'null'.
*
* @param element
* The element to get a tooltip for.
* @param column
* The column index for which to get a tooltip.
* @return The tooltip as a {@link String}.
*/
public String getTooltip(T element, int column) {
return null;
}
/**
* Determines, which {@link String} is in text editor cells when stating to edit.
*
......@@ -324,6 +345,31 @@ public abstract class DynamicTreeTableUIProviderBase<T> {
cell.setStyle(getCellStyle(data, columnIndex));
addContextMenuToCell(cell, columnIndex);
// For non-icon cells, enable line-break.
if(icon == null) {
Text text = new Text(cell.getText());
text.setStyle("-fx-text-alignment:justify;");
// Ensure some space to next column to the right.
int lineWrapBorder = 5;
text.wrappingWidthProperty()
.bind(cell.getTableColumn().widthProperty().subtract(lineWrapBorder));
cell.setGraphic(text);
}
// Add tooltip
final String tooltipStr = getTooltip(data, columnIndex);
if(tooltipStr != null) {
Tooltip tt = new Tooltip();
double fontSize = 14.0;
Font font = font(fontSize);
tt.setText(tooltipStr);
tt.setShowDuration(seconds(15));
tt.setFont(font);
cell.setTooltip(tt);
}
} else {
// reset icon for cases, in which a row was styled before, but became empty by now.
cell.setGraphic(null);
......
PrototypeProvider.java 76ee1b194635f76b1ca09f93ac37f8155b53ddb5 GREEN
PrototypeProvider.java 8396bb14c2ae9d820b822c43a9a9ab52cb8e8a93 GREEN
/*-------------------------------------------------------------------------+
| Copyright 2021 fortiss GmbH |
| Copyright 2023 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
......@@ -15,8 +15,11 @@
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.ext.reuse.ui.prototypes;
import static org.fortiss.tooling.ext.reuse.ui.ToolingReuseUIActivator.getDefault;
import static org.fortiss.tooling.ext.reuse.utils.ReuseLibraryUtilsBasics.getAllLocalReuseLibraries;
import static org.fortiss.tooling.ext.reuse.utils.ReuseLibraryUtilsBasics.getReuseElementName;
import static org.fortiss.tooling.kernel.utils.LoggingUtils.error;
import static org.fortiss.tooling.kernel.utils.LoggingUtils.showError;
import java.util.List;
......@@ -47,13 +50,24 @@ public final class PrototypeProvider extends PrototypeProviderBase {
return;
}
// register all elements of all found libraries (and the libraries themselves)
// Register all elements of all found libraries (and the libraries themselves).
for (ReuseLibrary library : libraryList) {
String libraryName = getReuseElementName(library);
// the library name is also used now as the category name for all contained
// reuse elements of this library
registerPrimaryPrototype(libraryName, library, libraryName);
// The library name is also used as the category name for all contained
// reuse elements of this library.
String categoryName = libraryName;
registerPrimaryPrototype(libraryName, library, categoryName);
// Library categories should have a lower priority than standard prototype
// categories (like "Behavioral Specification" elements).
try {
setPrototypeCategoryPriority(categoryName, -10);
} catch (IllegalArgumentException e) {
// Only in case someone changes registerPrimaryPrototype().
error(getDefault(),
"Error setting the category priority for the reuse library '" + categoryName + "'.", e);
showError("Cannot set category priortiy for '" + categoryName + "'.");
}
EList<EObject> reuseElementList = library.getReuseElementList();
for (EObject libraryElement : reuseElementList) {
......
AlternativeConfigurationEditingSupport.java 209d1e382a150d03f6f05fbe8303ba8d521be0f0 GREEN
AlternativeConfigurationEditingSupport.java adad0c5bb115c8c394bcd220135e9584a97e8aca GREEN
AlternativeVariationPointEditor.java 2c2d3d3779919ab033961075835e571350b7f7e2 GREEN
AlternativesNamesEditingSupport.java f70f92388dc6038c8f00097c8c0331d52e9ea9c0 GREEN
CheckBoxLabelProvider.java b810b06ec113dc499cb6f897d9515a067327bdb4 GREEN
......
......@@ -140,7 +140,7 @@ public class AlternativeConfigurationEditingSupport extends EditingSupport {
protected void setValue(final Object element, final Object value) {
// Case distinction for the type of the assigned value
if(value instanceof String) {
setValueString(element, (AbstractFeature)value);
setValueString(element, (String)value);
return;
}
......@@ -222,7 +222,7 @@ public class AlternativeConfigurationEditingSupport extends EditingSupport {
}
/** Sets the new value on the given AbstractFeature element. */
private void setValueString(final Object element, final AbstractFeature value) {
private void setValueString(final Object element, final String value) {
// The only String, that might be selected is OPTIONAL_FEATURE_DESELECTED_LABEL
assert (value).equals(OPTIONAL_ALTERNATIVE_NOT_SELECTED_STRING);
// ... which shall only be there for AlternativeFeatureConfiguration
......
CrossFeatureConstraintPropertySectionBase.java 37e772fb3471f85320170d373cbe2f319c350655 GREEN
FeaturePropertySectionBase.java 2ac0a6a56ea4755852fd14a9b5df81dff4a5dc7e GREEN
FeaturePropertySectionBase.java 598842b12b5bbb6f3cf2461a4d05fc721b637f54 GREEN
HasPresenceConditionPropertySectionBase.java ef300f0d9294d76f5d80e45b8cc0d94c24586a24 GREEN
......@@ -28,6 +28,7 @@ import org.fortiss.tooling.kernel.service.ICommandStackService;
import org.fortiss.tooling.kernel.ui.extension.base.PropertySectionBase;
import org.fortiss.variability.model.features.AbstractAlternativeFeature;
import org.fortiss.variability.model.features.AbstractFeature;
import org.fortiss.variability.model.features.AbstractFeatureModel;
/**
* Property Section for {@link AbstractFeature}s.
......@@ -52,10 +53,13 @@ public class FeaturePropertySectionBase extends PropertySectionBase {
feature = (AbstractFeature)input;
if(optionalCheckbox != null) {
if(feature.eContainer() instanceof AbstractAlternativeFeature) {
if(feature.eContainer() instanceof AbstractAlternativeFeature ||
feature instanceof AbstractFeatureModel) {
optionalCheckbox.setEnabled(false);
} else
} else {
optionalCheckbox.setEnabled(true);
optionalCheckbox.setSelection(feature.isOptional());
}
}
}
}
......
VariabilityUtils.java 6f2ffd231c27f5f7ab8c62d05350c0a92392eaf8 GREEN
VariabilityUtils.java fcaa561bdbe6bd9d6fff4312086a6c97177301f8 GREEN
......@@ -18,6 +18,8 @@ package org.fortiss.tooling.ext.variability.util;
import static org.fortiss.tooling.ext.variability.model.VariabilityModelElementFactory.createOptionalVariationPointSpecification;
import static org.fortiss.tooling.kernel.utils.EcoreUtils.getFirstChildWithType;
import static org.fortiss.tooling.kernel.utils.EcoreUtils.pickFirstInstanceOf;
import static org.fortiss.variability.util.VariabilityUtils.FEATURE_LITERAL_LEGAL_CHAR_REGEX;
import static org.fortiss.variability.util.VariabilityUtils.PRESENCE_CONDITIONS_KEYWORDS;
import org.eclipse.emf.ecore.EObject;
import org.fortiss.tooling.base.model.element.IModelElement;
......@@ -35,6 +37,12 @@ import org.fortiss.variability.presence.compiler.PresenceConditionCompiler;
*/
public class VariabilityUtils {
/** Failure message for incorrect Feature names. */
public final static String FEATURE_NAME_ERROR_MSG = "Feature names may only contain " +
FEATURE_LITERAL_LEGAL_CHAR_REGEX.replaceAll("\\\\", "") +
", must not be empty and must be different from the keywords " +
PRESENCE_CONDITIONS_KEYWORDS.replaceAll("\\|", ", ") + ".";
/**
* Checks for the given {@link EObject} whether it has been deactivated by a
* {@link DeactivationSpecification}.
......
......@@ -3,6 +3,6 @@ ConstraintViolationBase.java ec66973ab2183623f0cd4a85c59c886dddad6cf6 GREEN
DialogMessage.java 8420640e999e4fb15fa644333e5d71e1d16c2559 GREEN
ElementCompositorBase.java 7a445e5adde11878fe0515baca8b915287149b28 GREEN
MultiViolationConstraintCheckerBase.java 30886a94c99cf8948f64401b1db821abe06e1e6c GREEN
PrototypeProviderBase.java 3fb24d4bca697359a7c74da166ff8a674b675404 GREEN
PrototypeProviderBase.java 4625d5ed40d3bcadfc6dda3ed4cc1f3873a23307 GREEN
TransformationContextChainBase.java 1ef37880ab275778c563928e80ba378fec964cb6 GREEN
TransformationProviderBase.java 9e91100cc1f2c8fbd8d41af55aedfea34e02ff71 GREEN
/*-------------------------------------------------------------------------+
| Copyright 2011 fortiss GmbH |
| Copyright 2023 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
......@@ -123,6 +123,22 @@ public abstract class PrototypeProviderBase implements IPrototypeProvider {
return cat;
}
/**
* Sets the priority of the given prototype category. If the category does not exist, a
* {@link IllegalArgumentException} is thrown. Only needed if the category should be sorted
* based on the new priority and not by name.
*/
protected void setPrototypeCategoryPriority(String category, int priority)
throws IllegalArgumentException {
PrototypeCategory cat = categories.get(category);
if(cat == null) {
throw new IllegalArgumentException(
"Cannot set category priority since no prototype category exists with the given name '" +
category + "'.");
}
cat.setPriority(priority);
}
/** {@inheritDoc} */
@Override
public List<PrototypeCategory> getCategories() {
......
......@@ -8,7 +8,7 @@ LogMessage.java 14204ed9d51b356f50be52362247cfbbe0cbd5c7 GREEN
ModelElementTransformationContext.java 5a41bd3a75ce434c3174d50d2fdfab28b66f09f2 GREEN
ModelStorageError.java 2aef480044047e960e64811111a7f27310011cc2 GREEN
Prototype.java 5b91ecc45950569a19371470d0e3ae44cca86cf3 GREEN
PrototypeCategory.java 718124d0a6a390331bea7ccb45c2eaa3c31a9002 GREEN
PrototypeCategory.java ca500b4816ed42b9536488669aeab89561d2f08c GREEN
TransformationProviderChain.java 67ec6d0b4c23d295323572649606d79f3b897437 GREEN
TutorialAtomicStep.java 09c0d6597d542b431b5bbdc790ee9e533d9f77fb GREEN
TutorialCompositeStep.java cc61c2e86eff310762acac4d023fd709507355c8 GREEN
......
/*-------------------------------------------------------------------------+
| Copyright 2012 fortiss GmbH |
| Copyright 2023 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
......@@ -31,6 +31,9 @@ public class PrototypeCategory {
/** Stores the parent of the category. */
private PrototypeCategory parentCategory;
/** Stores the priority of the category. Is important for sorting: lower value = lower prio. */
private int categoryPriority;
/** Stores the prototypes affiliated with this category. */
private List<Prototype> children = new ArrayList<Prototype>();
......@@ -40,6 +43,17 @@ public class PrototypeCategory {
/** Constructor. */
public PrototypeCategory(String category) {
categoryName = category;
categoryPriority = 0;
}
/** Returns the priority of the category. */
public int getPriority() {
return categoryPriority;
}
/** Sets the priority of the category. */
public void setPriority(int priority) {
categoryPriority = priority;
}
/** Adds the prototype. */
......
......@@ -7,7 +7,7 @@ ElementCompositorService.java b1924b5b349118a70149cfac5b48544897d26e9e GREEN
LoggingService.java da784259f7b456b54bf75c41ec268f64919ce78d GREEN
MigrationService.java 017c8438262065f663427a998536035bc7732fe1 GREEN
PersistencyService.java f33993962d83b08df767da501cb11c14d37a7c19 GREEN
PrototypeService.java 9250b754a76d6791a89fc9aba20cc89255386274 GREEN
PrototypeService.java 4b82fd438f26fafaf225b35c734c2976b738e512 GREEN
ToolingKernelInternal.java afbd2ccb5277ffdaa5e8d6b901dc10b61ef4a36d GREEN
TransformationService.java 64ee4fb5ccc623f8acfba20866fc2b0944c4adab GREEN
TutorialService.java 675d3f365ce062869f86baa3779d50687674bda0 GREEN
/*-------------------------------------------------------------------------+
| Copyright 2011 fortiss GmbH |
| Copyright 2023 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
......@@ -16,6 +16,7 @@
package org.fortiss.tooling.kernel.internal;
import static java.util.Collections.emptyList;
import static java.util.Collections.reverse;
import static java.util.Collections.sort;
import static java.util.Collections.unmodifiableList;
import static org.conqat.lib.commons.collections.CollectionUtils.asUnmodifiable;
......@@ -236,9 +237,10 @@ public class PrototypeService implements IPrototypeService, IIntrospectiveKernel
}
}
Comparator<PrototypeCategory> lexicographicalComparator = (PrototypeCategory category1,
PrototypeCategory category2) -> category1.getName().compareTo(category2.getName());
sort(result, lexicographicalComparator);
// Sort first by priority and then by name (lexicographical).
sort(result, new PrototypeCategoryComparator());
// Reverse to get a descending order (highest prio at first / on top).
reverse(result);
return result;
}
......@@ -266,4 +268,28 @@ public class PrototypeService implements IPrototypeService, IIntrospectiveKernel
public IIntrospectionDetailsItem getDetailsItem() {
return new PrototypeKISSDetailsItem(prototypeProviderList);
}
/**
* Comparator that can compare prototype categories based on their 1.) priority and 2.) their
* name (lexicographical). The comparison order is ascending. This means a negative integer is
* returned, if category1 is "less" than category2 ( = category1 has lower priority or, in case
* of identical priorities, is lexicographically AFTER category2). Otherwise, a positive integer
* is returned, except both categories have identical priorities AND identical names, in which
* case zero is returned.
* Note: The lexicographical order is reversed (<A,B> = "A greater than B" = positive integer).
*/
static class PrototypeCategoryComparator implements Comparator<PrototypeCategory> {
/** {@inheritDoc} */
@Override
public int compare(PrototypeCategory category1, PrototypeCategory category2) {
int result = category1.getPriority() - category2.getPriority();
if(result == 0) {
// Negate integer to have the case that the order <A, B> corresponds to "A is
// greater than B" (= positive)
result = -category1.getName().compareTo(category2.getName());
}
return result;
}
}
}
FeatureModelTransformationUtils.java b38702296dcb48ff311b382bb9c05d2590e2dfac GREEN
Pair.java 2dfd7dc65f7b9ba09a120f1a6058d1e8e9556a37 GREEN
VariabilityUtils.java 66a727bdb58715dc7b1bd0ce320bd647f374f7d6 GREEN
VariabilityUtils.java 3e57a37ced6396076c71227aea8de534381b6ace GREEN
VariabilityUtilsInternal.java 9c781a47513bb0c4ddcd13be1c27d62b70f25998 GREEN
......@@ -17,6 +17,7 @@ package org.fortiss.variability.util;
import static java.util.stream.Collectors.toList;
import static org.fortiss.variability.model.VariabilityModelElementFactory.createFeatureConfigurationForFeature;
import static org.fortiss.variability.util.VariabilityUtilsInternal.getAllElementsFromSameContainmentTree;
import static org.fortiss.variability.util.VariabilityUtilsInternal.getAllReferences;
import static org.fortiss.variability.util.VariabilityUtilsInternal.getParentsWithType;
......@@ -27,6 +28,7 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.fortiss.variability.model.features.AbstractCompositionalFeature;
import org.fortiss.variability.model.features.AbstractCrossFeatureConstraint;
import org.fortiss.variability.model.features.AbstractFeature;
......@@ -163,14 +165,15 @@ public class VariabilityUtils {
*
* @param literalName
* {@link String} with the name to be checked.
* @return Whether the given name is compatible with the presence condition systax.
* @return Whether the given name is compatible with the presence condition syntax.
*/
public static boolean isNameLegalInPresenceCondition(String literalName) {
if(literalName.matches(PRESENCE_CONDITIONS_KEYWORDS)) {
return false;
}
return literalName.matches(FEATURE_LITERAL_LEGAL_CHAR_REGEX + "*");
// Add "+" to regex to make only non-empty names legal (instead of "*")
return literalName.matches(FEATURE_LITERAL_LEGAL_CHAR_REGEX + "+");
}
/**
......@@ -192,4 +195,22 @@ public class VariabilityUtils {
features.removeAll(getParentsWithType(constraint, AbstractFeature.class));
return features;
}
/**
* Retrieves all literals with the given name from the whole containment tree in which 'context'
* is contained in.
*
* Note, that the resulting {@link List} should usually contain at most one literal, as literal
* names should be unique.
*
* @param context
* Any {@link EObject} in the containment tree to search in.
* @param name
* The name of the literal which is searched.
* @return A {@link List} of all literals with the given name.
*/
public static List<ILiteralReferencable> getLiteralsWithName(EObject context, String name) {
return getAllElementsFromSameContainmentTree(context, ILiteralReferencable.class).stream()
.filter(l -> l.getName().equals(name)).collect(toList());
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment