Merge pull request #228 from ctrlaltca/error_suppression
Fix building with debug
This commit is contained in:
commit
1e5a00d100
17 changed files with 64 additions and 32 deletions
|
@ -76,8 +76,19 @@ IF(MSVC)
|
||||||
#set(CMAKE_CXX_FLAGS_DEBUG "/Zi")
|
#set(CMAKE_CXX_FLAGS_DEBUG "/Zi")
|
||||||
ELSEIF (CMAKE_COMPILER_IS_GNUCXX)
|
ELSEIF (CMAKE_COMPILER_IS_GNUCXX)
|
||||||
# linux/gcc, bsd/gcc, windows/mingw
|
# linux/gcc, bsd/gcc, windows/mingw
|
||||||
|
include(CheckCXXCompilerFlag)
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-s -O2")
|
set(CMAKE_CXX_FLAGS_RELEASE "-s -O2")
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O0 -Wall -Wextra -pedantic -Werror -Wcast-align -Wmissing-declarations -Winline -Wno-long-long -Wno-error=extra -Wno-error=unused-parameter -Wno-inline -Wno-error=delete-non-virtual-dtor -Wno-error=sign-compare -Wno-error=reorder -Wno-error=missing-declarations")
|
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O0 -Wall -Wextra -pedantic -Werror")
|
||||||
|
|
||||||
|
set(ADDITIONAL_DEBUG_FLAGS -Wcast-align -Wmissing-declarations -Winline -Wno-long-long -Wno-error=extra -Wno-error=unused-parameter -Wno-inline -Wno-error=delete-non-virtual-dtor -Wno-error=sign-compare -Wno-error=reorder -Wno-error=missing-declarations)
|
||||||
|
|
||||||
|
FOREACH(FLAG ${ADDITIONAL_DEBUG_FLAGS})
|
||||||
|
CHECK_CXX_COMPILER_FLAG("${FLAG}" CXX_HAS_WARNING_${FLAG})
|
||||||
|
IF(CXX_HAS_WARNING_${FLAG})
|
||||||
|
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAG}")
|
||||||
|
ENDIF()
|
||||||
|
ENDFOREACH()
|
||||||
ELSE()
|
ELSE()
|
||||||
# other: osx/llvm, bsd/llvm
|
# other: osx/llvm, bsd/llvm
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2")
|
set(CMAKE_CXX_FLAGS_RELEASE "-O2")
|
||||||
|
|
|
@ -113,7 +113,7 @@ DlgEditTokens::DlgEditTokens(CardDatabaseModel *_cardDatabaseModel, QWidget *par
|
||||||
setWindowTitle(tr("Edit tokens"));
|
setWindowTitle(tr("Edit tokens"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DlgEditTokens::tokenSelectionChanged(const QModelIndex ¤t, const QModelIndex &previous)
|
void DlgEditTokens::tokenSelectionChanged(const QModelIndex ¤t, const QModelIndex & /* previous */)
|
||||||
{
|
{
|
||||||
const QModelIndex realIndex = cardDatabaseDisplayModel->mapToSource(current);
|
const QModelIndex realIndex = cardDatabaseDisplayModel->mapToSource(current);
|
||||||
CardInfo *cardInfo = current.row() >= 0 ? cardDatabaseModel->getCard(realIndex.row()) : cardDatabaseModel->getDatabase()->getCard();
|
CardInfo *cardInfo = current.row() >= 0 ? cardDatabaseModel->getCard(realIndex.row()) : cardDatabaseModel->getDatabase()->getCard();
|
||||||
|
|
|
@ -18,10 +18,10 @@ public:
|
||||||
virtual void enable() { enabled = true; nodeChanged(); }
|
virtual void enable() { enabled = true; nodeChanged(); }
|
||||||
virtual void disable() { enabled = false; nodeChanged(); }
|
virtual void disable() { enabled = false; nodeChanged(); }
|
||||||
virtual FilterTreeNode *parent() const { return NULL; }
|
virtual FilterTreeNode *parent() const { return NULL; }
|
||||||
virtual FilterTreeNode *nodeAt(int i) const { return NULL; }
|
virtual FilterTreeNode *nodeAt(int /* i */) const { return NULL; }
|
||||||
virtual void deleteAt(int i) {}
|
virtual void deleteAt(int /* i */) {}
|
||||||
virtual int childCount() const { return 0; }
|
virtual int childCount() const { return 0; }
|
||||||
virtual int childIndex(const FilterTreeNode *node) const { return -1; }
|
virtual int childIndex(const FilterTreeNode * /* node */) const { return -1; }
|
||||||
virtual int index() const { return (parent() != NULL)? parent()->childIndex(this) : -1; }
|
virtual int index() const { return (parent() != NULL)? parent()->childIndex(this) : -1; }
|
||||||
virtual QString text() const { return QString(textCStr()); }
|
virtual QString text() const { return QString(textCStr()); }
|
||||||
virtual bool isLeaf() const { return false; }
|
virtual bool isLeaf() const { return false; }
|
||||||
|
@ -48,7 +48,7 @@ class FilterTreeBranch : public FilterTreeNode {
|
||||||
protected:
|
protected:
|
||||||
QList<T> childNodes;
|
QList<T> childNodes;
|
||||||
public:
|
public:
|
||||||
~FilterTreeBranch();
|
virtual ~FilterTreeBranch();
|
||||||
FilterTreeNode *nodeAt(int i) const;
|
FilterTreeNode *nodeAt(int i) const;
|
||||||
void deleteAt(int i);
|
void deleteAt(int i);
|
||||||
int childCount() const { return childNodes.size(); }
|
int childCount() const { return childNodes.size(); }
|
||||||
|
@ -102,6 +102,7 @@ public:
|
||||||
|
|
||||||
FilterItem(QString trm, FilterItemList *parent)
|
FilterItem(QString trm, FilterItemList *parent)
|
||||||
: p(parent), term(trm) {}
|
: p(parent), term(trm) {}
|
||||||
|
virtual ~FilterItem() {};
|
||||||
|
|
||||||
CardFilter::Attr attr() const { return p->attr(); }
|
CardFilter::Attr attr() const { return p->attr(); }
|
||||||
CardFilter::Type type() const { return p->type; }
|
CardFilter::Type type() const { return p->type; }
|
||||||
|
|
|
@ -33,7 +33,7 @@ ServerInfo_User LocalServer_DatabaseInterface::getUserData(const QString &name,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
AuthenticationResult LocalServer_DatabaseInterface::checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reasonStr, int &secondsLeft)
|
AuthenticationResult LocalServer_DatabaseInterface::checkUserPassword(Server_ProtocolHandler * /* handler */, const QString & /* user */, const QString & /* password */, QString & /* reasonStr */, int & /* secondsLeft */)
|
||||||
{
|
{
|
||||||
return UnknownUser;
|
return UnknownUser;
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,7 +136,6 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
qsrand(QDateTime::currentDateTime().toTime_t());
|
qsrand(QDateTime::currentDateTime().toTime_t());
|
||||||
|
|
||||||
bool startMainProgram = true;
|
|
||||||
#if QT_VERSION < 0x050000
|
#if QT_VERSION < 0x050000
|
||||||
const QString dataDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
|
const QString dataDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -43,7 +43,7 @@ void ReplayTimelineWidget::setTimeline(const QList<int> &_replayTimeline)
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReplayTimelineWidget::paintEvent(QPaintEvent *event)
|
void ReplayTimelineWidget::paintEvent(QPaintEvent * /* event */)
|
||||||
{
|
{
|
||||||
QPainter painter(this);
|
QPainter painter(this);
|
||||||
painter.drawRect(0, 0, width() - 1, height() - 1);
|
painter.drawRect(0, 0, width() - 1, height() - 1);
|
||||||
|
|
|
@ -254,7 +254,7 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor, GameReplay *_replay)
|
||||||
|
|
||||||
// Create list: event number -> time [ms]
|
// Create list: event number -> time [ms]
|
||||||
// Distribute simultaneous events evenly across 1 second.
|
// Distribute simultaneous events evenly across 1 second.
|
||||||
int lastEventTimestamp = -1;
|
unsigned int lastEventTimestamp = 0;
|
||||||
const int eventCount = replay->event_list_size();
|
const int eventCount = replay->event_list_size();
|
||||||
for (int i = 0; i < eventCount; ++i) {
|
for (int i = 0; i < eventCount; ++i) {
|
||||||
int j = i + 1;
|
int j = i + 1;
|
||||||
|
|
|
@ -202,7 +202,7 @@ void TabReplays::actDownload()
|
||||||
client->sendCommand(pend);
|
client->sendCommand(pend);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabReplays::downloadFinished(const Response &r, const CommandContainer &commandContainer, const QVariant &extraData)
|
void TabReplays::downloadFinished(const Response &r, const CommandContainer & /* commandContainer */, const QVariant &extraData)
|
||||||
{
|
{
|
||||||
if (r.response_code() != Response::RespOk)
|
if (r.response_code() != Response::RespOk)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -76,7 +76,7 @@ void CloseButton::paintEvent(QPaintEvent * /*event*/)
|
||||||
}
|
}
|
||||||
|
|
||||||
TabSupervisor::TabSupervisor(AbstractClient *_client, QWidget *parent)
|
TabSupervisor::TabSupervisor(AbstractClient *_client, QWidget *parent)
|
||||||
: QTabWidget(parent), userInfo(0), client(_client), tabUserLists(0), tabServer(0), tabDeckStorage(0), tabAdmin(0), tabReplays(0)
|
: QTabWidget(parent), userInfo(0), client(_client), tabServer(0), tabUserLists(0), tabDeckStorage(0), tabReplays(0), tabAdmin(0)
|
||||||
{
|
{
|
||||||
tabChangedIcon = new QIcon(":/resources/icon_tab_changed.svg");
|
tabChangedIcon = new QIcon(":/resources/icon_tab_changed.svg");
|
||||||
setElideMode(Qt::ElideRight);
|
setElideMode(Qt::ElideRight);
|
||||||
|
|
|
@ -355,7 +355,8 @@ DeckList::DeckList()
|
||||||
|
|
||||||
// TODO: http://qt-project.org/doc/qt-4.8/qobject.html#no-copy-constructor-or-assignment-operator
|
// TODO: http://qt-project.org/doc/qt-4.8/qobject.html#no-copy-constructor-or-assignment-operator
|
||||||
DeckList::DeckList(const DeckList &other)
|
DeckList::DeckList(const DeckList &other)
|
||||||
: name(other.name),
|
: QObject(),
|
||||||
|
name(other.name),
|
||||||
comments(other.comments),
|
comments(other.comments),
|
||||||
deckHash(other.deckHash)
|
deckHash(other.deckHash)
|
||||||
{
|
{
|
||||||
|
|
|
@ -97,7 +97,7 @@ protected slots:
|
||||||
void externalGameEventContainerReceived(const GameEventContainer &cont, qint64 sessionId);
|
void externalGameEventContainerReceived(const GameEventContainer &cont, qint64 sessionId);
|
||||||
void externalResponseReceived(const Response &resp, qint64 sessionId);
|
void externalResponseReceived(const Response &resp, qint64 sessionId);
|
||||||
|
|
||||||
virtual void doSendIslMessage(const IslMessage &msg, int serverId) { }
|
virtual void doSendIslMessage(const IslMessage & /* msg */, int /* serverId */) { }
|
||||||
protected:
|
protected:
|
||||||
void prepareDestroy();
|
void prepareDestroy();
|
||||||
void setDatabaseInterface(Server_DatabaseInterface *_databaseInterface);
|
void setDatabaseInterface(Server_DatabaseInterface *_databaseInterface);
|
||||||
|
|
|
@ -12,18 +12,18 @@ public:
|
||||||
: QObject(parent) { }
|
: QObject(parent) { }
|
||||||
|
|
||||||
virtual AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reasonStr, int &secondsLeft) = 0;
|
virtual AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reasonStr, int &secondsLeft) = 0;
|
||||||
virtual bool userExists(const QString &user) { return false; }
|
virtual bool userExists(const QString & /* user */) { return false; }
|
||||||
virtual QMap<QString, ServerInfo_User> getBuddyList(const QString &name) { return QMap<QString, ServerInfo_User>(); }
|
virtual QMap<QString, ServerInfo_User> getBuddyList(const QString & /* name */) { return QMap<QString, ServerInfo_User>(); }
|
||||||
virtual QMap<QString, ServerInfo_User> getIgnoreList(const QString &name) { return QMap<QString, ServerInfo_User>(); }
|
virtual QMap<QString, ServerInfo_User> getIgnoreList(const QString & /* name */) { return QMap<QString, ServerInfo_User>(); }
|
||||||
virtual bool isInBuddyList(const QString &whoseList, const QString &who) { return false; }
|
virtual bool isInBuddyList(const QString & /* whoseList */, const QString & /* who */) { return false; }
|
||||||
virtual bool isInIgnoreList(const QString &whoseList, const QString &who) { return false; }
|
virtual bool isInIgnoreList(const QString & /* whoseList */, const QString & /* who */) { return false; }
|
||||||
virtual ServerInfo_User getUserData(const QString &name, bool withId = false) = 0;
|
virtual ServerInfo_User getUserData(const QString &name, bool withId = false) = 0;
|
||||||
virtual void storeGameInformation(const QString &roomName, const QStringList &roomGameTypes, const ServerInfo_Game &gameInfo, const QSet<QString> &allPlayersEver, const QSet<QString> &allSpectatorsEver, const QList<GameReplay *> &replayList) { }
|
virtual void storeGameInformation(const QString & /* roomName */, const QStringList & /* roomGameTypes */, const ServerInfo_Game & /* gameInfo */, const QSet<QString> & /* allPlayersEver */, const QSet<QString> & /* allSpectatorsEver */, const QList<GameReplay *> & /* replayList */) { }
|
||||||
virtual DeckList *getDeckFromDatabase(int deckId, int userId) { return 0; }
|
virtual DeckList *getDeckFromDatabase(int /* deckId */, int /* userId */) { return 0; }
|
||||||
|
|
||||||
virtual qint64 startSession(const QString &userName, const QString &address) { return 0; }
|
virtual qint64 startSession(const QString & /* userName */, const QString & /* address */) { return 0; }
|
||||||
public slots:
|
public slots:
|
||||||
virtual void endSession(qint64 sessionId) { }
|
virtual void endSession(qint64 /* sessionId */ ) { }
|
||||||
public:
|
public:
|
||||||
virtual int getNextGameId() = 0;
|
virtual int getNextGameId() = 0;
|
||||||
virtual int getNextReplayId() = 0;
|
virtual int getNextReplayId() = 0;
|
||||||
|
@ -31,7 +31,7 @@ public:
|
||||||
virtual void clearSessionTables() { }
|
virtual void clearSessionTables() { }
|
||||||
virtual void lockSessionTables() { }
|
virtual void lockSessionTables() { }
|
||||||
virtual void unlockSessionTables() { }
|
virtual void unlockSessionTables() { }
|
||||||
virtual bool userSessionExists(const QString &userName) { return false; }
|
virtual bool userSessionExists(const QString & /* userName */) { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1594,7 +1594,7 @@ Response::ResponseCode Server_Player::cmdRevealCards(const Command_RevealCards &
|
||||||
return Response::RespOk;
|
return Response::RespOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Response::ResponseCode Server_Player::cmdChangeZoneProperties(const Command_ChangeZoneProperties &cmd, ResponseContainer &rc, GameEventStorage &ges)
|
Response::ResponseCode Server_Player::cmdChangeZoneProperties(const Command_ChangeZoneProperties &cmd, ResponseContainer & /* rc */, GameEventStorage &ges)
|
||||||
{
|
{
|
||||||
Server_CardZone *zone = zones.value(QString::fromStdString(cmd.zone_name()));
|
Server_CardZone *zone = zones.value(QString::fromStdString(cmd.zone_name()));
|
||||||
if (!zone)
|
if (!zone)
|
||||||
|
|
|
@ -49,7 +49,7 @@ protected:
|
||||||
AuthenticationResult authState;
|
AuthenticationResult authState;
|
||||||
bool acceptsUserListChanges;
|
bool acceptsUserListChanges;
|
||||||
bool acceptsRoomListChanges;
|
bool acceptsRoomListChanges;
|
||||||
virtual void logDebugMessage(const QString &message) { }
|
virtual void logDebugMessage(const QString & /* message */) { }
|
||||||
private:
|
private:
|
||||||
QList<int> messageSizeOverTime, messageCountOverTime;
|
QList<int> messageSizeOverTime, messageCountOverTime;
|
||||||
int timeRunning, lastDataReceived;
|
int timeRunning, lastDataReceived;
|
||||||
|
@ -71,13 +71,13 @@ private:
|
||||||
Response::ResponseCode cmdJoinGame(const Command_JoinGame &cmd, Server_Room *room, ResponseContainer &rc);
|
Response::ResponseCode cmdJoinGame(const Command_JoinGame &cmd, Server_Room *room, ResponseContainer &rc);
|
||||||
|
|
||||||
Response::ResponseCode processSessionCommandContainer(const CommandContainer &cont, ResponseContainer &rc);
|
Response::ResponseCode processSessionCommandContainer(const CommandContainer &cont, ResponseContainer &rc);
|
||||||
virtual Response::ResponseCode processExtendedSessionCommand(int cmdType, const SessionCommand &cmd, ResponseContainer &rc) { return Response::RespFunctionNotAllowed; }
|
virtual Response::ResponseCode processExtendedSessionCommand(int /* cmdType */, const SessionCommand & /* cmd */, ResponseContainer & /* rc */) { return Response::RespFunctionNotAllowed; }
|
||||||
Response::ResponseCode processRoomCommandContainer(const CommandContainer &cont, ResponseContainer &rc);
|
Response::ResponseCode processRoomCommandContainer(const CommandContainer &cont, ResponseContainer &rc);
|
||||||
Response::ResponseCode processGameCommandContainer(const CommandContainer &cont, ResponseContainer &rc);
|
Response::ResponseCode processGameCommandContainer(const CommandContainer &cont, ResponseContainer &rc);
|
||||||
Response::ResponseCode processModeratorCommandContainer(const CommandContainer &cont, ResponseContainer &rc);
|
Response::ResponseCode processModeratorCommandContainer(const CommandContainer &cont, ResponseContainer &rc);
|
||||||
virtual Response::ResponseCode processExtendedModeratorCommand(int cmdType, const ModeratorCommand &cmd, ResponseContainer &rc) { return Response::RespFunctionNotAllowed; }
|
virtual Response::ResponseCode processExtendedModeratorCommand(int /* cmdType */, const ModeratorCommand & /* cmd */, ResponseContainer & /* rc */) { return Response::RespFunctionNotAllowed; }
|
||||||
Response::ResponseCode processAdminCommandContainer(const CommandContainer &cont, ResponseContainer &rc);
|
Response::ResponseCode processAdminCommandContainer(const CommandContainer &cont, ResponseContainer &rc);
|
||||||
virtual Response::ResponseCode processExtendedAdminCommand(int cmdType, const AdminCommand &cmd, ResponseContainer &rc) { return Response::RespFunctionNotAllowed; }
|
virtual Response::ResponseCode processExtendedAdminCommand(int /* cmdType */, const AdminCommand & /* cmd */, ResponseContainer & /* rc */) { return Response::RespFunctionNotAllowed; }
|
||||||
private slots:
|
private slots:
|
||||||
void pingClockTimeout();
|
void pingClockTimeout();
|
||||||
public slots:
|
public slots:
|
||||||
|
|
|
@ -383,7 +383,7 @@ void SaveSetsPage::initializePage()
|
||||||
QMessageBox::critical(this, tr("Error"), tr("No set has been imported."));
|
QMessageBox::critical(this, tr("Error"), tr("No set has been imported."));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveSetsPage::updateTotalProgress(int cardsImported, int setIndex, const QString &setName)
|
void SaveSetsPage::updateTotalProgress(int cardsImported, int /* setIndex */, const QString &setName)
|
||||||
{
|
{
|
||||||
if (setName.isEmpty()) {
|
if (setName.isEmpty()) {
|
||||||
messageLog->append("<b>" + tr("Import finished: %1 cards.").arg(wizard()->importer->getCardList().size()) + "</b>");
|
messageLog->append("<b>" + tr("Import finished: %1 cards.").arg(wizard()->importer->getCardList().size()) + "</b>");
|
||||||
|
|
|
@ -37,6 +37,23 @@ RNG_Abstract *rng;
|
||||||
ServerLogger *logger;
|
ServerLogger *logger;
|
||||||
QThread *loggerThread;
|
QThread *loggerThread;
|
||||||
|
|
||||||
|
/* Prototypes */
|
||||||
|
|
||||||
|
void testRNG();
|
||||||
|
void testHash();
|
||||||
|
#if QT_VERSION < 0x050000
|
||||||
|
void myMessageOutput(QtMsgType type, const char *msg);
|
||||||
|
void myMessageOutput2(QtMsgType type, const char *msg);
|
||||||
|
#else
|
||||||
|
void myMessageOutput(QtMsgType type, const QMessageLogContext &, const QString &msg);
|
||||||
|
void myMessageOutput2(QtMsgType type, const QMessageLogContext &, const QString &msg);
|
||||||
|
#endif
|
||||||
|
#ifdef Q_OS_UNIX
|
||||||
|
void sigSegvHandler(int sig);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Implementations */
|
||||||
|
|
||||||
void testRNG()
|
void testRNG()
|
||||||
{
|
{
|
||||||
const int n = 500000;
|
const int n = 500000;
|
||||||
|
|
|
@ -18,12 +18,15 @@ QString PasswordHasher::computeHash(const QString &password, const QString &salt
|
||||||
|
|
||||||
QByteArray passwordBuffer = (salt + password).toUtf8();
|
QByteArray passwordBuffer = (salt + password).toUtf8();
|
||||||
int hashLen = gcry_md_get_algo_dlen(algo);
|
int hashLen = gcry_md_get_algo_dlen(algo);
|
||||||
char hash[hashLen], tmp[hashLen];
|
char *hash = new char[hashLen], *tmp = new char[hashLen];
|
||||||
gcry_md_hash_buffer(algo, hash, passwordBuffer.data(), passwordBuffer.size());
|
gcry_md_hash_buffer(algo, hash, passwordBuffer.data(), passwordBuffer.size());
|
||||||
for (int i = 1; i < rounds; ++i) {
|
for (int i = 1; i < rounds; ++i) {
|
||||||
memcpy(tmp, hash, hashLen);
|
memcpy(tmp, hash, hashLen);
|
||||||
gcry_md_hash_buffer(algo, hash, tmp, hashLen);
|
gcry_md_hash_buffer(algo, hash, tmp, hashLen);
|
||||||
}
|
}
|
||||||
return salt + QString(QByteArray(hash, hashLen).toBase64());
|
QString hashedPass = salt + QString(QByteArray(hash, hashLen).toBase64());
|
||||||
|
delete[] tmp;
|
||||||
|
delete[] hash;
|
||||||
|
return hashedPass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue