MuseScore/mscore/drumview.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

522 lines
15 KiB
C++
Raw Normal View History

2012-05-26 14:49:10 +02:00
//=============================================================================
// MusE Score
// Linux Music Score Editor
//
// Copyright (C) 2010 Werner Schweer and others
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2.
//
// 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================
#include "drumview.h"
#include "libmscore/staff.h"
#include "piano.h"
#include "libmscore/measure.h"
#include "libmscore/chord.h"
#include "libmscore/score.h"
#include "libmscore/note.h"
#include "libmscore/slur.h"
#include "libmscore/segment.h"
2013-05-13 18:49:17 +02:00
namespace Ms {
2012-05-26 14:49:10 +02:00
static const int MAP_OFFSET = 480;
//---------------------------------------------------------
// pitch2y
//---------------------------------------------------------
static int pitch2y(int pitch)
{
static int tt[] = {
12, 19, 25, 32, 38, 51, 58, 64, 71, 77, 84, 90
};
int y = (75 * keyHeight) - (tt[pitch % 12] + (7 * keyHeight) * (pitch / 12));
if (y < 0) {
y = 0;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
return y;
}
//---------------------------------------------------------
// DrumItem
//---------------------------------------------------------
2020-05-29 18:47:27 +02:00
DrumItem::DrumItem(Note* n)
: QGraphicsPolygonItem(), _note(n)
2012-05-26 14:49:10 +02:00
{
setFlags(flags() | QGraphicsItem::ItemIsSelectable);
int pitch = _note->pitch();
2012-05-26 14:49:10 +02:00
QPolygonF p;
double h2 = keyHeight / 2;
p << QPointF(0, -h2) << QPointF(h2, 0.0) << QPointF(0.0, h2) << QPointF(-h2, 0.0);
setPolygon(p);
setBrush(QBrush());
setSelected(_note->selected());
setData(0, QVariant::fromValue<void*>(_note));
2020-05-26 15:54:26 +02:00
setPos(_note->chord()->tick().ticks() + 480, pitch2y(pitch) + keyHeight / 4);
2012-05-26 14:49:10 +02:00
setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
}
//---------------------------------------------------------
// paint
//---------------------------------------------------------
void DrumItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*)
{
// Chord* chord = note->chord();
2012-11-19 09:29:46 +01:00
int x1 = 0; // note->onTimeOffset() + note->onTimeUserOffset();
2012-05-26 14:49:10 +02:00
painter->setPen(pen());
painter->setBrush(isSelected() ? Qt::yellow : Qt::blue);
painter->drawPolygon(polygon().translated(x1, 0.0));
}
//---------------------------------------------------------
// pix2pos
//---------------------------------------------------------
Pos DrumView::pix2pos(int x) const
{
x -= MAP_OFFSET;
if (x < 0) {
x = 0;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
return Pos(staff->score()->tempomap(), staff->score()->sigmap(), x, _timeType);
}
//---------------------------------------------------------
// pos2pix
//---------------------------------------------------------
int DrumView::pos2pix(const Pos& p) const
{
return p.time(_timeType) + MAP_OFFSET;
}
//---------------------------------------------------------
// drawBackground
//---------------------------------------------------------
void DrumView::drawBackground(QPainter* p, const QRectF& r)
{
if (staff == 0) {
return;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
Score* _score = staff->score();
2020-05-26 15:54:26 +02:00
2012-05-26 14:49:10 +02:00
QRectF r1;
r1.setCoords(-1000000.0, 0.0, 480.0, 1000000.0);
QRectF r2;
r2.setCoords(ticks + 480, 0.0, 1000000.0, 1000000.0);
QColor bg(0x71, 0x8d, 0xbe);
2020-05-26 15:54:26 +02:00
2012-05-26 14:49:10 +02:00
p->fillRect(r, bg);
if (r.intersects(r1)) {
p->fillRect(r.intersected(r1), bg.darker(150));
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
if (r.intersects(r2)) {
p->fillRect(r.intersected(r2), bg.darker(150));
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
//
// draw horizontal grid lines
//
qreal y1 = r.y();
qreal y2 = y1 + r.height();
2020-05-26 15:54:26 +02:00
qreal kh = 13.0;
2012-05-26 14:49:10 +02:00
qreal x1 = r.x();
qreal x2 = x1 + r.width();
2020-05-26 15:54:26 +02:00
2012-05-26 14:49:10 +02:00
int key = floor(y1 / 75);
qreal y = key * kh;
2020-05-26 15:54:26 +02:00
2012-05-26 14:49:10 +02:00
for (; key < 75; ++key, y += kh) {
if (y < y1) {
continue;
2020-05-26 15:54:26 +02:00
}
if (y > y2) {
2012-05-26 14:49:10 +02:00
break;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
p->setPen(QPen((key % 7) == 5 ? Qt::lightGray : Qt::gray));
p->drawLine(QLineF(x1, y, x2, y));
2020-05-26 15:54:26 +02:00
}
//
2012-05-26 14:49:10 +02:00
// draw vertical grid lines
2020-05-26 15:54:26 +02:00
//
2012-05-26 14:49:10 +02:00
static const int mag[7] = {
1, 1, 2, 5, 10, 20, 50
2020-05-26 15:54:26 +02:00
};
2012-05-26 14:49:10 +02:00
Pos pos1 = pix2pos(x1);
Pos pos2 = pix2pos(x2);
2020-05-26 15:54:26 +02:00
2012-05-26 14:49:10 +02:00
//---------------------------------------------------
// draw raster
//---------------------------------------------------
2020-05-26 15:54:26 +02:00
2012-05-26 14:49:10 +02:00
int bar1, bar2, beat, tick;
pos1.mbt(&bar1, &beat, &tick);
pos2.mbt(&bar2, &beat, &tick);
2020-05-26 15:54:26 +02:00
2012-05-26 14:49:10 +02:00
int mi = mag[magStep < 0 ? 0 : magStep];
2020-05-26 15:54:26 +02:00
2012-05-26 14:49:10 +02:00
bar1 = (bar1 / mi) * mi; // round down
if (bar1 && mi >= 2) {
2012-05-26 14:49:10 +02:00
bar1 -= 1;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
bar2 = ((bar2 + mi - 1) / mi) * mi; // round up
2020-05-26 15:54:26 +02:00
2012-05-26 14:49:10 +02:00
for (int bar = bar1; bar <= bar2;) {
Pos stick(_score->tempomap(), _score->sigmap(), bar, 0, 0);
if (magStep > 0) {
double x = double(pos2pix(stick));
if (x > 0) {
p->setPen(Qt::lightGray);
p->drawLine(x, y1, x, y2);
2020-05-26 15:54:26 +02:00
} else {
2012-05-26 14:49:10 +02:00
p->setPen(Qt::black);
p->drawLine(x, y1, x, y1);
}
} else {
int z = stick.timesig().timesig().numerator();
for (int b = 0; b < z; b++) {
if (magStep == 0) {
Pos xx(_score->tempomap(), _score->sigmap(), bar, b, 0);
int xp = pos2pix(xx);
if (xp < 0) {
2012-05-26 14:49:10 +02:00
continue;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
if (xp > 0) {
p->setPen(b == 0 ? Qt::lightGray : Qt::gray);
p->drawLine(xp, y1, xp, y2);
} else {
p->setPen(Qt::black);
p->drawLine(xp, y1, xp, y2);
2020-05-26 15:54:26 +02:00
}
} else {
int k;
2012-05-26 14:49:10 +02:00
if (magStep == -1) {
2020-05-26 15:54:26 +02:00
k = 2;
2012-05-26 14:49:10 +02:00
} else if (magStep == -2) {
2020-05-26 15:54:26 +02:00
k = 4;
2012-05-26 14:49:10 +02:00
} else if (magStep == -3) {
2020-05-26 15:54:26 +02:00
k = 8;
2012-05-26 14:49:10 +02:00
} else if (magStep == -4) {
2020-05-26 15:54:26 +02:00
k = 16;
} else {
k = 32;
}
2012-05-26 14:49:10 +02:00
int n = (MScore::division * 4) / stick.timesig().timesig().denominator();
for (int i = 0; i < k; ++i) {
Pos xx(_score->tempomap(), _score->sigmap(), bar, b, (n * i) / k);
2012-05-26 14:49:10 +02:00
int xp = pos2pix(xx);
if (xp < 0) {
continue;
}
if (xp > 0) {
p->setPen(i == 0 && b == 0 ? Qt::lightGray : Qt::gray);
2012-05-26 14:49:10 +02:00
p->drawLine(xp, y1, xp, y2);
} else {
p->setPen(Qt::black);
p->drawLine(xp, y1, xp, y2);
}
}
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
}
}
if (bar == 0 && mi >= 2) {
bar += (mi - 1);
2020-05-26 15:54:26 +02:00
} else {
bar += mi;
2020-05-26 15:54:26 +02:00
}
}
}
2012-05-26 14:49:10 +02:00
//---------------------------------------------------------
// DrumView
//---------------------------------------------------------
2020-05-29 18:47:27 +02:00
DrumView::DrumView()
: QGraphicsView()
2012-05-26 14:49:10 +02:00
{
setScene(new QGraphicsScene);
setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
setResizeAnchor(QGraphicsView::AnchorUnderMouse);
setMouseTracking(true);
setRubberBandSelectionMode(Qt::IntersectsItemBoundingRect);
setDragMode(QGraphicsView::RubberBandDrag);
2014-05-26 15:49:20 +02:00
_timeType = TType::TICKS;
2012-05-26 14:49:10 +02:00
magStep = 0;
}
//---------------------------------------------------------
// setStaff
//---------------------------------------------------------
void DrumView::setStaff(Staff* s, Pos* l)
{
static const QColor lcColors[3] = { Qt::red, Qt::blue, Qt::blue };
2020-05-26 15:54:26 +02:00
2012-05-26 14:49:10 +02:00
staff = s;
_locator = l;
pos.setContext(s->score()->tempomap(), s->score()->sigmap());
2020-05-26 15:54:26 +02:00
2012-05-26 14:49:10 +02:00
scene()->blockSignals(true);
2020-05-26 15:54:26 +02:00
2012-05-26 14:49:10 +02:00
scene()->clear();
for (int i = 0; i < 3; ++i) {
locatorLines[i] = new QGraphicsLineItem(QLineF(0.0, 0.0, 0.0, keyHeight * 75.0 * 5));
QPen pen(lcColors[i]);
pen.setWidth(2);
locatorLines[i]->setPen(pen);
locatorLines[i]->setZValue(1000 + i); // set stacking order
locatorLines[i]->setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
scene()->addItem(locatorLines[i]);
}
2020-05-26 15:54:26 +02:00
2012-05-26 14:49:10 +02:00
int staffIdx = staff->idx();
int startTrack = staffIdx * VOICES;
int endTrack = startTrack + VOICES;
for (Segment* seg = staff->score()->firstSegment(SegmentType::All); seg; seg = seg->next1()) {
2012-05-26 14:49:10 +02:00
for (int track = startTrack; track < endTrack; ++track) {
Element* e = seg->element(track);
2017-01-18 14:16:33 +01:00
if (e == 0 || e->type() != ElementType::CHORD) {
2012-05-26 14:49:10 +02:00
continue;
}
Chord* chord = static_cast<Chord*>(e);
foreach (Note* n, chord->notes()) {
if (n->tieBack()) {
2012-05-26 14:49:10 +02:00
continue;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
scene()->addItem(new DrumItem(n));
}
2020-05-26 15:54:26 +02:00
}
}
2012-05-26 14:49:10 +02:00
scene()->blockSignals(false);
2020-05-26 15:54:26 +02:00
2012-05-26 14:49:10 +02:00
Measure* lm = staff->score()->lastMeasure();
ticks = (lm->tick() + lm->ticks()).ticks();
2012-05-26 14:49:10 +02:00
scene()->setSceneRect(0.0, 0.0, double(ticks + 960), keyHeight * 75);
2020-05-26 15:54:26 +02:00
2012-05-26 14:49:10 +02:00
for (int i = 0; i < 3; ++i) {
moveLocator(i);
2020-05-26 15:54:26 +02:00
}
//
2012-05-26 14:49:10 +02:00
// move to something interesting
2020-05-26 15:54:26 +02:00
//
2012-05-26 14:49:10 +02:00
QList<QGraphicsItem*> items = scene()->selectedItems();
QRectF boundingRect;
foreach (QGraphicsItem* item, items) {
Note* note = static_cast<Note*>(item->data(0).value<void*>());
if (note) {
boundingRect |= item->mapToScene(item->boundingRect()).boundingRect();
2020-05-26 15:54:26 +02:00
}
}
2012-05-26 14:49:10 +02:00
centerOn(boundingRect.center());
}
//---------------------------------------------------------
// moveLocator
//---------------------------------------------------------
void DrumView::moveLocator(int i)
{
if (_locator[i].valid()) {
locatorLines[i]->setVisible(true);
qreal x = qreal(pos2pix(_locator[i]));
locatorLines[i]->setPos(QPointF(x, 0.0));
} else {
locatorLines[i]->setVisible(false);
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// wheelEvent
//---------------------------------------------------------
void DrumView::wheelEvent(QWheelEvent* event)
{
Fix Deprecation warnings with Qt 5.15 (and 5.14) * fix 383 warnings C4996 (deprecated) with one single line change * fix 5 'empty' warnings about invalid slots, not sure the remaining slots serve any purpose though * disable warnings C4127 and C4996 for thirdparty/google_analytics * fix 30 warnings C4996 using the suggested alternatives available since at least Qt 5.9, so won't break building against that * change as requested in code review plus some more fixes using the same idea * fixing yet more warnings * disable deprecation warnings in qoogle_analytics for MinGW too although I believe maxOS and Linux may use those too. Easy to extend to those, if need be. * Fix qml runtime warnings exactly following the advice given by that warning, but without really know what I'm doing here or whether that is still backwards compatible to Qt 5.9. * Use replacements as suggested, if available and no `endl` neded with `qDebug()` * fix 24 more * 2 more * 7 more (one only seen in DEBUG mode) * Fix the `endl` warnings * maybe more changes this way? * Add all warnings C5999 or bigger to the ignore list for telemetry with Qt 5.15 Beta 1 as avoiding only C26439, C26444,C 26452, C26495, C26498, C26812 isn't possible * fix 2 deprecation warning new with Qt 5.15 beta 1 * fix 4 new warnings and also Qt 5.12 builds, disable some dead code * fix deprecation warnings new with Qt 5.15's MSVC 2019 integration and revert some (`QNetworkReply::networkError()`) that Qt 5.15 beta 2 reverted too * fix warning reg. obsolete operator < for QVariants * revert changes needed prior to beta 3 And clarifying some earlier changes * mark ToDos * fix warning reg QString()::null * fix a 'regression' from a revert of an earlier change
2020-06-03 12:59:19 +02:00
int step = event->angleDelta().y() / 120;
2012-05-26 14:49:10 +02:00
double xmag = transform().m11();
double ymag = transform().m22();
2020-05-26 15:54:26 +02:00
2012-05-26 14:49:10 +02:00
if (event->modifiers() == Qt::ControlModifier) {
if (step > 0) {
for (int i = 0; i < step; ++i) {
if (xmag > 10.0) {
break;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
scale(1.1, 1.0);
xmag *= 1.1;
}
} else {
for (int i = 0; i < -step; ++i) {
if (xmag < 0.001) {
2020-05-26 15:54:26 +02:00
break;
}
2012-05-26 14:49:10 +02:00
scale(.9, 1.0);
xmag *= .9;
}
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
emit magChanged(xmag, ymag);
2020-05-26 15:54:26 +02:00
2012-05-26 14:49:10 +02:00
int tpix = (480 * 4) * xmag;
magStep = -5;
if (tpix <= 4000) {
magStep = -4;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
if (tpix <= 2000) {
magStep = -3;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
if (tpix <= 1000) {
magStep = -2;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
if (tpix <= 500) {
magStep = -1;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
if (tpix <= 128) {
magStep = 0;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
if (tpix <= 64) {
magStep = 1;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
if (tpix <= 32) {
magStep = 2;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
if (tpix <= 16) {
magStep = 3;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
if (tpix <= 8) {
magStep = 4;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
if (tpix <= 4) {
magStep = 5;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
if (tpix <= 2) {
magStep = 6;
2020-05-26 15:54:26 +02:00
}
//
2012-05-26 14:49:10 +02:00
// if xpos <= 0, then the scene is centered
// there is no scroll bar anymore sending
// change signals, so we have to do it here:
2020-05-26 15:54:26 +02:00
//
2012-05-26 14:49:10 +02:00
double xpos = -(mapFromScene(QPointF()).x());
if (xpos <= 0) {
emit xposChanged(xpos);
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
} else if (event->modifiers() == Qt::ShiftModifier) {
Fix Deprecation warnings with Qt 5.15 (and 5.14) * fix 383 warnings C4996 (deprecated) with one single line change * fix 5 'empty' warnings about invalid slots, not sure the remaining slots serve any purpose though * disable warnings C4127 and C4996 for thirdparty/google_analytics * fix 30 warnings C4996 using the suggested alternatives available since at least Qt 5.9, so won't break building against that * change as requested in code review plus some more fixes using the same idea * fixing yet more warnings * disable deprecation warnings in qoogle_analytics for MinGW too although I believe maxOS and Linux may use those too. Easy to extend to those, if need be. * Fix qml runtime warnings exactly following the advice given by that warning, but without really know what I'm doing here or whether that is still backwards compatible to Qt 5.9. * Use replacements as suggested, if available and no `endl` neded with `qDebug()` * fix 24 more * 2 more * 7 more (one only seen in DEBUG mode) * Fix the `endl` warnings * maybe more changes this way? * Add all warnings C5999 or bigger to the ignore list for telemetry with Qt 5.15 Beta 1 as avoiding only C26439, C26444,C 26452, C26495, C26498, C26812 isn't possible * fix 2 deprecation warning new with Qt 5.15 beta 1 * fix 4 new warnings and also Qt 5.12 builds, disable some dead code * fix deprecation warnings new with Qt 5.15's MSVC 2019 integration and revert some (`QNetworkReply::networkError()`) that Qt 5.15 beta 2 reverted too * fix warning reg. obsolete operator < for QVariants * revert changes needed prior to beta 3 And clarifying some earlier changes * mark ToDos * fix warning reg QString()::null * fix a 'regression' from a revert of an earlier change
2020-06-03 12:59:19 +02:00
QWheelEvent we(event->position(), event->globalPosition(), event->pixelDelta(), event->angleDelta(),
event->buttons(), event->modifiers(), event->phase(), event->inverted(), event->source());
2012-05-26 14:49:10 +02:00
QGraphicsView::wheelEvent(&we);
} else if (event->modifiers() == 0) {
QGraphicsView::wheelEvent(event);
} else if (event->modifiers() == (Qt::ShiftModifier | Qt::ControlModifier)) {
if (step > 0) {
for (int i = 0; i < step; ++i) {
if (ymag > 3.0) {
2020-05-26 15:54:26 +02:00
break;
}
2012-05-26 14:49:10 +02:00
scale(1.0, 1.1);
ymag *= 1.1;
}
} else {
for (int i = 0; i < -step; ++i) {
if (ymag < 0.4) {
break;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
scale(1.0, .9);
ymag *= .9;
}
}
emit magChanged(xmag, ymag);
2020-05-26 15:54:26 +02:00
}
}
2012-05-26 14:49:10 +02:00
//---------------------------------------------------------
// y2pitch
//---------------------------------------------------------
int DrumView::y2pitch(int y) const
{
int pitch;
const int total = (10 * 7 + 5) * keyHeight; // 75 Ganztonschritte
y = total - y;
int oct = (y / (7 * keyHeight)) * 12;
static const char kt[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7,
8, 8, 8, 8, 8, 8, 8,
9, 9, 9, 9, 9, 9,
10, 10, 10, 10, 10, 10, 10,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11
};
pitch = kt[y % 91] + oct;
if (pitch < 0 || pitch > 127) {
pitch = -1;
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
return pitch;
}
//---------------------------------------------------------
// mouseMoveEvent
//---------------------------------------------------------
void DrumView::mouseMoveEvent(QMouseEvent* event)
{
QPointF p(mapToScene(event->pos()));
int pitch = y2pitch(int(p.y()));
emit pitchChanged(pitch);
int tick = int(p.x()) - 480;
if (tick < 0) {
tick = 0;
pos.setTick(tick);
pos.setInvalid();
} else {
pos.setTick(tick);
2020-05-26 15:54:26 +02:00
}
2012-05-26 14:49:10 +02:00
emit posChanged(pos);
QGraphicsView::mouseMoveEvent(event);
}
//---------------------------------------------------------
// leaveEvent
//---------------------------------------------------------
void DrumView::leaveEvent(QEvent* event)
{
emit pitchChanged(-1);
pos.setInvalid();
emit posChanged(pos);
QGraphicsView::leaveEvent(event);
}
//---------------------------------------------------------
// ensureVisible
//---------------------------------------------------------
void DrumView::ensureVisible(int tick)
{
tick += MAP_OFFSET;
QPointF pt = mapToScene(0, height() / 2);
QGraphicsView::ensureVisible(qreal(tick), pt.y(), 240.0, 1.0);
}
2013-05-13 18:49:17 +02:00
}