From 6733b12e3bc918c8a1ff801badc8fa5a635763b0 Mon Sep 17 00:00:00 2001 From: Florian Hoelzl <hoelzl@fortiss.org> Date: Tue, 29 May 2018 11:20:50 +0200 Subject: [PATCH] Fixed code generation. Signed-off-by: Florian Hoelzl <hoelzl@fortiss.org> --- .../raspberry/generator/executable/.ratings | 2 +- .../executable/ConsoleOutputExecutable.java | 22 +++++++-------- .../executable/SingleUnitMainGenerator.java | 27 ++++++++++++------- .../generator/executable/framework/.ratings | 2 +- .../framework/IReadableExecutable.java | 9 ++++--- .../generator/executable/gamepad/.ratings | 6 ++--- .../gamepad/ButtonExecutableBase.java | 5 ++-- .../gamepad/GamepadExecutableBase.java | 3 +-- .../gamepad/StickExecutableBase.java | 5 ++-- .../generator/executable/rumblepad/.ratings | 6 ++--- .../rumblepad/ButtonExecutableBase.java | 5 ++-- .../rumblepad/RumblepadExecutableBase.java | 3 +-- .../rumblepad/StickExecutableBase.java | 5 ++-- 13 files changed, 55 insertions(+), 45 deletions(-) diff --git a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/.ratings b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/.ratings index 49e6435e..1afd8cd3 100644 --- a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/.ratings +++ b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/.ratings @@ -1,7 +1,7 @@ CanBusExecutable.java a6d7a7767a1eae9770007e98115ead912f8a6e47 RED CanConnectorExecutable.java ed13a0d5b71eae473ddec911cb572780660c85a4 RED CanTransmissionCatalog.java ec4637eda80234429a9f382a37713588a0fbb83a RED -ConsoleOutputExecutable.java 5b8c50f2236ad49958a0a0b599a7e60265a6fc06 YELLOW +ConsoleOutputExecutable.java b44f1802331d7795949e939366864fcf0edc0696 YELLOW HeaderCopyGenerator.java 18239a3adae35256e32dad19df9d8f38acbf7e66 RED MultiUnitMainGenerator.java 458754b89c2d79db3fee08baa444424772e40fb7 RED PWMActuatorExecutable.java dbcd7dbf46f7778cce7b52e659646d59ae7a2b3e YELLOW diff --git a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/ConsoleOutputExecutable.java b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/ConsoleOutputExecutable.java index 5b8c50f2..bc5797d7 100644 --- a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/ConsoleOutputExecutable.java +++ b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/ConsoleOutputExecutable.java @@ -15,21 +15,16 @@ +--------------------------------------------------------------------------*/ package org.fortiss.af3.platform.raspberry.generator.executable; -import static org.fortiss.af3.expression.utils.ExpressionModelElementFactory.funcCall; -import static org.fortiss.af3.expression.utils.ExpressionModelElementFactory.stringConst; - import org.fortiss.af3.component.model.OutputPort; -import org.fortiss.af3.expression.model.terms.IExpressionTerm; -import org.fortiss.af3.expression.model.terms.StringConst; import org.fortiss.af3.expression.model.types.TDouble; import org.fortiss.af3.platform.language.executable.ExecutableBase; -import org.fortiss.af3.platform.language.executable.IWritableExecutableWithNoValSupport; +import org.fortiss.af3.platform.raspberry.generator.executable.framework.IWriteableExecutable; import org.fortiss.af3.platform.raspberry.model.ConsoleOutput; import org.fortiss.af3.project.model.typesystem.IType; /** Executable for {@link ConsoleOutput}. */ public class ConsoleOutputExecutable extends ExecutableBase<ConsoleOutput> implements - IWritableExecutableWithNoValSupport { + IWriteableExecutable { /** Constructor. */ public ConsoleOutputExecutable(ConsoleOutput modelElement) { super(modelElement); @@ -37,10 +32,11 @@ public class ConsoleOutputExecutable extends ExecutableBase<ConsoleOutput> imple /** {@inheritDoc} */ @Override - public IExpressionTerm getValueWriteAccessor(OutputPort logicalSignal, IExpressionTerm value) { + public String getWriteCode(String prefix, String singletonPrefix, OutputPort logicalSignal, + String value) { String typeFormat = getTypeFormat(logicalSignal.getVariableType()); - StringConst format = stringConst(logicalSignal.getName() + " = " + typeFormat + "\n"); - return funcCall("printf", format, value); + String name = logicalSignal.getName(); + return "printf(\"" + name + " = " + typeFormat + "\\n\", " + value + ");\n"; } /** Returns the C format string for the given type. */ @@ -53,8 +49,8 @@ public class ConsoleOutputExecutable extends ExecutableBase<ConsoleOutput> imple /** {@inheritDoc} */ @Override - public IExpressionTerm getNoValWriteAccessor(OutputPort logicalSignal) { - StringConst format = stringConst(logicalSignal.getName() + " = NoVal"); - return funcCall("printf", format); + public String + getNoValWriteCode(String prefix, String singletonPrefix, OutputPort logicalSignal) { + return "printf(\"" + logicalSignal.getName() + " = NoVal\\n\");\n"; } } diff --git a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/SingleUnitMainGenerator.java b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/SingleUnitMainGenerator.java index 6f019af4..3c704f64 100644 --- a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/SingleUnitMainGenerator.java +++ b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/SingleUnitMainGenerator.java @@ -15,6 +15,8 @@ +--------------------------------------------------------------------------*/ package org.fortiss.af3.platform.raspberry.generator.executable; +import static org.fortiss.af3.component.generator.c.ComponentProgramToCSourcePackageTransformation.getPortNoValIdentifier; +import static org.fortiss.af3.component.generator.component.PortVariableUtils.getPortIdentifier; import static org.fortiss.af3.platform.raspberry.generator.templates.RasPiCTemplates.getSingleUnitMainCFile; import java.util.HashMap; @@ -291,11 +293,6 @@ class SingleUnitMainGenerator { // } // } - /** Returns the port and ID identifier. */ - private String portName(Port port) { - return port.getName().replace(' ', '_') + "_ID_" + port.getId(); - } - /** Creates the read code for the given receiver and port. */ private String createWriteCode(Transmitter transmitter, OutputPort outport) { ExecutableBase<?> exec = platformConnector2ExecutableBase.get(transmitter); @@ -306,8 +303,15 @@ class SingleUnitMainGenerator { String iPrefix = instancePrefixMap.get(exec); if(exec instanceof IWriteableExecutable) { IWriteableExecutable wexec = (IWriteableExecutable)exec; - // TODO: NoVal support - return wexec.getWriteCode(iPrefix, sPrefix, outport, portName(outport)); + String sourceVariable = getPortIdentifier(outport); + String writeCode = wexec.getWriteCode(iPrefix, sPrefix, outport, sourceVariable); + String novalCode = wexec.getNoValWriteCode(iPrefix, sPrefix, outport); + if(novalCode != null) { + String novalVariable = getPortNoValIdentifier(sourceVariable); + return "if (" + novalVariable + ") {\n" + novalCode + "}\n else {\n" + writeCode + + "}\n"; + } + return writeCode; } return "FIXME(\"No executable available to write " + outport.getName() + " to " + transmitter.getName() + "\");\n"; @@ -323,8 +327,13 @@ class SingleUnitMainGenerator { String iPrefix = instancePrefixMap.get(exec); if(exec instanceof IReadableExecutable) { IReadableExecutable rexec = (IReadableExecutable)exec; - // TODO: NoVal support - return rexec.getReadCode(iPrefix, sPrefix, inport); + String targetVariable = getPortIdentifier(inport); + String readCode = rexec.getReadCode(iPrefix, sPrefix, inport, targetVariable); + String novalCode = rexec.getNoValReadCode(iPrefix, sPrefix, inport); + if(novalCode != null) { + return "if (" + novalCode + ") {\n" + readCode + "}\""; + } + return readCode; } return "FIXME\"No executable available to read " + inport.getName() + " from " + receiver.getName() + "\");\n"; diff --git a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/framework/.ratings b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/framework/.ratings index 03367d7c..754df1df 100644 --- a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/framework/.ratings +++ b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/framework/.ratings @@ -4,7 +4,7 @@ IInstanceTerminationExecutable.java 7be0257c229e85e223e72a19d21fd4c7c5db1750 YEL IRasPiHeaderExecutable.java f14b5714e7b982e097f6ac6e95eb91223a30d048 YELLOW IRasPiLibraryBasedExecutable.java cf3548f22185e666fdcf6d4658b783734c0e5e8e YELLOW IRasPiSourceBasedExecutable.java 79646213964346ace17013f5c8df5de13dafb1f0 YELLOW -IReadableExecutable.java fdab374944e016be0f3c891af9b992627f16b9c3 YELLOW +IReadableExecutable.java 68e8decd7568587e5b1951a1b3fed1237643d604 YELLOW ISingletonExecutable.java d7a794f50cf4746fa9378ffaa89283130b5273b1 YELLOW ISingletonInitializationExecutable.java fe042d336b3f9c618051d6598dfad882292b554f YELLOW ISingletonTerminationExecutable.java 2bd04ac893bedfd44ca4e73a27dd636873d8b64a YELLOW diff --git a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/framework/IReadableExecutable.java b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/framework/IReadableExecutable.java index fdab3749..68e8decd 100644 --- a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/framework/IReadableExecutable.java +++ b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/framework/IReadableExecutable.java @@ -18,13 +18,16 @@ package org.fortiss.af3.platform.raspberry.generator.executable.framework; import org.fortiss.af3.component.model.InputPort; /** - * Executable for platform elements that can be written (e.g. actuators and busses). + * Executable for platform elements that can be read (e.g. sensors and busses). Each method is + * provided a target variable by the calling code generator, which should be used to write the read + * value into. * * @author hoelzl */ public interface IReadableExecutable { - /** Returns the read code for the given port. */ - String getReadCode(String prefix, String singletonPrefix, InputPort logicalSignal); + /** Returns the read code for the given port and target variable. */ + String getReadCode(String prefix, String singletonPrefix, InputPort logicalSignal, + String targetVariable); /** * Returns the read code to determine whether the value of the platform element is NoVal. May diff --git a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/gamepad/.ratings b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/gamepad/.ratings index 9322aa76..a9984d17 100644 --- a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/gamepad/.ratings +++ b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/gamepad/.ratings @@ -2,14 +2,14 @@ Button1Executable.java 4419314d71af50239cf6933a83a0f652614cf368 YELLOW Button2Executable.java 3af03ceea3aa09178fe88fe630c94282de0b72f2 YELLOW Button3Executable.java 964fbe4e0b5282ab617c4be2bed31afa8b4f394f YELLOW Button4Executable.java 53db1cce9e3dfface4027f883586bf90638cd4ff YELLOW -ButtonExecutableBase.java e0c755229dcc73a980247dbca5146cda6262bcf8 YELLOW +ButtonExecutableBase.java c088da46cb2cef538948e5cb1794e55b13ab7cba YELLOW ButtonL1Executable.java ab68cddae1d323ff0ecd7956133c44d1ef0f9168 YELLOW ButtonL2Executable.java 336b9d8d26a682b701f7a2ca078369c9cc621fbb YELLOW ButtonR1Executable.java 700ef701ed77a0d3f8141166fe647ac5cd4ad570 YELLOW ButtonR2Executable.java 9b4acdc37505f41c60d8216c92bcbd3f43a2ccec YELLOW -GamepadExecutableBase.java d4b88c08dd1bd77ae3c3e24daed638ab7fbf69e7 YELLOW +GamepadExecutableBase.java ec5dc44fcb2547990f01dc088da49683e126d1c0 YELLOW Left_StickXExecutable.java c3e7f28f44fa27bd79e14ed7e60f44be2dc5a9ab YELLOW Left_StickYExecutable.java f81cc1e3124eb712507825bc54e7d0f633fde640 YELLOW Right_StickXExecutable.java ade165c88d0c6758efa167e5ba445eff87a0fd79 YELLOW Right_StickYExecutable.java 891ea877d8c3f4bab6072a02b17bb92a6caa055d YELLOW -StickExecutableBase.java 65fabd5583e055a30081517d11c1986e4041c6c3 YELLOW +StickExecutableBase.java 28de7e3d22652f548545e4cbdedbb5298fc56905 YELLOW diff --git a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/gamepad/ButtonExecutableBase.java b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/gamepad/ButtonExecutableBase.java index e0c75522..c088da46 100644 --- a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/gamepad/ButtonExecutableBase.java +++ b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/gamepad/ButtonExecutableBase.java @@ -33,8 +33,9 @@ abstract class ButtonExecutableBase<T extends EObject> extends GamepadExecutable /** {@inheritDoc} */ @Override - public final String getReadCode(String prefix, String singletonPrefix, InputPort logicalSignal) { - return "gamepad_get_button_state(" + getButtonIdentifier() + ");\n"; + public final String getReadCode(String prefix, String singletonPrefix, InputPort logicalSignal, + String targetVariable) { + return targetVariable + " = gamepad_get_button_state(" + getButtonIdentifier() + ");\n"; } /** {@inheritDoc} */ diff --git a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/gamepad/GamepadExecutableBase.java b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/gamepad/GamepadExecutableBase.java index dde1abb7..ec5dc44f 100644 --- a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/gamepad/GamepadExecutableBase.java +++ b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/gamepad/GamepadExecutableBase.java @@ -44,8 +44,7 @@ abstract class GamepadExecutableBase<T extends EObject> extends PiHALLibraryExec String prefixedVar = singletonPrefix + "_gamepad_config"; StringBuilder sb = new StringBuilder(); sb.append("// initialize the gamepad configuration\n"); - sb.append("gamepad_configuration_t* " + prefixedVar + - " = malloc(sizeof(gamepad_configuration_t));\n"); + sb.append(prefixedVar + " = malloc(sizeof(gamepad_configuration_t));\n"); sb.append(prefixedVar + "->device_id = \"/dev/input/js0\";\n"); sb.append(prefixedVar + "->waiting_sleep_in_micros = 250;\n"); sb.append(prefixedVar + "->axis_callback = NULL;\n"); diff --git a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/gamepad/StickExecutableBase.java b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/gamepad/StickExecutableBase.java index 65fabd55..28de7e3d 100644 --- a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/gamepad/StickExecutableBase.java +++ b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/gamepad/StickExecutableBase.java @@ -33,8 +33,9 @@ abstract class StickExecutableBase<T extends EObject> extends GamepadExecutableB /** {@inheritDoc} */ @Override - public final String getReadCode(String prefix, String singletonPrefix, InputPort logicalSignal) { - return "gamepad_get_axis_position(" + getAxisIdentifier() + ");\n"; + public final String getReadCode(String prefix, String singletonPrefix, InputPort logicalSignal, + String targetVariable) { + return targetVariable + " = gamepad_get_axis_position(" + getAxisIdentifier() + ");\n"; } /** {@inheritDoc} */ diff --git a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/rumblepad/.ratings b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/rumblepad/.ratings index bc7da89e..28db7167 100644 --- a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/rumblepad/.ratings +++ b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/rumblepad/.ratings @@ -1,6 +1,6 @@ ButtonAExecutable.java bbcb151d851b1b3d3e97b7e11b790fa13559fd96 YELLOW ButtonBExecutable.java d659e04dc60cba0808bd2fceae22fcbc1bd203a9 YELLOW -ButtonExecutableBase.java e29dff88a089470888c295886bce9d3179516424 YELLOW +ButtonExecutableBase.java 92a0dcba935028925c1b2af6d3d68152380189fe YELLOW ButtonHomeExecutable.java e3a19a82d2cafd3bc75b6a7fc1a75df5656df48c YELLOW ButtonL1Executable.java 68fac6c2abc7ea40eb7cc16839677a4cdc24111a YELLOW ButtonL3Executable.java 2d04b51ee7ab822419140cf69821bbcbcfded359 YELLOW @@ -20,6 +20,6 @@ Left_StickYExecutable.java cc2b36f9bca913dc1956f34495cf9c77acb13c88 YELLOW R2PositionExecutable.java 19f778392841d02d281fd856564b75e1333dffaa YELLOW Right_StickXExecutable.java 97656a2ae56a70eac88153b123f2cd9c584af967 YELLOW Right_StickYExecutable.java f3d942123ca47d0ddbf32f4f46bfaf2b21732653 YELLOW -RumblepadExecutableBase.java a12c66ea010375e0367646444f1c0b90bf791b03 YELLOW +RumblepadExecutableBase.java d5af8e370cab04e7c37e645055a4268d026995fd YELLOW SimpleRumbleFeatureExecutable.java 413b6fb3f5847f0d09f52341c98b95f74c352016 YELLOW -StickExecutableBase.java b9592ed47078f82aa0e95f90f545c5ff3ee26dc4 YELLOW +StickExecutableBase.java a9ae46291b6090ea090a3adc4ec45160a274b149 YELLOW diff --git a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/rumblepad/ButtonExecutableBase.java b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/rumblepad/ButtonExecutableBase.java index e29dff88..92a0dcba 100644 --- a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/rumblepad/ButtonExecutableBase.java +++ b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/rumblepad/ButtonExecutableBase.java @@ -33,8 +33,9 @@ abstract class ButtonExecutableBase<T extends EObject> extends RumblepadExecutab /** {@inheritDoc} */ @Override - public final String getReadCode(String prefix, String singletonPrefix, InputPort logicalSignal) { - return "rumblepad_get_button_state(" + getButtonIdentifier() + ");\n"; + public final String getReadCode(String prefix, String singletonPrefix, InputPort logicalSignal, + String targetVariable) { + return targetVariable + " = rumblepad_get_button_state(" + getButtonIdentifier() + ");\n"; } /** {@inheritDoc} */ diff --git a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/rumblepad/RumblepadExecutableBase.java b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/rumblepad/RumblepadExecutableBase.java index a12c66ea..d5af8e37 100644 --- a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/rumblepad/RumblepadExecutableBase.java +++ b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/rumblepad/RumblepadExecutableBase.java @@ -44,8 +44,7 @@ abstract class RumblepadExecutableBase<T extends EObject> extends PiHALLibraryEx String prefixedVar = singletonPrefix + "_rumblepad_config"; StringBuilder sb = new StringBuilder(); sb.append("// initialize the rumblepad configuration\n"); - sb.append("rumblepad_configuration_t* " + prefixedVar + - " = malloc(sizeof(rumblepad_configuration_t));\n"); + sb.append(prefixedVar + " = malloc(sizeof(rumblepad_configuration_t));\n"); sb.append(prefixedVar + "->device_id = \"/dev/input/js0\";\n"); sb.append(prefixedVar + "->waiting_sleep_in_micros = 50;\n"); sb.append(prefixedVar + "->axis_callback = NULL;\n"); diff --git a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/rumblepad/StickExecutableBase.java b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/rumblepad/StickExecutableBase.java index b9592ed4..a9ae4629 100644 --- a/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/rumblepad/StickExecutableBase.java +++ b/org.fortiss.af3.platform.raspberry/src/org/fortiss/af3/platform/raspberry/generator/executable/rumblepad/StickExecutableBase.java @@ -33,8 +33,9 @@ abstract class StickExecutableBase<T extends EObject> extends RumblepadExecutabl /** {@inheritDoc} */ @Override - public final String getReadCode(String prefix, String singletonPrefix, InputPort logicalSignal) { - return "rumblepad_get_axis_position(" + getAxisIdentifier() + ");\n"; + public final String getReadCode(String prefix, String singletonPrefix, InputPort logicalSignal, + String targetVariable) { + return targetVariable + " = rumblepad_get_axis_position(" + getAxisIdentifier() + ");\n"; } /** {@inheritDoc} */ -- GitLab