Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc-2-2
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc-2-2
Commits
1e80fd26
Commit
1e80fd26
authored
Nov 19, 2012
by
Francois Cartegnie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Qt: add fingerprinting ui
parent
0248a7fc
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
488 additions
and
2 deletions
+488
-2
modules/gui/qt4/Modules.am
modules/gui/qt4/Modules.am
+8
-0
modules/gui/qt4/adapters/chromaprint.cpp
modules/gui/qt4/adapters/chromaprint.cpp
+77
-0
modules/gui/qt4/adapters/chromaprint.hpp
modules/gui/qt4/adapters/chromaprint.hpp
+55
-0
modules/gui/qt4/components/info_panels.cpp
modules/gui/qt4/components/info_panels.cpp
+28
-2
modules/gui/qt4/components/info_panels.hpp
modules/gui/qt4/components/info_panels.hpp
+5
-0
modules/gui/qt4/dialogs/fingerprintdialog.cpp
modules/gui/qt4/dialogs/fingerprintdialog.cpp
+116
-0
modules/gui/qt4/dialogs/fingerprintdialog.hpp
modules/gui/qt4/dialogs/fingerprintdialog.hpp
+61
-0
modules/gui/qt4/ui/fingerprintdialog.ui
modules/gui/qt4/ui/fingerprintdialog.ui
+138
-0
No files found.
modules/gui/qt4/Modules.am
View file @
1e80fd26
...
...
@@ -23,6 +23,7 @@ nodist_SOURCES_qt4 = \
extensions_manager.moc.cpp \
recents.moc.cpp \
adapters/seekpoints.moc.cpp \
adapters/chromaprint.moc.cpp \
variables.moc.cpp \
dialogs/playlist.moc.cpp \
dialogs/bookmarks.moc.cpp \
...
...
@@ -45,6 +46,7 @@ nodist_SOURCES_qt4 = \
dialogs/vlm.moc.cpp \
dialogs/firstrun.moc.cpp \
dialogs/extensions.moc.cpp \
dialogs/fingerprintdialog.moc.cpp \
components/extended_panels.moc.cpp \
components/info_panels.moc.cpp \
components/info_widgets.moc.cpp \
...
...
@@ -98,6 +100,7 @@ nodist_SOURCES_qt4 = \
ui/messages_panel.h \
ui/about.h \
ui/update.h \
ui/fingerprintdialog.h \
styles/seekstyle.moc.cpp \
dialogs/ml_configuration.moc.cpp \
components/playlist/ml_model.moc.cpp \
...
...
@@ -282,6 +285,7 @@ SOURCES_qt4 = qt4.cpp \
extensions_manager.cpp \
recents.cpp \
adapters/seekpoints.cpp \
adapters/chromaprint.cpp \
variables.cpp \
dialogs/playlist.cpp \
dialogs/bookmarks.cpp \
...
...
@@ -305,6 +309,7 @@ SOURCES_qt4 = qt4.cpp \
dialogs/firstrun.cpp \
dialogs/podcast_configuration.cpp \
dialogs/extensions.cpp \
dialogs/fingerprintdialog.cpp \
components/extended_panels.cpp \
components/info_panels.cpp \
components/info_widgets.cpp \
...
...
@@ -359,6 +364,7 @@ noinst_HEADERS = \
extensions_manager.hpp \
recents.hpp \
adapters/seekpoints.hpp \
adapters/chromaprint.hpp \
variables.hpp \
dialogs/playlist.hpp \
dialogs/bookmarks.hpp \
...
...
@@ -382,6 +388,7 @@ noinst_HEADERS = \
dialogs/firstrun.hpp \
dialogs/podcast_configuration.hpp \
dialogs/extensions.hpp \
dialogs/fingerprintdialog.hpp \
components/extended_panels.hpp \
components/info_panels.hpp \
components/info_widgets.hpp \
...
...
@@ -450,4 +457,5 @@ EXTRA_DIST += \
ui/update.ui \
ui/sout.ui \
ui/vlm.ui \
ui/fingerprintdialog.ui \
$(DEPS_res)
modules/gui/qt4/adapters/chromaprint.cpp
0 → 100644
View file @
1e80fd26
/*****************************************************************************
* chromaprint.cpp: Fingerprinter helper class
*****************************************************************************
* Copyright (C) 2012 VLC authors and VideoLAN
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "chromaprint.hpp"
#include <vlc_fingerprinter.h>
#include <vlc_modules.h>
Chromaprint
::
Chromaprint
(
intf_thread_t
*
_p_intf
)
:
p_intf
(
_p_intf
)
{
Q_ASSERT
(
p_intf
);
p_fingerprinter
=
fingerprinter_Create
(
VLC_OBJECT
(
p_intf
)
);
if
(
p_fingerprinter
)
var_AddCallback
(
p_fingerprinter
,
"results-available"
,
results_available
,
this
);
}
int
Chromaprint
::
results_available
(
vlc_object_t
*
,
const
char
*
,
vlc_value_t
,
vlc_value_t
,
void
*
param
)
{
Chromaprint
*
me
=
(
Chromaprint
*
)
param
;
me
->
finish
();
return
0
;
}
fingerprint_request_t
*
Chromaprint
::
fetchResults
()
{
return
p_fingerprinter
->
pf_getresults
(
p_fingerprinter
);
}
void
Chromaprint
::
apply
(
fingerprint_request_t
*
p_r
,
int
i_id
)
{
p_fingerprinter
->
pf_apply
(
p_r
,
i_id
);
}
bool
Chromaprint
::
enqueue
(
input_item_t
*
p_item
)
{
if
(
!
p_fingerprinter
)
return
false
;
fingerprint_request_t
*
p_r
=
fingerprint_request_New
(
p_item
);
if
(
!
p_r
)
return
false
;
mtime_t
t
=
input_item_GetDuration
(
p_item
);
if
(
t
)
p_r
->
i_duration
=
(
unsigned
int
)
(
t
/
1000000
);
p_fingerprinter
->
pf_enqueue
(
p_fingerprinter
,
p_r
);
return
true
;
}
bool
Chromaprint
::
isSupported
(
QString
uri
)
{
if
(
!
module_exists
(
"stream_out_chromaprint"
)
)
return
false
;
else
return
(
uri
.
startsWith
(
"file://"
)
||
uri
.
startsWith
(
"/"
)
);
}
Chromaprint
::~
Chromaprint
()
{
if
(
p_fingerprinter
)
fingerprinter_Destroy
(
p_fingerprinter
);
}
modules/gui/qt4/adapters/chromaprint.hpp
0 → 100644
View file @
1e80fd26
/*****************************************************************************
* chromaprint.hpp: Fingerprinter helper class
*****************************************************************************
* Copyright (C) 2012 VLC authors and VideoLAN
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifndef CHROMAPRINT_HPP
#define CHROMAPRINT_HPP
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <QObject>
#include <QString>
#include <vlc_fingerprinter.h>
#include <vlc_interface.h>
class
Chromaprint
:
public
QObject
{
Q_OBJECT
public:
Chromaprint
(
intf_thread_t
*
p_intf
=
NULL
);
virtual
~
Chromaprint
();
bool
enqueue
(
input_item_t
*
p_item
);
static
int
results_available
(
vlc_object_t
*
p_this
,
const
char
*
,
vlc_value_t
,
vlc_value_t
newval
,
void
*
param
);
fingerprint_request_t
*
fetchResults
();
void
apply
(
fingerprint_request_t
*
,
int
i_id
);
static
bool
isSupported
(
QString
uri
);
signals:
void
finished
();
private:
void
finish
()
{
emit
finished
();
}
intf_thread_t
*
p_intf
;
fingerprinter_thread_t
*
p_fingerprinter
;
};
#endif // CHROMAPRINT_HPP
modules/gui/qt4/components/info_panels.cpp
View file @
1e80fd26
...
...
@@ -34,6 +34,8 @@
#include "components/info_panels.hpp"
#include "components/interface_widgets.hpp"
#include "info_widgets.hpp"
#include "dialogs/fingerprintdialog.hpp"
#include "adapters/chromaprint.hpp"
#include <assert.h>
#include <vlc_url.h>
...
...
@@ -129,7 +131,15 @@ MetaPanel::MetaPanel( QWidget *parent,
/* Language on the same line */
ADD_META
(
VLC_META_LANGUAGE
,
language_text
,
7
,
-
1
);
line
++
;
ADD_META
(
VLC_META_PUBLISHER
,
publisher_text
,
0
,
7
);
line
++
;
ADD_META
(
VLC_META_PUBLISHER
,
publisher_text
,
0
,
7
);
fingerprintButton
=
new
QPushButton
(
qtr
(
"&Fingerprint"
)
);
fingerprintButton
->
setToolTip
(
qtr
(
"Find meta data using audio fingerprinting"
)
);
fingerprintButton
->
setVisible
(
false
);
metaLayout
->
addWidget
(
fingerprintButton
,
line
,
7
,
3
,
-
1
);
CONNECT
(
fingerprintButton
,
clicked
(),
this
,
fingerprint
()
);
line
++
;
lblURL
=
new
QLabel
;
lblURL
->
setOpenExternalLinks
(
true
);
...
...
@@ -212,7 +222,8 @@ void MetaPanel::update( input_item_t *p_item )
/* URL / URI */
psz_meta
=
input_item_GetURI
(
p_item
);
if
(
!
EMPTY_STR
(
psz_meta
)
)
emit
uriSet
(
qfu
(
psz_meta
)
);
emit
uriSet
(
qfu
(
psz_meta
)
);
fingerprintButton
->
setVisible
(
Chromaprint
::
isSupported
(
QString
(
psz_meta
)
)
);
free
(
psz_meta
);
/* Other classic though */
...
...
@@ -337,11 +348,26 @@ void MetaPanel::clear()
publisher_text
->
clear
();
encodedby_text
->
clear
();
art_cover
->
clear
();
fingerprintButton
->
setVisible
(
false
);
setEditMode
(
false
);
emit
uriSet
(
""
);
}
void
MetaPanel
::
fingerprint
()
{
FingerprintDialog
*
dialog
=
new
FingerprintDialog
(
this
,
p_intf
,
p_input
);
CONNECT
(
dialog
,
metaApplied
(
input_item_t
*
),
this
,
fingerprintUpdate
(
input_item_t
*
)
);
dialog
->
setAttribute
(
Qt
::
WA_DeleteOnClose
,
true
);
dialog
->
show
();
}
void
MetaPanel
::
fingerprintUpdate
(
input_item_t
*
p_item
)
{
update
(
p_item
);
setEditMode
(
true
);
}
/**
* Second Panel - Shows the extra metadata in a tree, non editable.
**/
...
...
modules/gui/qt4/components/info_panels.hpp
View file @
1e80fd26
...
...
@@ -52,6 +52,7 @@ class CoverArtLabel;
class
QTextEdit
;
class
QLabel
;
class
VLCStatsView
;
class
QPushButton
;
class
MetaPanel
:
public
QWidget
{
...
...
@@ -88,9 +89,13 @@ private:
QLabel
*
lblURL
;
QString
currentURL
;
QPushButton
*
fingerprintButton
;
public
slots
:
void
update
(
input_item_t
*
);
void
clear
();
void
fingerprint
();
void
fingerprintUpdate
(
input_item_t
*
);
private
slots
:
void
enterEditMode
();
...
...
modules/gui/qt4/dialogs/fingerprintdialog.cpp
0 → 100644
View file @
1e80fd26
/*****************************************************************************
* fingerprintdialog.cpp: Fingerprinter Dialog
*****************************************************************************
* Copyright (C) 2012 VLC authors and VideoLAN
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include "fingerprintdialog.hpp"
#include "ui/fingerprintdialog.h"
#include "adapters/chromaprint.hpp"
#include <vlc_url.h>
#include <QLabel>
#include <QListWidgetItem>
FingerprintDialog
::
FingerprintDialog
(
QWidget
*
parent
,
intf_thread_t
*
p_intf
,
input_item_t
*
p_item
)
:
QDialog
(
parent
),
ui
(
new
Ui
::
FingerprintDialog
),
p_r
(
NULL
)
{
ui
->
setupUi
(
this
);
ui
->
stackedWidget
->
setCurrentWidget
(
ui
->
wait
);
ui
->
buttonBox
->
addButton
(
"&Close"
,
QDialogButtonBox
::
RejectRole
);
ui
->
buttonsBox
->
addButton
(
"&Apply this identity to the file"
,
QDialogButtonBox
::
AcceptRole
);
ui
->
buttonsBox
->
addButton
(
"&Discard all identities"
,
QDialogButtonBox
::
RejectRole
);
CONNECT
(
ui
->
buttonsBox
,
accepted
(),
this
,
applyIdentity
()
);
CONNECT
(
ui
->
buttonBox
,
rejected
(),
this
,
close
()
);
CONNECT
(
ui
->
buttonsBox
,
rejected
(),
this
,
close
()
);
t
=
new
Chromaprint
(
p_intf
);
if
(
t
)
{
CONNECT
(
t
,
finished
(),
this
,
handleResults
()
);
t
->
enqueue
(
p_item
);
}
}
void
FingerprintDialog
::
applyIdentity
()
{
Q_ASSERT
(
p_r
);
if
(
ui
->
recordsList
->
currentIndex
().
isValid
()
)
t
->
apply
(
p_r
,
ui
->
recordsList
->
currentIndex
().
row
()
);
emit
metaApplied
(
p_r
->
p_item
);
close
();
}
void
FingerprintDialog
::
handleResults
()
{
p_r
=
t
->
fetchResults
();
if
(
!
p_r
)
{
ui
->
stackedWidget
->
setCurrentWidget
(
ui
->
error
);
return
;
}
if
(
vlc_array_count
(
&
p_r
->
results
.
metas_array
)
==
0
)
{
fingerprint_request_Delete
(
p_r
);
p_r
=
NULL
;
ui
->
stackedWidget
->
setCurrentWidget
(
ui
->
error
);
return
;
}
ui
->
stackedWidget
->
setCurrentWidget
(
ui
->
results
);
for
(
int
i
=
0
;
i
<
vlc_array_count
(
&
p_r
->
results
.
metas_array
)
;
i
++
)
{
vlc_meta_t
*
p_meta
=
(
vlc_meta_t
*
)
vlc_array_item_at_index
(
&
p_r
->
results
.
metas_array
,
i
);
QListWidgetItem
*
item
=
new
QListWidgetItem
();
ui
->
recordsList
->
addItem
(
item
);
QString
mb_id
(
vlc_meta_GetExtra
(
p_meta
,
"musicbrainz-id"
)
);
QLabel
*
label
=
new
QLabel
(
QString
(
"<h3 style=
\"
margin: 0
\"
><a style=
\"
text-decoration:none
\"
href=
\"
%1
\"
>%2</a></h3>"
"<span style=
\"
padding-left:20px
\"
>%3</span>"
)
.
arg
(
QString
(
"http://mb.videolan.org/recording/%1"
).
arg
(
mb_id
)
)
.
arg
(
qfu
(
vlc_meta_Get
(
p_meta
,
vlc_meta_Title
)
)
)
.
arg
(
qfu
(
vlc_meta_Get
(
p_meta
,
vlc_meta_Artist
)
)
)
);
label
->
setSizePolicy
(
QSizePolicy
::
Expanding
,
QSizePolicy
::
Preferred
);
label
->
setOpenExternalLinks
(
true
);
item
->
setSizeHint
(
label
->
sizeHint
()
);
ui
->
recordsList
->
setItemWidget
(
item
,
label
);
}
ui
->
recordsList
->
setCurrentIndex
(
ui
->
recordsList
->
model
()
->
index
(
0
,
0
)
);
}
FingerprintDialog
::~
FingerprintDialog
()
{
if
(
t
)
delete
t
;
if
(
p_r
)
fingerprint_request_Delete
(
p_r
);
delete
ui
;
}
modules/gui/qt4/dialogs/fingerprintdialog.hpp
0 → 100644
View file @
1e80fd26
/*****************************************************************************
* fingerprintdialog.hpp: Fingerprinter Dialog
*****************************************************************************
* Copyright (C) 2012 VLC authors and VideoLAN
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifndef FINGERPRINTDIALOG_HPP
#define FINGERPRINTDIALOG_HPP
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "qt4.hpp"
#include <QDialog>
#include <vlc_interface.h>
#include <vlc_fingerprinter.h>
namespace
Ui
{
class
FingerprintDialog
;
}
class
Chromaprint
;
class
FingerprintDialog
:
public
QDialog
{
Q_OBJECT
public:
FingerprintDialog
(
QWidget
*
parent
,
intf_thread_t
*
p_intf
,
input_item_t
*
p_item
);
~
FingerprintDialog
();
private:
Ui
::
FingerprintDialog
*
ui
;
Chromaprint
*
t
;
fingerprint_request_t
*
p_r
;
private
slots
:
void
handleResults
();
void
applyIdentity
();
signals:
void
metaApplied
(
input_item_t
*
);
};
#endif // FINGERPRINTDIALOG_HPP
modules/gui/qt4/ui/fingerprintdialog.ui
0 → 100644
View file @
1e80fd26
<?xml version="1.0" encoding="UTF-8"?>
<ui
version=
"4.0"
>
<class>
FingerprintDialog
</class>
<widget
class=
"QDialog"
name=
"FingerprintDialog"
>
<property
name=
"windowModality"
>
<enum>
Qt::WindowModal
</enum>
</property>
<property
name=
"geometry"
>
<rect>
<x>
0
</x>
<y>
0
</y>
<width>
499
</width>
<height>
257
</height>
</rect>
</property>
<property
name=
"windowTitle"
>
<string>
Audio Fingerprinting
</string>
</property>
<layout
class=
"QVBoxLayout"
name=
"verticalLayout_3"
>
<item>
<widget
class=
"QStackedWidget"
name=
"stackedWidget"
>
<property
name=
"sizePolicy"
>
<sizepolicy
hsizetype=
"Preferred"
vsizetype=
"Minimum"
>
<horstretch>
0
</horstretch>
<verstretch>
0
</verstretch>
</sizepolicy>
</property>
<property
name=
"currentIndex"
>
<number>
0
</number>
</property>
<widget
class=
"QWidget"
name=
"results"
>
<layout
class=
"QVBoxLayout"
name=
"verticalLayout_2"
>
<item>
<widget
class=
"QLabel"
name=
"label_3"
>
<property
name=
"text"
>
<string>
Select a matching identity
</string>
</property>
</widget>
</item>
<item>
<widget
class=
"QListWidget"
name=
"recordsList"
/>
</item>
<item>
<widget
class=
"QDialogButtonBox"
name=
"buttonsBox"
>
<property
name=
"standardButtons"
>
<set>
QDialogButtonBox::NoButton
</set>
</property>
</widget>
</item>
</layout>
</widget>
<widget
class=
"QWidget"
name=
"error"
>
<layout
class=
"QVBoxLayout"
name=
"verticalLayout_4"
>
<item>
<widget
class=
"QLabel"
name=
"label_2"
>
<property
name=
"text"
>
<string>
No fingerprint has been found
</string>
</property>
<property
name=
"alignment"
>
<set>
Qt::AlignCenter
</set>
</property>
</widget>
</item>
<item>
<widget
class=
"QDialogButtonBox"
name=
"buttonBox"
>
<property
name=
"standardButtons"
>
<set>
QDialogButtonBox::NoButton
</set>
</property>
</widget>
</item>
</layout>
</widget>
<widget
class=
"QWidget"
name=
"wait"
>
<property
name=
"sizePolicy"
>
<sizepolicy
hsizetype=
"Preferred"
vsizetype=
"Preferred"
>
<horstretch>
0
</horstretch>
<verstretch>
0
</verstretch>
</sizepolicy>
</property>
<layout
class=
"QVBoxLayout"
name=
"verticalLayout"
>
<item>
<spacer
name=
"verticalSpacer"
>
<property
name=
"orientation"
>
<enum>
Qt::Vertical
</enum>
</property>
<property
name=
"sizeHint"
stdset=
"0"
>
<size>
<width>
20
</width>
<height>
40
</height>
</size>
</property>
</spacer>
</item>
<item>
<widget
class=
"QProgressBar"
name=
"progressBar"
>
<property
name=
"minimum"
>
<number>
0
</number>
</property>
<property
name=
"maximum"
>
<number>
0
</number>
</property>
<property
name=
"value"
>
<number>
-1
</number>
</property>
</widget>
</item>
<item>
<widget
class=
"QLabel"
name=
"label"
>
<property
name=
"text"
>
<string>
Fingerprinting track...
</string>
</property>
<property
name=
"alignment"
>
<set>
Qt::AlignCenter
</set>
</property>
</widget>
</item>
<item>
<spacer
name=
"verticalSpacer_2"
>
<property
name=
"orientation"
>
<enum>
Qt::Vertical
</enum>
</property>
<property
name=
"sizeHint"
stdset=
"0"
>
<size>
<width>
20
</width>
<height>
40
</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment