From 94d62b006d145f4f3df6bd5299d412aa0d6a9c87 Mon Sep 17 00:00:00 2001
From: Lorn Potter <lorn.potter@gmail.com>
Date: Sat, 24 Nov 2012 20:39:46 +1000
Subject: [PATCH] iOS: implement accelerometer for iOS

This change implements an accelerometer for iOS.

Change-Id: Id6de98427312bc0be42935fd9704117665d1e4a2
Reviewed-by: Thomas McGuire <thomas.mcguire@kdab.com>
---
 src/plugins/sensors/ios/ios.pro             |  17 +++
 src/plugins/sensors/ios/iosaccelerometer.h  |  71 ++++++++++
 src/plugins/sensors/ios/iosaccelerometer.mm | 143 ++++++++++++++++++++
 src/plugins/sensors/ios/iosmotionmanager.h  |  55 ++++++++
 src/plugins/sensors/ios/iosmotionmanager.mm |  57 ++++++++
 src/plugins/sensors/ios/main.mm             |  70 ++++++++++
 src/plugins/sensors/ios/plugin.json         |   1 +
 src/plugins/sensors/sensors.pro             |   2 +-
 src/sensors/doc/src/compatmap.qdoc          |  18 +++
 9 files changed, 433 insertions(+), 1 deletion(-)
 create mode 100644 src/plugins/sensors/ios/ios.pro
 create mode 100644 src/plugins/sensors/ios/iosaccelerometer.h
 create mode 100644 src/plugins/sensors/ios/iosaccelerometer.mm
 create mode 100644 src/plugins/sensors/ios/iosmotionmanager.h
 create mode 100644 src/plugins/sensors/ios/iosmotionmanager.mm
 create mode 100644 src/plugins/sensors/ios/main.mm
 create mode 100644 src/plugins/sensors/ios/plugin.json

diff --git a/src/plugins/sensors/ios/ios.pro b/src/plugins/sensors/ios/ios.pro
new file mode 100644
index 00000000..4242cfca
--- /dev/null
+++ b/src/plugins/sensors/ios/ios.pro
@@ -0,0 +1,17 @@
+TARGET = qtsensors_ios
+QT = core sensors
+
+PLUGIN_TYPE = sensors
+PLUGIN_CLASS_NAME = IOSSensorPlugin
+load(qt_plugin)
+
+OTHER_FILES = plugin.json
+
+HEADERS += iosaccelerometer.h \
+        iosmotionmanager.h
+
+OBJECTIVE_SOURCES += main.mm \
+    iosaccelerometer.mm \
+    iosmotionmanager.mm
+
+LIBS += -framework UIKit -framework CoreMotion
diff --git a/src/plugins/sensors/ios/iosaccelerometer.h b/src/plugins/sensors/ios/iosaccelerometer.h
new file mode 100644
index 00000000..34cc3ebd
--- /dev/null
+++ b/src/plugins/sensors/ios/iosaccelerometer.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Lorn Potter
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtSensors module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef IOSACCELEROMETER_H
+#define IOSACCELEROMETER_H
+
+#include <qsensorbackend.h>
+#include <qaccelerometer.h>
+
+QT_BEGIN_NAMESPACE
+
+@class QtIoAccelListener;
+
+class IOSAccelerometer : public QSensorBackend
+{
+public:
+    static char const * const id;
+
+    explicit IOSAccelerometer(QSensor *sensor);
+    ~IOSAccelerometer();
+
+    void start();
+    void stop();
+    void readingsChanged(quint64,qreal,qreal,qreal);
+
+private:
+    QtIoAccelListener *m_listener;
+    QAccelerometerReading m_reading;
+};
+QT_END_NAMESPACE
+
+#endif // IOSACCELEROMETER_H
+
diff --git a/src/plugins/sensors/ios/iosaccelerometer.mm b/src/plugins/sensors/ios/iosaccelerometer.mm
new file mode 100644
index 00000000..ef7d2a6d
--- /dev/null
+++ b/src/plugins/sensors/ios/iosaccelerometer.mm
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Lorn Potter
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtSensors module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "iosaccelerometer.h"
+#include "iosmotionmanager.h"
+
+#include <UIKit/UIAccelerometer.h>
+#include <CoreMotion/CMMotionManager.h>
+
+char const * const IOSAccelerometer::id("ios.accelerometer");
+
+@interface QtIoAccelListener : NSObject
+{
+    IOSAccelerometer *m_qiosAccelerometer;
+    NSOperationQueue *m_updateQueue;
+}
+@end
+
+@implementation QtIoAccelListener
+
+-(id)initWithQIOSAccelerometer:(IOSAccelerometer *) qiosAccelerometer
+{
+    self = [super init];
+    if (self) {
+        m_qiosAccelerometer = qiosAccelerometer;
+        m_updateQueue = [[NSOperationQueue alloc] init];
+    }
+    return self;
+}
+
+-(void)dealloc
+{
+    [m_updateQueue release];
+    [super dealloc];
+}
+
+-(void)startAccelerometer
+{
+    CMMotionManager *motionManager = [QIOSMotionManager sharedManager];
+
+    if (motionManager.deviceMotionAvailable) {
+        [motionManager startAccelerometerUpdatesToQueue:m_updateQueue withHandler:^(CMAccelerometerData *data, NSError *error) {
+            dispatch_async(dispatch_get_main_queue(), ^{
+                Q_UNUSED(error);
+                CMAcceleration acc = data.acceleration;
+                // Convert from G to m/s2, and flip axes:
+                const qreal G = 9.8066;
+                qreal x = qreal(acc.x) * G * -1;
+                qreal y = qreal(acc.y) * G * -1;
+                qreal z = qreal(acc.z) * G * -1;
+                m_qiosAccelerometer->readingsChanged(quint64(data.timestamp), x, y, z);
+            });
+        }];
+    }
+}
+
+-(void)stopAccelerometer
+{
+    [[QIOSMotionManager sharedManager] stopAccelerometerUpdates];
+}
+
+-(void)setInterval:(NSTimeInterval) interval
+{
+    [QIOSMotionManager sharedManager].accelerometerUpdateInterval = interval;
+}
+
+@end
+
+QT_BEGIN_NAMESPACE
+
+IOSAccelerometer::IOSAccelerometer(QSensor *sensor)
+    : QSensorBackend(sensor)
+    , m_listener([[QtIoAccelListener alloc] initWithQIOSAccelerometer:this])
+{
+    setReading<QAccelerometerReading>(&m_reading);
+    addDataRate(1, 100); // 100Hz
+    addOutputRange(-22.418, 22.418, 0.17651); // 2G
+}
+
+IOSAccelerometer::~IOSAccelerometer()
+{
+    [m_listener dealloc];
+}
+
+void IOSAccelerometer::start()
+{
+    [m_listener startAccelerometer];
+}
+
+void IOSAccelerometer::stop()
+{
+    [m_listener stopAccelerometer];
+}
+
+void IOSAccelerometer::readingsChanged(quint64 ts, qreal x, qreal y, qreal z)
+{
+    m_reading.setTimestamp(ts);
+    m_reading.setX(x);
+    m_reading.setY(y);
+    m_reading.setZ(z);
+
+    newReadingAvailable();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sensors/ios/iosmotionmanager.h b/src/plugins/sensors/ios/iosmotionmanager.h
new file mode 100644
index 00000000..7babfc36
--- /dev/null
+++ b/src/plugins/sensors/ios/iosmotionmanager.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Lorn Potter
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtSensors module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef IOSMOTIONMANAGER_H
+#define IOSMOTIONMANAGER_H
+
+#import <UIKit/UIKit.h>
+#import <CoreMotion/CoreMotion.h>
+
+@interface QIOSMotionManager : NSObject {
+}
+
++ (CMMotionManager *)sharedManager;
+@end
+
+#endif //IOSMOTIONMANAGER_H
+
diff --git a/src/plugins/sensors/ios/iosmotionmanager.mm b/src/plugins/sensors/ios/iosmotionmanager.mm
new file mode 100644
index 00000000..a367c49b
--- /dev/null
+++ b/src/plugins/sensors/ios/iosmotionmanager.mm
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Lorn Potter
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtSensors module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "iosmotionmanager.h"
+
+static CMMotionManager *sharedManager = nil;
+
+@implementation QIOSMotionManager
+
++ (CMMotionManager *)sharedManager
+{
+    static dispatch_once_t staticToken;
+    dispatch_once(&staticToken, ^{
+        sharedManager = [[CMMotionManager alloc] init];
+    });
+    return sharedManager;
+}
+
+@end
diff --git a/src/plugins/sensors/ios/main.mm b/src/plugins/sensors/ios/main.mm
new file mode 100644
index 00000000..3c739393
--- /dev/null
+++ b/src/plugins/sensors/ios/main.mm
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtSensors module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qsensorplugin.h>
+#include <qsensorbackend.h>
+#include <qsensormanager.h>
+
+#include "iosaccelerometer.h"
+
+class IOSSensorPlugin : public QObject, public QSensorPluginInterface, public QSensorBackendFactory
+{
+    Q_OBJECT
+    Q_PLUGIN_METADATA(IID "com.qt-project.Qt.QSensorPluginInterface/1.0" FILE "plugin.json")
+    Q_INTERFACES(QSensorPluginInterface)
+public:
+    void registerSensors()
+    {
+        if (!QSensorManager::isBackendRegistered(QAccelerometer::type, IOSAccelerometer::id))
+            QSensorManager::registerBackend(QAccelerometer::type, IOSAccelerometer::id, this);
+    }
+
+    QSensorBackend *createBackend(QSensor *sensor)
+    {
+        if (sensor->identifier() == IOSAccelerometer::id)
+            return new IOSAccelerometer(sensor);
+
+        return 0;
+    }
+};
+
+#include "main.moc"
+
diff --git a/src/plugins/sensors/ios/plugin.json b/src/plugins/sensors/ios/plugin.json
new file mode 100644
index 00000000..8a55b3ae
--- /dev/null
+++ b/src/plugins/sensors/ios/plugin.json
@@ -0,0 +1 @@
+{ "Keys": [ "notused" ] }
diff --git a/src/plugins/sensors/sensors.pro b/src/plugins/sensors/sensors.pro
index ef15f133..73f42672 100644
--- a/src/plugins/sensors/sensors.pro
+++ b/src/plugins/sensors/sensors.pro
@@ -21,4 +21,4 @@ isEmpty(SENSORS_PLUGINS)|contains(SENSORS_PLUGINS, blackberry):blackberry:SUBDIR
 isEmpty(SENSORS_PLUGINS)|contains(SENSORS_PLUGINS, linux):linux:SUBDIRS += linux
 isEmpty(SENSORS_PLUGINS)|contains(SENSORS_PLUGINS, android):android:SUBDIRS += android
 isEmpty(SENSORS_PLUGINS)|contains(SENSORS_PLUGINS, sensorfw):sensorfw:SUBDIRS += sensorfw
-
+isEmpty(SENSORS_PLUGINS)|contains(SENSORS_PLUGINS, ios):ios:SUBDIRS += ios
diff --git a/src/sensors/doc/src/compatmap.qdoc b/src/sensors/doc/src/compatmap.qdoc
index ffca5f6d..62f94de0 100644
--- a/src/sensors/doc/src/compatmap.qdoc
+++ b/src/sensors/doc/src/compatmap.qdoc
@@ -56,6 +56,7 @@
     <td><b>Blackberry</b></td>
     <td><b>Android</b></td>
     <td><b>Linux</b></td>
+    <td><b>iOS</b></td>
     <td><b>Generic</b></td>
     <td><b>Sensorfw</b></td>
     </tr>
@@ -64,6 +65,7 @@
     <td bgcolor="green"></td>
     <td bgcolor="green"></td>
     <td bgcolor="green"></td>
+    <td bgcolor="green"></td>
     <td bgcolor="gray"></td>
     <td bgcolor="green"></td>
     </tr>
@@ -74,6 +76,7 @@
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
+    <td bgcolor="gray"></td>
     </tr>
     <tr>
     <td nowrap="nowrap">Ambient Light Sensor</td>
@@ -81,6 +84,7 @@
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
+    <td bgcolor="gray"></td>
     <td bgcolor="green"></td>
     </tr>
     <tr>
@@ -90,6 +94,7 @@
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
+    <td bgcolor="gray"></td>
     </tr>
     <tr>
     <td nowrap="nowrap">Compass</td>
@@ -97,6 +102,7 @@
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
+    <td bgcolor="gray"></td>
     <td bgcolor="green"></td>
     </tr>
     <tr>
@@ -105,6 +111,7 @@
     <td bgcolor="green"></td>
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
+    <td bgcolor="gray"></td>
     <td bgcolor="green"></td>
     </tr>
     <tr>
@@ -114,6 +121,7 @@
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
+    <td bgcolor="gray"></td>
     </tr>
     <tr>
     <td nowrap="nowrap">IR Proximity Sensor</td>
@@ -121,6 +129,7 @@
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
+    <td bgcolor="gray"></td>
     <td bgcolor="green"></td>
     </tr>
     <tr>
@@ -129,6 +138,7 @@
     <td bgcolor="green"></td>
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
+    <td bgcolor="gray"></td>
     <td bgcolor="green"></td>
     </tr>
     <tr>
@@ -137,6 +147,7 @@
     <td bgcolor="green"></td>
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
+    <td bgcolor="gray"></td>
     <td bgcolor="green"></td>
     </tr>
     <tr>
@@ -144,6 +155,7 @@
     <td bgcolor="green"></td>
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
+    <td bgcolor="gray"></td>
     <td bgcolor="green"></td>
     <td bgcolor="green"></td>
     </tr>
@@ -154,6 +166,7 @@
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
+    <td bgcolor="gray"></td>
     </tr>
     <tr>
     <td nowrap="nowrap">Proximity Sensor</td>
@@ -161,6 +174,7 @@
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
+    <td bgcolor="gray"></td>
     <td bgcolor="green"></td>
     </tr>
     <tr>
@@ -168,6 +182,7 @@
     <td bgcolor="green"></td>
     <td bgcolor="green"></td>
     <td bgcolor="gray"></td>
+    <td bgcolor="gray"></td>
     <td bgcolor="green"></td>
     <td bgcolor="green"></td>
     </tr>
@@ -178,12 +193,14 @@
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
+    <td bgcolor="gray"></td>
     </tr>
     <tr>
     <td nowrap="nowrap">Tilt Sensor</td>
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
+    <td bgcolor="gray"></td>
     <td bgcolor="green"></td>
     <td bgcolor="gray"></td>
     </tr>
@@ -193,6 +210,7 @@
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
     <td bgcolor="gray"></td>
+    <td bgcolor="gray"></td>
     <td bgcolor="green"></td>
     </tr>
     </table>
-- 
GitLab