ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

shimgvw.c
Go to the documentation of this file.
00001 /*
00002  *
00003  * PROJECT:         ReactOS Picture and Fax Viewer
00004  * FILE:            dll/win32/shimgvw/shimgvw.c
00005  * PURPOSE:         shimgvw.dll
00006  * PROGRAMMER:      Dmitry Chapyshev (dmitry@reactos.org)
00007  *
00008  * UPDATE HISTORY:
00009  *      28/05/2008  Created
00010  */
00011 
00012 #include <stdio.h>
00013 #include <stdlib.h>
00014 #include <stdarg.h>
00015 
00016 #include <windows.h>
00017 #include <commctrl.h>
00018 #include <gdiplus.h>
00019 #include <tchar.h>
00020 
00021 #define NDEBUG
00022 #include <debug.h>
00023 
00024 #include "shimgvw.h"
00025 
00026 
00027 HINSTANCE hInstance;
00028 SHIMGVW_SETTINGS shiSettings;
00029 GpImage *image;
00030 WNDPROC PrevProc = NULL;
00031 
00032 HWND hDispWnd, hToolBar;
00033 
00034 /* ToolBar Buttons */
00035 static const TBBUTTON Buttons [] =
00036 {   /* iBitmap,     idCommand,   fsState,         fsStyle,     bReserved[2], dwData, iString */
00037     {TBICON_PREV,   IDC_PREV,    TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
00038     {TBICON_NEXT,   IDC_NEXT,    TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
00039     {15,            0,           TBSTATE_ENABLED, BTNS_SEP,    {0}, 0, 0},
00040     {TBICON_ZOOMP,  IDC_ZOOMP,   TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
00041     {TBICON_ZOOMM,  IDC_ZOOMM,   TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
00042     {15,            0,           TBSTATE_ENABLED, BTNS_SEP,    {0}, 0, 0},
00043     {TBICON_ROT1,   IDC_ROT1,    TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
00044     {TBICON_ROT2,   IDC_ROT2,    TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
00045     {15,            0,           TBSTATE_ENABLED, BTNS_SEP,    {0}, 0, 0},
00046     {TBICON_SAVE,   IDC_SAVE,    TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
00047     {TBICON_PRINT,  IDC_PRINT,   TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
00048 };
00049 
00050 static void pLoadImage(LPWSTR szOpenFileName)
00051 {
00052     if (GetFileAttributesW(szOpenFileName) == 0xFFFFFFFF)
00053     {
00054         DPRINT1("File %s not found!\n", szOpenFileName);
00055         return;
00056     }
00057 
00058     GdipLoadImageFromFile(szOpenFileName, &image);
00059     if (!image)
00060     {
00061         DPRINT1("GdipLoadImageFromFile() failed\n");
00062     }
00063 }
00064 
00065 static VOID
00066 ImageView_DrawImage(HWND hwnd)
00067 {
00068     GpGraphics *graphics;
00069     UINT uImgWidth, uImgHeight;
00070     UINT height = 0, width = 0, x = 0, y = 0;
00071     PAINTSTRUCT ps;
00072     RECT rect;
00073     HDC hdc;
00074 
00075     hdc = BeginPaint(hwnd, &ps);
00076     if (!hdc)
00077     {
00078         DPRINT1("BeginPaint() failed\n");
00079         return;
00080     }
00081 
00082     GdipCreateFromHDC(hdc, &graphics);
00083     if (!graphics)
00084     {
00085         DPRINT1("GdipCreateFromHDC() failed\n");
00086         return;
00087     }
00088   
00089     GdipGetImageWidth(image, &uImgWidth);
00090     GdipGetImageHeight(image, &uImgHeight);
00091 
00092     if (GetClientRect(hwnd, &rect))
00093     {
00094         FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
00095 
00096         if ((rect.right == uImgWidth)&&(rect.bottom == uImgHeight))
00097         {
00098             x = 0, y = 0, width = rect.right, height = rect.bottom;
00099         }
00100         else if ((rect.right >= uImgWidth)&&(rect.bottom >= uImgHeight))
00101         {
00102             x = (rect.right/2)-(uImgWidth/2);
00103             y = (rect.bottom/2)-(uImgHeight/2);
00104             width = uImgWidth;
00105             height = uImgHeight;
00106         }
00107         else if ((rect.right < uImgWidth)||(rect.bottom < uImgHeight))
00108         {
00109             if (rect.bottom < uImgHeight)
00110             {
00111                 height = rect.bottom;
00112                 width = uImgWidth*(UINT)rect.bottom/uImgHeight;
00113                 x = (rect.right/2)-(width/2);
00114                 y = (rect.bottom/2)-(height/2);
00115             }
00116             if (rect.right < uImgWidth)
00117             {
00118                 width = rect.right;
00119                 height = uImgHeight*(UINT)rect.right/uImgWidth;
00120                 x = (rect.right/2)-(width/2);
00121                 y = (rect.bottom/2)-(height/2);
00122             }
00123             if ((height > rect.bottom)||(width > rect.right))
00124             {
00125                 for (;;)
00126                 {
00127                     if (((int)width - 1 < 0)||((int)height - 1 < 0)) break;
00128                     width -= 1;
00129                     height -= 1;
00130                     y = (rect.bottom/2)-(height/2);
00131                     x = (rect.right/2)-(width/2);
00132                     if ((height < rect.bottom)&&(width < rect.right)) break;
00133                 }
00134             }
00135         }
00136         else if ((rect.right <= uImgWidth)&&(rect.bottom <= uImgHeight))
00137         {
00138             height = uImgHeight*(UINT)rect.right/uImgWidth;
00139             y = (rect.bottom/2)-(height/2);
00140             width = rect.right;
00141 
00142             if ((height > rect.bottom)||(width > rect.right))
00143             {
00144                 for (;;)
00145                 {
00146                     if (((int)width - 1 < 0)||((int)height - 1 < 0)) break;
00147                     width -= 1;
00148                     height -= 1;
00149                     y = (rect.bottom/2)-(height/2);
00150                     x = (rect.right/2)-(width/2);
00151                     if ((height < rect.bottom)&&(width < rect.right)) break;
00152                 }
00153             }
00154         }
00155 
00156         DPRINT("x = %d\ny = %d\nWidth = %d\nHeight = %d\n\nrect.right = %d\nrect.bottom = %d\n\nuImgWidth = %d\nuImgHeight = %d\n", x, y, width, height, rect.right, rect.bottom, uImgWidth, uImgHeight);
00157         Rectangle(hdc, x - 1, y - 1, x + width + 1, y + height + 1);
00158         GdipDrawImageRect(graphics, image, x, y, width, height);
00159     }
00160     GdipDeleteGraphics(graphics);
00161     EndPaint(hwnd, &ps);
00162 }
00163 
00164 static BOOL
00165 ImageView_LoadSettings()
00166 {
00167     HKEY hKey;
00168     DWORD dwSize;
00169 
00170     if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\ReactOS\\shimgvw"), 0, KEY_READ, &hKey) == ERROR_SUCCESS)
00171     {
00172         dwSize = sizeof(SHIMGVW_SETTINGS);
00173         if (RegQueryValueEx(hKey, _T("Settings"), NULL, NULL, (LPBYTE)&shiSettings, &dwSize) == ERROR_SUCCESS)
00174         {
00175             RegCloseKey(hKey);
00176             return TRUE;
00177         }
00178 
00179         RegCloseKey(hKey);
00180     }
00181 
00182     return FALSE;
00183 }
00184 
00185 static VOID
00186 ImageView_SaveSettings(HWND hwnd)
00187 {
00188     WINDOWPLACEMENT wp;
00189     HKEY hKey;
00190 
00191     ShowWindow(hwnd, SW_HIDE);
00192     wp.length = sizeof(WINDOWPLACEMENT);
00193     GetWindowPlacement(hwnd, &wp);
00194 
00195     shiSettings.Left = wp.rcNormalPosition.left;
00196     shiSettings.Top  = wp.rcNormalPosition.top;
00197     shiSettings.Right  = wp.rcNormalPosition.right;
00198     shiSettings.Bottom = wp.rcNormalPosition.bottom;
00199     shiSettings.Maximized = (IsZoomed(hwnd) || (wp.flags & WPF_RESTORETOMAXIMIZED));
00200 
00201     if (RegCreateKeyEx(HKEY_CURRENT_USER, _T("Software\\ReactOS\\shimgvw"), 0, NULL,
00202         REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS)
00203     {
00204         RegSetValueEx(hKey, _T("Settings"), 0, REG_BINARY, (LPBYTE)&shiSettings, sizeof(SHIMGVW_SETTINGS));
00205         RegCloseKey(hKey);
00206     }
00207 }
00208 
00209 static BOOL
00210 ImageView_CreateToolBar(HWND hwnd)
00211 {
00212     INT numButtons = sizeof(Buttons) / sizeof(Buttons[0]);
00213 
00214     hToolBar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
00215                               WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | CCS_BOTTOM | TBSTYLE_TOOLTIPS,
00216                               0, 0, 0, 0, hwnd,
00217                               0, hInstance, NULL);
00218     if(hToolBar != NULL)
00219     {
00220         HIMAGELIST hImageList;
00221 
00222         SendMessage(hToolBar, TB_SETEXTENDEDSTYLE,
00223                     0, TBSTYLE_EX_HIDECLIPPEDBUTTONS);
00224 
00225         SendMessage(hToolBar, TB_BUTTONSTRUCTSIZE,
00226                     sizeof(Buttons[0]), 0);
00227 
00228         hImageList = ImageList_Create(TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, ILC_MASK | ILC_COLOR24, 1, 1);
00229 
00230         ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_PREVICON), IMAGE_BITMAP,
00231                       TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
00232 
00233         ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_NEXTICON), IMAGE_BITMAP,
00234                       TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
00235 
00236         ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_ZOOMPICON), IMAGE_BITMAP,
00237                       TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
00238 
00239         ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_ZOOMMICON), IMAGE_BITMAP,
00240                       TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
00241 
00242         ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_SAVEICON), IMAGE_BITMAP,
00243                       TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
00244 
00245         ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_PRINTICON), IMAGE_BITMAP,
00246                       TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
00247 
00248         ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_ROT1ICON), IMAGE_BITMAP,
00249                       TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
00250 
00251         ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_ROT2ICON), IMAGE_BITMAP,
00252                       TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
00253 
00254         if (hImageList == NULL) return FALSE;
00255 
00256         ImageList_Destroy((HIMAGELIST)SendMessage(hToolBar, TB_SETIMAGELIST,
00257                                                   0, (LPARAM)hImageList));
00258 
00259         SendMessage(hToolBar, TB_ADDBUTTONS,
00260                     numButtons, (LPARAM)Buttons);
00261 
00262         return TRUE;
00263     }
00264 
00265     return FALSE;
00266 }
00267 
00268 LRESULT CALLBACK
00269 ImageView_DispWndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
00270 {
00271     switch (Message)
00272     {
00273         case WM_PAINT:
00274         {
00275             ImageView_DrawImage(hwnd);
00276             return 0L;
00277         }
00278     }
00279     return CallWindowProc(PrevProc, hwnd, Message, wParam, lParam);
00280 }
00281 
00282 static VOID
00283 ImageView_InitControls(HWND hwnd)
00284 {
00285     MoveWindow(hwnd, shiSettings.Left, shiSettings.Top,
00286                shiSettings.Right - shiSettings.Left,
00287                shiSettings.Bottom - shiSettings.Top, TRUE);
00288 
00289     if (shiSettings.Maximized) ShowWindow(hwnd, SW_MAXIMIZE);
00290 
00291     hDispWnd = CreateWindowEx(0, _T("STATIC"), _T(""),
00292                               WS_CHILD | WS_VISIBLE,
00293                               0, 0, 0, 0, hwnd, NULL, hInstance, NULL);
00294 
00295     SetClassLongPtr(hDispWnd, GCL_STYLE, CS_HREDRAW | CS_VREDRAW);
00296     PrevProc = (WNDPROC) SetWindowLongPtr(hDispWnd, GWL_WNDPROC, (LPARAM) ImageView_DispWndProc);
00297 
00298     ImageView_CreateToolBar(hwnd);
00299 }
00300 
00301 LRESULT CALLBACK
00302 ImageView_WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
00303 {
00304     switch (Message)
00305     {
00306         case WM_CREATE:
00307         {
00308             ImageView_InitControls(hwnd);
00309             return 0L;
00310         }
00311         case WM_COMMAND:
00312         {
00313             switch (wParam)
00314             {
00315                 case IDC_PREV:
00316 
00317                 break;
00318                 case IDC_NEXT:
00319 
00320                 break;
00321                 case IDC_ZOOMP:
00322 
00323                 break;
00324                 case IDC_ZOOMM:
00325 
00326                 break;
00327                 case IDC_SAVE:
00328 
00329                 break;
00330                 case IDC_PRINT:
00331 
00332                 break;
00333                 case IDC_ROT1:
00334 
00335                 break;
00336                 case IDC_ROT2:
00337 
00338                 break;
00339             }
00340         }
00341         break;
00342 
00343         case WM_NOTIFY:
00344         {
00345             LPNMHDR pnmhdr = (LPNMHDR)lParam;
00346 
00347             switch (pnmhdr->code)
00348             {
00349                 case TTN_GETDISPINFO:
00350                 {
00351                     LPTOOLTIPTEXT lpttt;
00352                     UINT idButton;
00353 
00354                     lpttt = (LPTOOLTIPTEXT)lParam;
00355                     idButton = (UINT)lpttt->hdr.idFrom;
00356 
00357                     switch (idButton)
00358                     {
00359                         case IDC_PREV:
00360                             lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_PREV_PIC);
00361                         break;
00362                         case IDC_NEXT:
00363                             lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_NEXT_PIC);
00364                         break;
00365                         case IDC_ZOOMP:
00366                             lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_ZOOM_IN);
00367                         break;
00368                         case IDC_ZOOMM:
00369                             lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_ZOOM_OUT);
00370                         break;
00371                         case IDC_SAVE:
00372                             lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_SAVEAS);
00373                         break;
00374                         case IDC_PRINT:
00375                             lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_PRINT);
00376                         break;
00377                         case IDC_ROT1:
00378                             lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_ROT_COUNCW);
00379                         break;
00380                         case IDC_ROT2:
00381                             lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_ROT_CLOCKW);
00382                         break;
00383                     }
00384                     return TRUE;
00385                 }
00386             }
00387             break;
00388         }
00389         case WM_SIZING:
00390         {
00391             LPRECT pRect = (LPRECT)lParam;
00392             if (pRect->right-pRect->left < 350)
00393                 pRect->right = pRect->left + 350;
00394 
00395             if (pRect->bottom-pRect->top < 290)
00396                 pRect->bottom = pRect->top + 290;
00397             return TRUE;
00398         }
00399         case WM_SIZE:
00400         {
00401             RECT rc;
00402             SendMessage(hToolBar, TB_AUTOSIZE, 0, 0);
00403             SendMessage(hToolBar, TB_GETITEMRECT, 1, (LPARAM)&rc);
00404             MoveWindow(hDispWnd, 1, 1, LOWORD(lParam)-1, HIWORD(lParam)-rc.bottom, TRUE);
00405             return 0L;
00406         }
00407         case WM_DESTROY:
00408         {
00409             ImageView_SaveSettings(hwnd);
00410             SetWindowLongPtr(hDispWnd, GWL_WNDPROC, (LPARAM) PrevProc);
00411             PostQuitMessage(0);
00412             break;
00413         }
00414     }
00415 
00416     return DefWindowProc(hwnd, Message, wParam, lParam);
00417 }
00418 
00419 LONG WINAPI
00420 ImageView_CreateWindow(HWND hwnd, LPWSTR szFileName)
00421 {
00422     struct GdiplusStartupInput gdiplusStartupInput;
00423     ULONG_PTR gdiplusToken;
00424     WNDCLASS WndClass = {0};
00425     TCHAR szBuf[512];
00426     HWND hMainWnd;
00427     MSG msg;
00428 
00429     if (!ImageView_LoadSettings())
00430     {
00431         shiSettings.Maximized = FALSE;
00432         shiSettings.Left      = 0;
00433         shiSettings.Top       = 0;
00434         shiSettings.Right     = 520;
00435         shiSettings.Bottom    = 400;
00436     }
00437 
00438     // Initialize GDI+
00439     gdiplusStartupInput.GdiplusVersion              = 1;
00440     gdiplusStartupInput.DebugEventCallback          = NULL;
00441     gdiplusStartupInput.SuppressBackgroundThread    = FALSE;
00442     gdiplusStartupInput.SuppressExternalCodecs      = FALSE;
00443 
00444     GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
00445     pLoadImage(szFileName);
00446 
00447     // Create the window
00448     WndClass.lpszClassName  = _T("shimgvw_window");
00449     WndClass.lpfnWndProc    = (WNDPROC)ImageView_WndProc;
00450     WndClass.hInstance      = hInstance;
00451     WndClass.style          = CS_HREDRAW | CS_VREDRAW;
00452     WndClass.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPICON));
00453     WndClass.hCursor        = LoadCursor(hInstance, IDC_ARROW);
00454     WndClass.hbrBackground  = (HBRUSH)COLOR_WINDOW;
00455 
00456     if (!RegisterClass(&WndClass)) return -1;
00457 
00458     LoadString(hInstance, IDS_APPTITLE, szBuf, sizeof(szBuf) / sizeof(TCHAR));
00459     hMainWnd = CreateWindow(_T("shimgvw_window"), szBuf,
00460                             WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CAPTION,
00461                             CW_USEDEFAULT, CW_USEDEFAULT,
00462                             0, 0, NULL, NULL, hInstance, NULL); 
00463 
00464     // Show it
00465     ShowWindow(hMainWnd, SW_SHOW);
00466     UpdateWindow(hMainWnd);
00467 
00468     // Message Loop
00469     while(GetMessage(&msg,NULL,0,0))
00470     {
00471         TranslateMessage(&msg);
00472         DispatchMessageW(&msg);
00473     }
00474 
00475     if (image)
00476         GdipDisposeImage(image);
00477     GdiplusShutdown(gdiplusToken);
00478     return -1;
00479 }
00480 
00481 VOID WINAPI
00482 ImageView_FullscreenW(HWND hwnd, HINSTANCE hInst, LPCWSTR path, int nShow)
00483 {
00484     ImageView_CreateWindow(hwnd, (LPWSTR)path);
00485 }
00486 
00487 VOID WINAPI
00488 ImageView_Fullscreen(HWND hwnd, HINSTANCE hInst, LPCWSTR path, int nShow)
00489 {
00490     ImageView_CreateWindow(hwnd, (LPWSTR)path);
00491 }
00492 
00493 VOID WINAPI
00494 ImageView_FullscreenA(HWND hwnd, HINSTANCE hInst, LPCSTR path, int nShow)
00495 {
00496     WCHAR szFile[MAX_PATH];
00497 
00498     if (MultiByteToWideChar(CP_ACP, 0, (char*)path, strlen((char*)path)+1, szFile, MAX_PATH))
00499     {
00500         ImageView_CreateWindow(hwnd, (LPWSTR)szFile);
00501     }
00502 }
00503 
00504 VOID WINAPI
00505 ImageView_PrintTo(HWND hwnd, HINSTANCE hInst, LPCWSTR path, int nShow)
00506 {
00507     DPRINT("ImageView_PrintTo() not implemented\n");
00508 }
00509 
00510 VOID WINAPI
00511 ImageView_PrintToA(HWND hwnd, HINSTANCE hInst, LPCSTR path, int nShow)
00512 {
00513     DPRINT("ImageView_PrintToA() not implemented\n");
00514 }
00515 
00516 VOID WINAPI
00517 ImageView_PrintToW(HWND hwnd, HINSTANCE hInst, LPCWSTR path, int nShow)
00518 {
00519     DPRINT("ImageView_PrintToW() not implemented\n");
00520 }
00521 
00522 BOOL WINAPI
00523 DllMain(IN HINSTANCE hinstDLL,
00524         IN DWORD dwReason,
00525         IN LPVOID lpvReserved)
00526 {
00527     switch (dwReason)
00528     {
00529         case DLL_PROCESS_ATTACH:
00530         case DLL_THREAD_ATTACH:
00531             hInstance = hinstDLL;
00532             break;
00533     }
00534 
00535     return TRUE;
00536 }
00537 

Generated on Sat May 26 2012 04:25:06 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.