diff --git a/WPrefs.app/HotCornerShortcuts.c b/WPrefs.app/HotCornerShortcuts.c new file mode 100644 index 00000000..d3259d80 --- /dev/null +++ b/WPrefs.app/HotCornerShortcuts.c @@ -0,0 +1,465 @@ +/* HotCornerShortcuts.c - screen corners actions + * + * WPrefs - Window Maker Preferences Program + * + * Copyright (c) 2023 Window Maker Team + * + * 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 "WPrefs.h" + +typedef struct _Panel { + WMBox *box; + + char *sectionName; + + char *description; + + CallbackRec callbacks; + + WMWidget *parent; + WMPixmap *icon; + Pixmap quarter[4]; + + WMFrame *hcF; + WMButton *hcB; + WMFrame *hceF; + WMSlider *hceS; + WMLabel *hceL; + WMFrame *hcdescF; + WMLabel *hcdescL; + + WMFrame *hcdelayF; + WMButton *hcdelayB[5]; + WMTextField *hcdelayT; + WMLabel *hcdelayL; + WMLabel *icornerL; + + WMFrame *hcactionsF; + WMTextField *hcactionsT[4]; + + char hotcornerDelaySelected; +} _Panel; + +#define ICON_FILE "hotcorners" + +#define DELAY_ICON "timer%i" +#define DELAY_ICON_S "timer%is" + +static void edgeCallback(WMWidget * w, void *data) +{ + _Panel *panel = (_Panel *) data; + char buffer[64]; + int i; + + /* Parameter not used, but tell the compiler that it is ok */ + (void) w; + + i = WMGetSliderValue(panel->hceS); + + if (i == 0) + sprintf(buffer, _("OFF")); + else if (i == 1) + sprintf(buffer, _("1 pixel")); + else if (i <= 4) + /* 2-4 */ + sprintf(buffer, _("%i pixels"), i); + else + /* >4 */ + sprintf(buffer, _("%i pixels "), i); /* note space! */ + WMSetLabelText(panel->hceL, buffer); +} + +static void showData(_Panel * panel) +{ + int i; + char buffer[32]; + WMPropList *array; + + if (!GetObjectForKey("HotCornerDelay")) + i = 250; + else + i = GetIntegerForKey("HotCornerDelay"); + sprintf(buffer, "%i", i); + WMSetTextFieldText(panel->hcdelayT, buffer); + + switch (i) { + case 0: + WMPerformButtonClick(panel->hcdelayB[0]); + break; + case 250: + WMPerformButtonClick(panel->hcdelayB[1]); + break; + case 500: + WMPerformButtonClick(panel->hcdelayB[2]); + break; + case 750: + WMPerformButtonClick(panel->hcdelayB[3]); + break; + case 1000: + WMPerformButtonClick(panel->hcdelayB[4]); + break; + } + + i = GetIntegerForKey("HotCornerEdge"); + i = i < 0 ? 2 : i; + i = i > 10 ? 10 : i; + WMSetSliderValue(panel->hceS, i); + edgeCallback(NULL, panel); + + WMSetButtonSelected(panel->hcB, GetBoolForKey("HotCorners")); + + array = GetObjectForKey("HotCornerActions"); + if (array && (!WMIsPLArray(array) || WMGetPropListItemCount(array) != sizeof(panel->hcactionsT) / sizeof(WMTextField *))) { + wwarning(_("invalid data in option HotCornerActions.")); + } else { + if (array) { + for (i = 0; i < sizeof(panel->hcactionsT) / sizeof(WMTextField *); i++) + if (strcasecmp(WMGetFromPLString(WMGetFromPLArray(array, i)), "None") != 0) + WMSetTextFieldText(panel->hcactionsT[i], WMGetFromPLString(WMGetFromPLArray(array, i))); + } + } +} + +static void storeData(_Panel * panel) +{ + WMPropList *list; + WMPropList *tmp; + char *str; + int i; + + SetBoolForKey(WMGetButtonSelected(panel->hcB), "HotCorners"); + + str = WMGetTextFieldText(panel->hcdelayT); + if (sscanf(str, "%i", &i) != 1) + i = 0; + SetIntegerForKey(i, "HotCornerDelay"); + free(str); + + SetIntegerForKey(WMGetSliderValue(panel->hceS), "HotCornerEdge"); + + list = WMCreatePLArray(NULL, NULL); + for (i = 0; i < sizeof(panel->hcactionsT) / sizeof(WMTextField *); i++) { + str = WMGetTextFieldText(panel->hcactionsT[i]); + if (strlen(str) == 0) + str = "None"; + tmp = WMCreatePLString(str); + WMAddToPLArray(list, tmp); + } + SetObjectForKey(list, "HotCornerActions"); +} + +static void pushDelayButton(WMWidget * w, void *data) +{ + _Panel *panel = (_Panel *) data; + + panel->hotcornerDelaySelected = 1; + if (w == panel->hcdelayB[0]) { + WMSetTextFieldText(panel->hcdelayT, "0"); + } else if (w == panel->hcdelayB[1]) { + WMSetTextFieldText(panel->hcdelayT, "250"); + } else if (w == panel->hcdelayB[2]) { + WMSetTextFieldText(panel->hcdelayT, "500"); + } else if (w == panel->hcdelayB[3]) { + WMSetTextFieldText(panel->hcdelayT, "700"); + } else if (w == panel->hcdelayB[4]) { + WMSetTextFieldText(panel->hcdelayT, "1000"); + } +} + +static void delayTextChanged(void *observerData, WMNotification * notification) +{ + _Panel *panel = (_Panel *) observerData; + int i; + + /* Parameter not used, but tell the compiler that it is ok */ + (void) notification; + + if (panel->hotcornerDelaySelected) { + for (i = 0; i < 5; i++) { + WMSetButtonSelected(panel->hcdelayB[i], False); + } + panel->hotcornerDelaySelected = 0; + } +} + +static void createPanel(Panel * p) +{ + _Panel *panel = (_Panel *) p; + int i; + char *buf1, *buf2; + WMColor *color; + WMFont *font; + char *path; + RImage *xis = NULL; + WMScreen *scr = WMWidgetScreen(panel->parent); + RContext *rc = WMScreenRContext(scr); + GC gc = XCreateGC(scr->display, WMWidgetXID(panel->parent), 0, NULL); + + path = LocateImage(ICON_FILE); + if (path) { + xis = RLoadImage(rc, path, 0); + if (!xis) { + wwarning(_("could not load image file %s"), path); + } + wfree(path); + } + + panel->box = WMCreateBox(panel->parent); + WMSetViewExpandsToParent(WMWidgetView(panel->box), 2, 2, 2, 2); + + + /***************** Hot Corner lelf side frames *****************/ + panel->hcF = WMCreateFrame(panel->box); + WMResizeWidget(panel->hcF, 240, 53); + WMMoveWidget(panel->hcF, 15, 17); + + panel->hcB = WMCreateSwitchButton(panel->hcF); + WMResizeWidget(panel->hcB, 150, 30); + WMMoveWidget(panel->hcB, 15, 12); + WMSetButtonText(panel->hcB, _("Enable Hot Corners")); + + WMMapSubwidgets(panel->hcF); + + panel->hceF = WMCreateFrame(panel->box); + WMSetFrameTitle(panel->hceF, _("Hot Corner Edge")); + WMResizeWidget(panel->hceF, 240, 40); + WMMoveWidget(panel->hceF, 15, 77); + + panel->hceS = WMCreateSlider(panel->hceF); + WMResizeWidget(panel->hceS, 80, 15); + WMMoveWidget(panel->hceS, 15, 18); + WMSetSliderMinValue(panel->hceS, 2); + WMSetSliderMaxValue(panel->hceS, 10); + WMSetSliderAction(panel->hceS, edgeCallback, panel); + + panel->hceL = WMCreateLabel(panel->hceF); + WMResizeWidget(panel->hceL, 100, 15); + WMMoveWidget(panel->hceL, 105, 18); + + WMMapSubwidgets(panel->hceF); + + panel->hcdescF = WMCreateFrame(panel->box); + WMResizeWidget(panel->hcdescF, 240, 95); + WMMoveWidget(panel->hcdescF, 15, 130); + + panel->hcdescL = WMCreateLabel(panel->hcdescF); + WMResizeWidget(panel->hcdescL, 200, 60); + WMMoveWidget(panel->hcdescL, 15, 10); + WMSetLabelText(panel->hcdescL, + _("Instructions:\n\n" + " - assign command to corner\n" + " - or leave it empty\n")); + + WMMapSubwidgets(panel->hcdescF); + + /***************** Hot Corner Action Delay *****************/ + panel->hcdelayF = WMCreateFrame(panel->box); + WMResizeWidget(panel->hcdelayF, 245, 60); + WMMoveWidget(panel->hcdelayF, 265, 10); + + WMSetFrameTitle(panel->hcdelayF, _("Hot Corner Delay")); + + buf1 = wmalloc(strlen(DELAY_ICON) + 1); + buf2 = wmalloc(strlen(DELAY_ICON_S) + 1); + + for (i = 0; i < 5; i++) { + char *path; + + panel->hcdelayB[i] = WMCreateCustomButton(panel->hcdelayF, WBBStateChangeMask); + WMResizeWidget(panel->hcdelayB[i], 25, 25); + WMMoveWidget(panel->hcdelayB[i], 12 + (30 * i), 25); + WMSetButtonBordered(panel->hcdelayB[i], False); + WMSetButtonImagePosition(panel->hcdelayB[i], WIPImageOnly); + WMSetButtonAction(panel->hcdelayB[i], pushDelayButton, panel); + if (i > 0) + WMGroupButtons(panel->hcdelayB[0], panel->hcdelayB[i]); + sprintf(buf1, DELAY_ICON, i); + sprintf(buf2, DELAY_ICON_S, i); + path = LocateImage(buf1); + if (path) { + panel->icon = WMCreatePixmapFromFile(scr, path); + if (panel->icon) { + WMSetButtonImage(panel->hcdelayB[i], panel->icon); + WMReleasePixmap(panel->icon); + } else { + wwarning(_("could not load icon file %s"), path); + } + wfree(path); + } + path = LocateImage(buf2); + if (path) { + panel->icon = WMCreatePixmapFromFile(scr, path); + if (panel->icon) { + WMSetButtonAltImage(panel->hcdelayB[i], panel->icon); + WMReleasePixmap(panel->icon); + } else { + wwarning(_("could not load icon file %s"), path); + } + wfree(path); + } + } + wfree(buf1); + wfree(buf2); + + panel->hcdelayT = WMCreateTextField(panel->hcdelayF); + + WMResizeWidget(panel->hcdelayT, 36, 20); + WMMoveWidget(panel->hcdelayT, 165, 28); + WMAddNotificationObserver(delayTextChanged, panel, WMTextDidChangeNotification, panel->hcdelayT); + + panel->hcdelayL = WMCreateLabel(panel->hcdelayF); + WMResizeWidget(panel->hcdelayL, 36, 16); + WMMoveWidget(panel->hcdelayL, 205, 32); + WMSetLabelText(panel->hcdelayL, _("ms")); + + color = WMDarkGrayColor(scr); + font = WMSystemFontOfSize(scr, 10); + + WMSetLabelTextColor(panel->hcdelayL, color); + WMSetLabelFont(panel->hcdelayL, font); + + WMReleaseColor(color); + WMReleaseFont(font); + + WMMapSubwidgets(panel->hcdelayF); + + /***************** Set Hot Corner Actions ****************/ + panel->hcactionsF = WMCreateFrame(panel->box); + WMSetFrameTitle(panel->hcactionsF, _("Hot Corner Actions")); + WMResizeWidget(panel->hcactionsF, 245, 148); + WMMoveWidget(panel->hcactionsF, 265, 77); + + panel->icornerL = WMCreateLabel(panel->hcactionsF); + WMResizeWidget(panel->icornerL, 24, 24); + WMMoveWidget(panel->icornerL, 10, 18); + WMSetLabelImagePosition(panel->icornerL, WIPImageOnly); + CreateImages(scr, rc, xis, ICON_FILE, &panel->icon, NULL); + if (panel->icon) + { + WMPixmap *nicon; + + panel->quarter[0] = XCreatePixmap(scr->display, WMWidgetXID(panel->parent), panel->icon->width/2, panel->icon->height/2, WMScreenDepth(scr)); + XCopyArea(scr->display, WMGetPixmapXID(panel->icon), panel->quarter[0], gc, 0, 0, panel->icon->width/2, panel->icon->height/2, 0, 0); + nicon = WMCreatePixmapFromXPixmaps(scr, panel->quarter[0], WMGetPixmapMaskXID(panel->icon), + panel->icon->width/2, panel->icon->height/2, WMScreenDepth(scr)); + WMSetLabelImage(panel->icornerL, nicon); + WMReleasePixmap(nicon); + } + + panel->hcactionsT[0] = WMCreateTextField(panel->hcactionsF); + WMResizeWidget(panel->hcactionsT[0], 180, 20); + WMMoveWidget(panel->hcactionsT[0], 50, 20); + + panel->icornerL = WMCreateLabel(panel->hcactionsF); + WMResizeWidget(panel->icornerL, 24, 24); + WMMoveWidget(panel->icornerL, 10, 48); + WMSetLabelImagePosition(panel->icornerL, WIPImageOnly); + if (panel->icon) + { + WMPixmap *nicon; + + panel->quarter[1] = XCreatePixmap(scr->display, WMWidgetXID(panel->parent), panel->icon->width/2, panel->icon->height/2, WMScreenDepth(scr)); + XCopyArea(scr->display, WMGetPixmapXID(panel->icon), panel->quarter[1], gc, panel->icon->width/2, 0, panel->icon->width/2, panel->icon->height/2, 0, 0); + nicon = WMCreatePixmapFromXPixmaps(scr, panel->quarter[1], WMGetPixmapMaskXID(panel->icon), + panel->icon->width/2, panel->icon->height/2, WMScreenDepth(scr)); + WMSetLabelImage(panel->icornerL, nicon); + WMReleasePixmap(nicon); + } + + panel->hcactionsT[1] = WMCreateTextField(panel->hcactionsF); + WMResizeWidget(panel->hcactionsT[1], 180, 20); + WMMoveWidget(panel->hcactionsT[1], 50, 50); + + panel->icornerL = WMCreateLabel(panel->hcactionsF); + WMResizeWidget(panel->icornerL, 24, 24); + WMMoveWidget(panel->icornerL, 10, 78); + WMSetLabelImagePosition(panel->icornerL, WIPImageOnly); + if (panel->icon) + { + WMPixmap *nicon; + + panel->quarter[2] = XCreatePixmap(scr->display, WMWidgetXID(panel->parent), panel->icon->width/2, panel->icon->height/2, WMScreenDepth(scr)); + XCopyArea(scr->display, WMGetPixmapXID(panel->icon), panel->quarter[2], gc, 0, panel->icon->height/2, panel->icon->width/2, panel->icon->height/2, 0, 0); + nicon = WMCreatePixmapFromXPixmaps(scr, panel->quarter[2], WMGetPixmapMaskXID(panel->icon), + panel->icon->width/2, panel->icon->height/2, WMScreenDepth(scr)); + WMSetLabelImage(panel->icornerL, nicon); + WMReleasePixmap(nicon); + } + panel->hcactionsT[2] = WMCreateTextField(panel->hcactionsF); + WMResizeWidget(panel->hcactionsT[2], 180, 20); + WMMoveWidget(panel->hcactionsT[2], 50, 80); + + panel->icornerL = WMCreateLabel(panel->hcactionsF); + WMResizeWidget(panel->icornerL, 24, 24); + WMMoveWidget(panel->icornerL, 10, 108); + WMSetLabelImagePosition(panel->icornerL, WIPImageOnly); + if (panel->icon) + { + WMPixmap *nicon; + + panel->quarter[3] = XCreatePixmap(scr->display, WMWidgetXID(panel->parent), panel->icon->width/2, panel->icon->height/2, WMScreenDepth(scr)); + XCopyArea(scr->display, WMGetPixmapXID(panel->icon), panel->quarter[3], gc, panel->icon->width/2, panel->icon->height/2, panel->icon->width/2, panel->icon->height/2, 0, 0); + nicon = WMCreatePixmapFromXPixmaps(scr, panel->quarter[3], WMGetPixmapMaskXID(panel->icon), + panel->icon->width/2, panel->icon->height/2, WMScreenDepth(scr)); + WMSetLabelImage(panel->icornerL, nicon); + WMReleasePixmap(nicon); + } + + panel->hcactionsT[3] = WMCreateTextField(panel->hcactionsF); + WMResizeWidget(panel->hcactionsT[3], 180, 20); + WMMoveWidget(panel->hcactionsT[3], 50, 107); + + WMMapSubwidgets(panel->hcactionsF); + + if (xis) + RReleaseImage(xis); + XFreeGC(scr->display, gc); + + WMRealizeWidget(panel->box); + WMMapSubwidgets(panel->box); + + showData(panel); +} +static void prepareForClose(_Panel *panel) +{ + int i; + WMScreen *scr = WMWidgetScreen(panel->parent); + + WMReleasePixmap(panel->icon); + for (i = 0; i < sizeof(panel->quarter) / sizeof(Pixmap); i++) + XFreePixmap(scr->display, panel->quarter[i]); +} + +Panel *InitHotCornerShortcuts(WMWidget *parent) +{ + _Panel *panel; + + panel = wmalloc(sizeof(_Panel)); + + panel->sectionName = _("Hot Corner Shortcut Preferences"); + panel->description = _("Choose actions to perform when you move the\n" + "mouse pointer to the screen corners."); + panel->parent = parent; + + panel->callbacks.createWidgets = createPanel; + panel->callbacks.updateDomain = storeData; + panel->callbacks.prepareForClose = prepareForClose; + + AddSection(panel, ICON_FILE); + + return panel; +} diff --git a/WPrefs.app/Makefile.am b/WPrefs.app/Makefile.am index 2d81b4e1..4408ff96 100644 --- a/WPrefs.app/Makefile.am +++ b/WPrefs.app/Makefile.am @@ -35,6 +35,7 @@ WPrefs_SOURCES = \ Expert.c \ Focus.c \ FontSimple.c \ + HotCornerShortcuts.c \ Icons.c \ KeyboardShortcuts.c \ Menu.c \ diff --git a/WPrefs.app/WPrefs.c b/WPrefs.app/WPrefs.c index 0913e24c..cbffa5af 100644 --- a/WPrefs.app/WPrefs.c +++ b/WPrefs.app/WPrefs.c @@ -575,6 +575,7 @@ void Initialize(WMScreen * scr) InitKeyboardSettings(WPrefs.banner); #endif InitKeyboardShortcuts(WPrefs.banner); + InitHotCornerShortcuts(WPrefs.banner); InitMouseSettings(WPrefs.banner); InitAppearance(WPrefs.banner); diff --git a/WPrefs.app/WPrefs.h b/WPrefs.app/WPrefs.h index 99592971..2b0042c4 100644 --- a/WPrefs.app/WPrefs.h +++ b/WPrefs.app/WPrefs.h @@ -155,6 +155,7 @@ Panel *InitDocks(WMWidget *parent); Panel *InitExpert(WMWidget *parent); Panel *InitFocus(WMWidget *parent); Panel *InitFontSimple(WMWidget *parent); +Panel *InitHotCornerShortcuts(WMWidget *parent); Panel *InitIcons(WMWidget *parent); Panel *InitKeyboardShortcuts(WMWidget *parent); Panel *InitMenu(WMWidget *parent); diff --git a/WPrefs.app/po/Makefile.am b/WPrefs.app/po/Makefile.am index 860c605f..b216a6dd 100644 --- a/WPrefs.app/po/Makefile.am +++ b/WPrefs.app/po/Makefile.am @@ -14,6 +14,7 @@ POTFILES = \ $(top_srcdir)/WPrefs.app/Expert.c \ $(top_srcdir)/WPrefs.app/Focus.c \ $(top_srcdir)/WPrefs.app/FontSimple.c \ + $(top_srcdir)/WPrefs.app/HotCornerShortcuts.c \ $(top_srcdir)/WPrefs.app/Icons.c \ $(top_srcdir)/WPrefs.app/KeyboardShortcuts.c \ $(top_srcdir)/WPrefs.app/Menu.c \ diff --git a/WPrefs.app/tiff/Makefile.am b/WPrefs.app/tiff/Makefile.am index e4b66de1..6ee06103 100644 --- a/WPrefs.app/tiff/Makefile.am +++ b/WPrefs.app/tiff/Makefile.am @@ -15,6 +15,7 @@ dist_tiffdata_DATA = \ ergonomic.tiff \ expert.tiff \ fonts.tiff \ + hotcorners.tiff \ iconprefs.tiff \ keyboard.tiff \ keyboardprefs.tiff \ diff --git a/WPrefs.app/tiff/hotcorners.tiff b/WPrefs.app/tiff/hotcorners.tiff new file mode 100644 index 00000000..83352bc2 Binary files /dev/null and b/WPrefs.app/tiff/hotcorners.tiff differ diff --git a/WPrefs.app/xpm/Makefile.am b/WPrefs.app/xpm/Makefile.am index 01f15f3a..08e25dd8 100644 --- a/WPrefs.app/xpm/Makefile.am +++ b/WPrefs.app/xpm/Makefile.am @@ -15,6 +15,7 @@ dist_xpmdata_DATA = \ ergonomic.xpm \ expert.xpm \ fonts.xpm \ + hotcorners.xpm \ iconprefs.xpm \ keyboard.xpm \ keyboardprefs.xpm \ diff --git a/WPrefs.app/xpm/hotcorners.xpm b/WPrefs.app/xpm/hotcorners.xpm new file mode 100644 index 00000000..c6b3d660 --- /dev/null +++ b/WPrefs.app/xpm/hotcorners.xpm @@ -0,0 +1,137 @@ +/* XPM */ +static char * hotcorners_xpm[] = { +"48 48 86 1", +" c #2C2C2C", +". c #FEFEFE", +"+ c #505075", +"@ c #4E4E74", +"# c #515176", +"$ c #4B4B72", +"% c #494971", +"& c #515175", +"* c #4F4F74", +"= c #4C4C73", +"- c #696984", +"; c #545477", +"> c #5E5E7D", +", c #676783", +"' c #58587A", +") c #5B5B7C", +"! c #B1B1BB", +"~ c #A5A5B1", +"{ c #A1A1AE", +"] c #AEAEB9", +"^ c #79798F", +"/ c #5C5C7C", +"( c #D5D5DA", +"_ c #E6E6E9", +": c #E8E8EB", +"< c #EDEDEF", +"[ c #E7E7EA", +"} c #FDFDFD", +"| c #FFFFFF", +"1 c #EBEBEC", +"2 c #7F7F93", +"3 c #484871", +"4 c #7B7B85", +"5 c #EFEFEF", +"6 c #A6A6A6", +"7 c #292959", +"8 c #464670", +"9 c #8C8C96", +"0 c #F4F4F4", +"a c #F5F5F6", +"b c #F2F2F2", +"c c #9797A6", +"d c #474770", +"e c #4D4D73", +"f c #9393A3", +"g c #F4F4F5", +"h c #F3F3F3", +"i c #EBEBEE", +"j c #6D6D87", +"k c #9D9DAB", +"l c #F9F9F9", +"m c #F1F1F1", +"n c #A5A5A5", +"o c #EAEAEA", +"p c #6A6A86", +"q c #D3D3D6", +"r c #717171", +"s c #848484", +"t c #9F9FA3", +"u c #47476F", +"v c #323256", +"w c #9B9B9A", +"x c #888889", +"y c #000012", +"z c #6B6B6D", +"A c #757587", +"B c #46466D", +"C c #3B3B47", +"D c #2E2E50", +"E c #242447", +"F c #838383", +"G c #919191", +"H c #202041", +"I c #4F4F73", +"J c #4E4E72", +"K c #232343", +"L c #4F4F4F", +"M c #252548", +"N c #505074", +"O c #3A3A57", +"P c #404060", +"Q c #505076", +"R c #49496B", +"S c #31314E", +"T c #2F2F49", +"U c #434362", +" .", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++@#$%&*=+++++++++++++++++++++++++++%-;>,')@++.", +" ++)!~{]]^@++++++++++++++++++++++++++/(_:<[!#++.", +" ++'[.}|12*++++++++++++++++++++++++++345||.~$++.", +" ++,<||}67+++++++++++++++++++++++++++890||}{%++a", +" ++>:|||bcd+++++++++++++++++++++++++efg||}|]&++.", +" ++;_5h||ij+++++++++++++++++++++++++@kl|mno]*++.", +" ++pqrshltu++++++++++++++++++++++++++vwoxyzAe++.", +" ++BCDEFGHI++++++++++++++++++++++++++JKLMNOP+++.", +" ++QR+*STJ++++++++++++++++++++++++++++JU*++++++.", +" +++++++*++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++QR+*STJ++++++++++++++++++++++++++++JTS*+RQ++.", +" ++BCDEFGHI++++++++++++++++++++++++++IHGFEDCB++.", +" ++pqrshltu++++++++++++++++++++++++++utlhsrqp++.", +" ++;_5h||ij++++++++++++++++++++++++++ji||h5_;++.", +" ++>:|||bcd++++++++++++++++++++++++++dcb|||:>++.", +" ++,<||}67++++++++++++++++++++++++++++76}||<,++.", +" ++'[.}|12*++++++++++++++++++++++++++*21|}.['++.", +" ++)!~{]]^@++++++++++++++++++++++++++@^]]{~!)++.", +" ++@#$%&*=++++++++++++++++++++++++++++=*&%$#@++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +" ++++++++++++++++++++++++++++++++++++++++++++++.", +"................................................"};