From a9d68105c8730793f39d83822e8f3367e824aeb4 Mon Sep 17 00:00:00 2001 From: Niels Date: Fri, 18 Feb 2011 10:21:53 +0100 Subject: [PATCH] load file with crtl+o --- app.pro | 6 +- fileselector.cpp | 225 ++++++++++++++++++++++++++++++++++++++++++++ fileselector.h | 71 ++++++++++++++ main.cpp | 2 +- mainwidget.cpp | 20 ++++ mainwidget.h | 4 + mapwidget.cpp | 5 +- mapwidget.h | 1 + pics/bookmark.png | Bin 0 -> 1145 bytes pics/cancel.png | Bin 0 -> 848 bytes pics/icons.qrc | 9 ++ pics/nobookmark.png | Bin 0 -> 1082 bytes pics/ok.png | Bin 0 -> 601 bytes pics/up.png | Bin 0 -> 672 bytes 14 files changed, 340 insertions(+), 3 deletions(-) create mode 100644 fileselector.cpp create mode 100644 fileselector.h create mode 100644 pics/bookmark.png create mode 100644 pics/cancel.png create mode 100644 pics/icons.qrc create mode 100644 pics/nobookmark.png create mode 100644 pics/ok.png create mode 100644 pics/up.png diff --git a/app.pro b/app.pro index 1683219..89128c3 100644 --- a/app.pro +++ b/app.pro @@ -5,7 +5,6 @@ TEMPLATE = app QT += network -#LIBS += -Lmonav -lgpsgridclient -lcontractionhierarchiesclient INCLUDEPATH += monav SOURCES += main.cpp \ @@ -22,6 +21,7 @@ SOURCES += main.cpp \ mapwidget.cpp \ markerlist.cpp \ downloadwidget.cpp \ + fileselector.cpp \ searchwidget.cpp \ gpsclient.cpp @@ -38,5 +38,9 @@ HEADERS += mainwidget.h \ mapwidget.h \ markerlist.h \ downloadwidget.h \ + fileselector.h \ searchwidget.h \ gpsclient.h + +RESOURCES = pics/icons.qrc + diff --git a/fileselector.cpp b/fileselector.cpp new file mode 100644 index 0000000..e38fb05 --- /dev/null +++ b/fileselector.cpp @@ -0,0 +1,225 @@ +/* + * Copyright 2010-2011 Niels Kummerfeldt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "fileselector.h" + +#include +#include +#include +#include +#include + +FileSelector::FileSelector(QWidget *parent) + : QWidget(parent), + m_view(new QListView(this)), + m_model(new QFileSystemModel(this)), + m_title(new QLabel(this)), + m_path(new QLabel(this)), + m_bookmarkButton(new QPushButton(this)), + m_bookmarkMenu(new QMenu(this)), + m_bookmarks(), + m_signalMapper(new QSignalMapper(this)) +{ + QGridLayout *layout = new QGridLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + layout->setRowStretch(5, 1); + layout->setSpacing(0); + + m_title->setAlignment(Qt::AlignCenter); + layout->addWidget(m_title, 0, 0, 1, 2); + layout->addWidget(m_path, 1, 0, 1, 2); + + m_view->setModel(m_model); + connect(m_view, SIGNAL(activated(QModelIndex)), this, SLOT(enter(QModelIndex))); + layout->addWidget(m_view, 2, 0, 6, 1); + m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_view->setSelectionMode(QListView::ExtendedSelection); + QFont font = m_view->font(); + font.setPointSize(8); + m_view->setFont(font); + + m_model->setNameFilterDisables(false); + m_model->setRootPath("/"); + + connect(m_signalMapper, SIGNAL(mapped(QString)), this, SLOT(setCurrentDirectory(QString))); + + m_bookmarkButton->setIcon(QIcon(":nobookmark.png")); + m_bookmarkButton->setShortcut(QKeySequence(Qt::ALT+Qt::Key_B)); + connect(m_bookmarkButton, SIGNAL(clicked()), this, SLOT(toggleBookmark())); + layout->addWidget(m_bookmarkButton, 2, 1); + + QPushButton *button = new QPushButton(); + button->setIcon(QIcon(":up.png")); + button->setShortcut(QKeySequence(Qt::ALT+Qt::Key_Up)); + connect(button, SIGNAL(clicked()), this, SLOT(goUp())); + layout->addWidget(button, 3, 1); + + button = new QPushButton(); + button->setIcon(QIcon(":ok.png")); + connect(button, SIGNAL(clicked()), this, SLOT(accept())); + layout->addWidget(button, 6, 1); + + button = new QPushButton(); + button->setIcon(QIcon(":cancel.png")); + button->setShortcut(QKeySequence(Qt::Key_Escape)); + connect(button, SIGNAL(clicked()), this, SIGNAL(cancel())); + layout->addWidget(button, 7, 1); + + QSettings conf(QDir::homePath()+"Maps/nanomap.conf", QSettings::NativeFormat); + conf.beginGroup("fileselector"); + m_bookmarks = conf.value("bookmarks").toStringList(); + conf.endGroup(); + + setCurrentDirectory(m_model->index(QDir::homePath())); + updateBookmarkMenu(); + + m_view->setFocus(Qt::OtherFocusReason); + resize(320, 240); +} + +FileSelector::~FileSelector() +{ + QSettings conf(QDir::homePath()+"Maps/nanomap.conf", QSettings::NativeFormat); + conf.beginGroup("fileselector"); + conf.setValue("bookmarks", m_bookmarks); + conf.endGroup(); +} + +void FileSelector::setTitle(const QString &title) +{ + m_title->setText(""+title+""); +} + +void FileSelector::setFileTypes(const QStringList &types) +{ + m_model->setNameFilters(types); +} + +void FileSelector::keyPressEvent(QKeyEvent *event) +{ + if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_B) { + m_bookmarkMenu->popup(mapToGlobal(QPoint(0, 0))); + } +} + +void FileSelector::toggleBookmark() +{ + QString path = m_model->filePath(m_view->rootIndex()); + if (m_bookmarks.contains(path)) { + m_bookmarks.removeAll(path); + m_bookmarkButton->setIcon(QIcon(":nobookmark.png")); + } else { + m_bookmarks.append(path); + m_bookmarkButton->setIcon(QIcon(":bookmark.png")); + } + updateBookmarkMenu(); +} + +void FileSelector::goUp() +{ + QModelIndex current = m_view->rootIndex(); + if (current.isValid()) { + QModelIndex up = current.parent(); + if (up.isValid()) { + setCurrentDirectory(up); + } + } +} + +void FileSelector::accept() +{ + QModelIndex index = m_view->currentIndex(); + if (index.isValid()) { + if (!m_model->isDir(index)) { + emit fileSelected(m_model->filePath(index)); + } + } +} + +void FileSelector::enter(const QModelIndex &index) +{ + if (m_model->isDir(index)) { + setCurrentDirectory(index); + } else { + QModelIndexList selected = m_view->selectionModel()->selectedIndexes(); + QStringList files; + foreach (const QModelIndex &i, selected) { + files << m_model->filePath(i); + } + emit fileSelected(files.first()); + } +} + +void FileSelector::setCurrentDirectory(const QString &dir) +{ + setCurrentDirectory(m_model->index(dir)); +} + +void FileSelector::setCurrentDirectory(const QModelIndex &dir) +{ + m_view->setRootIndex(dir); + QString path = m_model->filePath(dir); + setPathLabel(path); + if (m_bookmarks.contains(path)) { + m_bookmarkButton->setIcon(QIcon(":bookmark.png")); + } else { + m_bookmarkButton->setIcon(QIcon(":nobookmark.png")); + } +} + +void FileSelector::updateBookmarkMenu() +{ + m_bookmarkMenu->clear(); + + if (m_bookmarks.isEmpty()) { + QAction *action = new QAction("No bookmarks", m_bookmarkMenu); + action->setIcon(QIcon(":nobookmark.png")); + m_bookmarkMenu->addAction(action); + return; + } + + foreach (const QString &bm, m_bookmarks) { + QAction *action = new QAction(shortText(bm, 290), m_bookmarkMenu); + action->setIcon(QIcon(":bookmark.png")); + m_bookmarkMenu->addAction(action); + connect(action, SIGNAL(triggered()), m_signalMapper, SLOT(map())); + m_signalMapper->setMapping(action, bm); + } +} + +void FileSelector::setPathLabel(const QString &dir) +{ + m_path->setText(shortText(dir, 310)); +} + +QString FileSelector::shortText(const QString &text, int width) +{ + QFontMetrics fm(m_path->font()); + + QString shortText = text; + int n = 0; + while (fm.width(shortText) > width) { + ++n; + shortText = text; + shortText.replace(0, n, "..."); + } + + return shortText; +} + diff --git a/fileselector.h b/fileselector.h new file mode 100644 index 0000000..5b41e72 --- /dev/null +++ b/fileselector.h @@ -0,0 +1,71 @@ +/* + * Copyright 2010-2011 Niels Kummerfeldt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef FILESELECTOR_H +#define FILESELECTOR_H + +#include +#include +#include +#include +#include +#include +#include + +class FileSelector : public QWidget +{ + Q_OBJECT +public: + FileSelector(QWidget *parent = 0); + ~FileSelector(); + + void setTitle(const QString &title); + void setFileTypes(const QStringList &types); + +signals: + void fileSelected(const QString &fileName); + void cancel(); + +protected: + void keyPressEvent(QKeyEvent *event); + +private slots: + void toggleBookmark(); + void goUp(); + void accept(); + void enter(const QModelIndex &index); + void setCurrentDirectory(const QString &dir); + +private: + void setCurrentDirectory(const QModelIndex &dir); + void updateBookmarkMenu(); + void setPathLabel(const QString &dir); + QString shortText(const QString &text, int width); + + QListView *m_view; + QFileSystemModel *m_model; + QLabel *m_title, *m_path; + QPushButton *m_bookmarkButton; + QMenu *m_bookmarkMenu; + QStringList m_bookmarks; + QSignalMapper *m_signalMapper; + +}; + +#endif // FILESELECTOR_H diff --git a/main.cpp b/main.cpp index ba596f7..da3d904 100644 --- a/main.cpp +++ b/main.cpp @@ -28,7 +28,7 @@ int main(int argc, char *argv[]) MainWidget w; if (QApplication::arguments().count() > 1) { - w.loadFile(QApplication::arguments().at(1), ""); + w.loadFile(QApplication::arguments().at(1)); } QObject::connect(&w, SIGNAL(close()), &a, SLOT(quit())); diff --git a/mainwidget.cpp b/mainwidget.cpp index 58f00fa..50cc57e 100644 --- a/mainwidget.cpp +++ b/mainwidget.cpp @@ -20,6 +20,7 @@ #include "mainwidget.h" #include "downloadwidget.h" +#include "fileselector.h" #include "mapwidget.h" #include "markerlist.h" #include "searchwidget.h" @@ -42,6 +43,7 @@ MainWidget::MainWidget(QWidget *parent) m_map(new MapWidget(this)), m_markerList(new MarkerList(this)), m_dlWidget(new DownloadWidget(this)), + m_fileSelector(new FileSelector(this)), m_search(new SearchWidget(this)) { QHBoxLayout *layout = new QHBoxLayout(this); @@ -73,6 +75,7 @@ MainWidget::MainWidget(QWidget *parent) connect(m_map, SIGNAL(close()), this, SIGNAL(close())); connect(m_map, SIGNAL(showMarkerList()), this, SLOT(showList())); connect(m_map, SIGNAL(downloadArea(int, QRectF)), this, SLOT(downloadArea(int, QRectF))); + connect(m_map, SIGNAL(loadFile()), this, SLOT(showFileSelector())); connect(m_map, SIGNAL(search()), this, SLOT(search())); m_stack->insertWidget(0, m_map); @@ -88,6 +91,11 @@ MainWidget::MainWidget(QWidget *parent) connect(m_search, SIGNAL(centerOn(qreal, qreal)), this, SLOT(showMap(qreal, qreal))); m_stack->insertWidget(3, m_search); + m_fileSelector->setFileTypes(QStringList() << "*.gpx" << "*.osm"); + connect(m_fileSelector, SIGNAL(cancel()), this, SLOT(showMap())); + connect(m_fileSelector, SIGNAL(fileSelected(QString)), this, SLOT(loadFile(QString))); + m_stack->insertWidget(4, m_fileSelector); + resize(320, 240); } @@ -95,6 +103,11 @@ MainWidget::~MainWidget() { } +void MainWidget::loadFile(const QString &fileName) +{ + loadFile(fileName, ""); +} + void MainWidget::loadFile(const QString &fileName, const QString &title) { if (fileName.endsWith(".gpx")) { @@ -108,6 +121,7 @@ void MainWidget::loadFile(const QString &fileName, const QString &title) QString t = title.isEmpty() ? "Points Of Interest" : title; m_map->addLayer(l, 3, t); } + showMap(); } void MainWidget::showList() @@ -123,6 +137,7 @@ void MainWidget::markerAdded(const QString &name) void MainWidget::showMap() { m_stack->setCurrentIndex(0); + m_map->setFocus(Qt::OtherFocusReason); } void MainWidget::showMap(qreal lon, qreal lat) @@ -143,3 +158,8 @@ void MainWidget::search() m_stack->setCurrentIndex(3); } +void MainWidget::showFileSelector() +{ + m_stack->setCurrentIndex(4); +} + diff --git a/mainwidget.h b/mainwidget.h index 0f3d297..cce1360 100644 --- a/mainwidget.h +++ b/mainwidget.h @@ -25,6 +25,7 @@ #include class DownloadWidget; +class FileSelector; class MapWidget; class MarkerList; class SearchWidget; @@ -37,6 +38,7 @@ public: ~MainWidget(); public slots: + void loadFile(const QString &fileName); void loadFile(const QString &fileName, const QString &title); signals: @@ -49,12 +51,14 @@ private slots: void showMap(qreal lon, qreal lat); void downloadArea(int level, const QRectF &rect); void search(); + void showFileSelector(); private: QStackedWidget *m_stack; MapWidget *m_map; MarkerList *m_markerList; DownloadWidget *m_dlWidget; + FileSelector *m_fileSelector; SearchWidget *m_search; }; diff --git a/mapwidget.cpp b/mapwidget.cpp index a70966c..c86cf16 100644 --- a/mapwidget.cpp +++ b/mapwidget.cpp @@ -273,6 +273,8 @@ void MapWidget::keyPressEvent(QKeyEvent *event) if (event->modifiers() == Qt::NoModifier) { changeZoomLevel(-1); reloadPixmaps(); + } else if (event->modifiers() == Qt::ControlModifier) { + emit loadFile(); } break; } @@ -414,11 +416,12 @@ void MapWidget::paintEvent(QPaintEvent *event) usage << "l: Show/hide individual layers"; usage << "tab: Show/hide marker list"; if (m_networkMode) { - usage << "d: Download tiles for visible area"; + usage << "d: Download map data for visible area"; painter.drawText(30, 200, 260, 20, Qt::AlignCenter, "Map data: (C) OpenStreetMap.org"); } else if (!m_copyright.isEmpty()) { painter.drawText(30, 200, 260, 20, Qt::AlignCenter, "Map data: (C) "+m_copyright); } + usage << "Ctrl+o: Load POI / Track file"; painter.drawText(30, 10, 260, 20, Qt::AlignCenter, "NanoMap - Usage"); painter.drawLine(70, 27, 250, 27); painter.drawText(30, 30, 260, 200, Qt::AlignLeft, usage.join("\n")); diff --git a/mapwidget.h b/mapwidget.h index a5b316b..3333e39 100644 --- a/mapwidget.h +++ b/mapwidget.h @@ -49,6 +49,7 @@ signals: void close(); void showMarkerList(); void downloadArea(int level, const QRectF &rect); + void loadFile(); void search(); protected: diff --git a/pics/bookmark.png b/pics/bookmark.png new file mode 100644 index 0000000000000000000000000000000000000000..34e72c36103654f1a4040894dc1c161efef0ed41 GIT binary patch literal 1145 zcmV-<1cv*GP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L022rR022rShPj2i00007bV*G`2iXD^ z3>P7`r_sm&00a3+L_t(|+O3pZXdG1-$Ny)}Ty{5UF05%THrM7tp_--yX_FL65uwye zs5b;nv5H8ZeDP6?Q0Pl6K1!@95mK!Ms}H6kq_mi}LV8J3jkQVHwrP?z*)(0dm+a2W z`TVjw!K#e}>j%I6ANI`oecuisfn}^UxSU?CuTpjHvTW- z(RZb$n>ebM>@GLTo_&$09U*8&C(Ei zgof=x;0Zl%eQDm-y~wS588W9F(1`J@B-kwA-kU}&bPTbvlSoHG5mFdtespaN9P6?# zh|p)x999d%Z{*hOguk>IR!JjdZYhKWptD4RA&{oBlPC>v1p^O)n}{G49z}BYA~!n& z*9{!kBNL--RV~k>pyp}7FagZ~?B79PfncyQskc(dOuQn6<3bY>zTji&m@ z`i`Q7CIPwwp(O!Yo^Sz_2!m3T`7tUj zaIRmdfQb#Qy=oR->Gz9yWA2AnwcngO=PNWnLF51ku-wOKcw^`ses8S+VtfM8mQyTU z?Uf#S4saa`O3M=%jF}a)j2n4rW%r=7fRhCB2Ad#P6~`S>AWV^?2>`;|)xBw#g#m9` z(`&3TiXa1!$`NI&id~z^bUus}0fa1>5SSSem>L#PB-rMCPuaK62ymon1GpY|kClU< z&#1S#D|%;U0Q<_Cg}=B#Lpp8o*~HSSf1BU5!Yp{a z_{80x=kv%_CjlI3KZ{vBpuTQJkfTF0AAe8-^261JTEa#6aNtPXBzm680^#gmX>3y!^2O4V`EXNpx`(y%OtY6I4_r$GOo(X zx)ZIf^GMR31Vi=p_g4G*8Z*w6^JyiekX$YhLZGazAuu_K^{FW}r@Ff1Y**LyWP@GU z*WcGv=LsEop8(Rc5V2!IIb7Su z-o6ka^s&ZR>@Gu5G0`UWq*PTnSV6{yZwWCi1}WdgCz#zUD?VQ~laY?44^yC{+MOmv zS?!jjEZJdy<2-+^fC)#T1$>wr9EN}46R6bGZDz-SQv7}?#?shY4?y6!&ID|?iQ}&F zlWxp^gQ)~DGcjf4ssv-M1o1M+X>eM)x!bL1Ve{znZ%QdVldg+3TwteK}VWR7-bM~3*G<_4PkUOXgDmm!89M~Hro|} zHX$+u2`0gACt!1O{2Tx+tU+fZG9QS7*jWsyh9PQ(=c)xikR(@Ds&GsH5dmfXW_FKQ zR8>{CrVFZ&&LO@W0qx|`uNfe5+(b&sNT=O?BQI0@%!M}{NaL_#2x@}aQ>2Ghk-SeI zHyv?uBr_NTY&60Y0~^C4oi;!PBUo{;m<(vnwpM={Z&rZbE}mLR!O|0qftqgODWn)vavCHprRtB*os}d@0tGl aoqqu?)kdoeH1-ex0000 + + up.png + ok.png + cancel.png + bookmark.png + nobookmark.png + + diff --git a/pics/nobookmark.png b/pics/nobookmark.png new file mode 100644 index 0000000000000000000000000000000000000000..1ce6d3e2bd3439a5a2312c91d0bbd5f5248af4f0 GIT binary patch literal 1082 zcmV-A1jYM_P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L022rR022rShPj2i00007bV*G`2ign_ z3oRtzE0&J{00X*7L_t(I%dJ#RXk%3vJ@@Bn8|{meHVvljU?UHk#HN*sRdLxC>@Y1@ zR8W{HEvUFCLPuP@g+HwbQbZ736x)skHByQYP*;N+7mCA_mSCd^!C2C?G$CzC%1hq6 z_qou#X{N>*1}}V@d(U^ibMO7m2i)P(b-h{F_2xUp(>npp&CPX(LZRP+!C-QJe*WSA zg?MIWhH}oo32M0k2K{Aop3np^Lo9oEDM%p!Q=5D5{a~O&gcIt zm)yE>{S{#C+*=Q+s(Q)m^}anZF+p7}R~^PM46LuO+oe+JgM2>!`DNq%-?at1p4bNP z=9MdtGR7_tLY@NfgsQ3!_V@QA5{W=n)xUw{rUu)#aeRD?cs!1HJdQ%4khg977u&Xf z5<+};|H8s`vbebTSuU5G)-(-WU0v||{b*@v0U-pGQV>Ew2!U!MsPV|RBK zJ3Bi_rBa}juCY)k^x?q3KwDp5AKY#?7-MxwQpz(SgmA(%O#pz)<$}-WgQ}`XrBW`| z)6=t;PN!c81OiYL#UVRQdTRk8g!7q}WuaQFqFSw@R4O4FjiOjAzQ%5BZ2bClFxZ?( zB%aYU4UDlm0^7DBgg8T3Q)`+gDwPTh!@%n5Dh>}17gnxb{g}NAAQTE+J2^S&P9~Fm znx;7lPhYu_O4BrPaBzTVG>ZNG{VzD@uTN}k-E6n1sVSb%=f4dGgCip&BjB7vQ4}!7 zKq&>Kw5}_Tj*d_)7Lm*4u)V#FOeS;9=kqEr3?>Gn#c^5^L2=)Fx%O?8A) zN|>ez!!S@Pm7H5hDY3D!Ar(dGTv}SnH8jZN8KHN&YglaH*(IIl+xdjSP0=)6vb(?n%e+iZ*LFTY_@K%hWRI_v*A3JQnnI898(A( zkjZ2akH?YE=eMMkmdE3Hthcw9ba!_QS^-?*oL_Le-BzJccrF%;oz%|%0+BK&uAyVlWdHyG07*qoM6N<$g2b)& AS^xk5 literal 0 HcmV?d00001 diff --git a/pics/ok.png b/pics/ok.png new file mode 100644 index 0000000000000000000000000000000000000000..c173526fa5f970742fedafc67792a6ac49a03c90 GIT binary patch literal 601 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJbFq_W2nPqp?T7vkfLzW3kH}&M z2FBeW%xLxI@gtz1WQl7;NpOBzNqJ&XDnogBxn5>oc5!lIL8@MUQTpt6Hc~*bXFer+E;(Cn1#2ETprARAs<)hZB%ivkq+zI(k*}<2n5=1(lxd8Z zag?Y*xRgnltYy56X|R-`o4A34grS|ZiM_sWnU+hijz^}hTdc89xT#N+Sx}sHNWM#a zrAtDyZ&sCmR%bwNXJB@FQ2w-#g2|zU?O_E|qROU6m(7kYpAuU&Exu+&LhY=i+8If8 zvyvLtBsDKhuAZFIFekNfc3R{7^yc~LEpszEmSwii%WPkf-@T%sXGO`xl_gX5*3Q~m zH+xh4>`hZPomhS9-l_MwZNSjbEeY}qW?5Ge8Doi%V2}Xj<)unD+(A`pUBki?K%1+_fKtXh^3=d z%U2!QIlO20*xFv%sj#f`_3Y@|H*e3%C^&p(`h~4UMVl`?alE0CDe!3d(e5WKZko!u hb|UUZpNfUwJ2Tui5{OlJmjFsQ44$rjF6*2UngD(H)oTC% literal 0 HcmV?d00001 diff --git a/pics/up.png b/pics/up.png new file mode 100644 index 0000000000000000000000000000000000000000..b3d9cef97e16ca46909765c0a67091c97908660b GIT binary patch literal 672 zcmV;R0$=@!P)0b000McNliru*9;vE5edJ)+6{olpPkPT$sbOg93kgUk5S3}N14Mj zJ9`2QPnU^Q!($^(CTVNfnvCJd_^zB_{%mUB`TqliV3)SpD2)!M;I1`LS5+JxL^j zO~OgoFbrKmJg8}SpP#!u{Y2f#ZY)Tn8ycjY)X_29v1zB_c}-ACQP&!9y++%+cK|hQ zcVTYU5iEd=eDJ6R!6Ub4fC}%BEHs50WXy+95J(Yr%Kip{H}1g9jtZOr0000