Alexey Zavyalov: Start implementing new International Settings applet (Windows XP-alike style, and eventually will work in Windows XP).

I keep the old intl.cpl in our tree since it contains some hacks to switch languages/locales/layouts, which will soon be gone (along with the old intl.cpl logically)

svn path=/trunk/; revision=22412
This commit is contained in:
Aleksey Bragin
2006-06-19 12:43:29 +00:00
parent c9099e06c5
commit f2f67e344c
12 changed files with 707 additions and 0 deletions
+3
View File
@@ -13,6 +13,9 @@
<directory name="intl">
<xi:include href="intl/intl.rbuild" />
</directory>
<directory name="intl_new">
<xi:include href="intl_new/intl.rbuild" />
</directory>
<directory name="main">
<xi:include href="main/main.rbuild" />
</directory>
+48
View File
@@ -0,0 +1,48 @@
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
IDD_REGOPTSPAGE DIALOGEX 0, 0, 252, 236
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION
CAPTION "Regional options"
FONT 8, "MS Shell Dlg"
BEGIN
GROUPBOX "Regional options and standards", IDC_GROUPBOX, 5, 3, 242, 165
LTEXT "This option influences a way of display by some programs of numbers, sums of money, dates and time.", IDC_STATIC, 14, 15, 230, 16
LTEXT "&Choose an element from the list or press the button ""Setup"" to set formats independently:", IDC_STATIC, 14, 36, 230, 16
COMBOBOX IDC_SETREG_COMBO, 14, 54, 168, 120, CBS_DROPDOWNLIST | CBS_AUTOHSCROLL |
WS_VSCROLL | WS_TABSTOP | CBS_SORT
PUSHBUTTON "Se&tup...", IDC_SETUP_BUTTON, 187, 54, 52, 13
LTEXT "Samples", IDC_STATIC, 14, 73, 70, 10
LTEXT "Number:", IDC_STATIC, 16, 86, 48, 10
LTEXT "Monetary:", IDC_STATIC, 16, 101, 48, 10
LTEXT "Time:", IDC_STATIC, 16, 116, 48, 10
LTEXT "Short date:", IDC_STATIC, 16, 131, 48, 10
LTEXT "Long date:", IDC_STATIC, 16, 146, 48, 10
EDITTEXT IDC_NUMSAMPLE_EDIT, 69, 86, 170, 12, ES_READONLY | WS_CHILD | WS_VISIBLE | WS_GROUP
EDITTEXT IDC_MONEYSAMPLE_EDIT, 69, 101, 170, 12, ES_READONLY | WS_CHILD | WS_VISIBLE | WS_GROUP
EDITTEXT IDC_TIMESAMPLE_EDIT, 69, 116, 170, 12, ES_READONLY | WS_CHILD | WS_VISIBLE | WS_GROUP
EDITTEXT IDC_SHORTTIMESAMPLE_EDIT, 69, 131, 170, 12, ES_READONLY | WS_CHILD | WS_VISIBLE | WS_GROUP
EDITTEXT IDC_FULLTIMESAMPLE_EDIT, 69, 146, 170, 12, ES_READONLY | WS_CHILD | WS_VISIBLE | WS_GROUP
GROUPBOX "Geographic location", IDC_GROUPBOX, 5, 172, 242, 56
LTEXT "Set up your location that services could supply you with the local information, for example, news and reports of weather", IDC_STATIC, 14, 184, 225, 24
COMBOBOX IDC_LOCATION_COMBO, 14, 211, 225, 40, CBS_DROPDOWNLIST | CBS_AUTOHSCROLL |
WS_VSCROLL | WS_TABSTOP | CBS_SORT
END
IDD_EXTRAOPTSPAGE DIALOGEX 0, 0, 252, 236
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION
CAPTION "Extra"
FONT 8, "MS Shell Dlg"
BEGIN
GROUPBOX "Program language that not unicode supported", IDC_GROUPBOX, 5, 5, 242, 90
COMBOBOX IDC_LANGUAGE_COMBO, 14, 75, 225, 60, CBS_DROPDOWNLIST | CBS_AUTOHSCROLL |
WS_VSCROLL | WS_TABSTOP | CBS_SORT
LTEXT "This option...", IDC_STATIC, 14, 18, 223, 33
LTEXT "Select language...", IDC_STATIC, 14, 55, 223, 18
GROUPBOX "Transformation tables codepages", IDC_GROUPBOX, 5, 101, 242, 88
END
STRINGTABLE
BEGIN
IDS_CPLNAME "Language and regional options"
IDS_CPLDESCRIPTION "Choose language and formats of numbers, currencies, time and date"
END
+102
View File
@@ -0,0 +1,102 @@
/*
* PROJECT: ReactOS International Control Panel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/cpl/intl/extra.c
* PURPOSE: Extra parameters page
* PROGRAMMERS: Alexey Zavyalov ([email protected])
*/
/* INCLUDES *****************************************************************/
#include <windows.h>
#include <commctrl.h>
#include <cpl.h>
#include "intl.h"
#include "resource.h"
/* GLOBALS ******************************************************************/
HWND hLanguageList;
/* FUNCTIONS ****************************************************************/
/* Language enumerate procedure */
BOOL
CALLBACK
LanguagesEnumProc(LPTSTR lpLanguage)
{
LCID Lcid;
TCHAR Lang[MAX_STR_SIZE];
int Index;
Lcid = wcstoul(lpLanguage, NULL, 16);
GetLocaleInfo(Lcid, LOCALE_SLANGUAGE, Lang, sizeof(Lang));
Index = SendMessageW(hLanguageList,
CB_ADDSTRING,
0,
(LPARAM)Lang);
SendMessageW(hLanguageList,
CB_SETITEMDATA,
Index,
(LPARAM)Lcid);
return TRUE;
}
/* Enumerate all installed language identifiers */
static
VOID
CreateLanguagesList(HWND hWnd)
{
TCHAR LangSel[MAX_STR_SIZE];
hLanguageList = hWnd;
EnumSystemLocalesW(LanguagesEnumProc, LCID_INSTALLED);
// Select current locale
GetLocaleInfo(GetUserDefaultLCID(),
LOCALE_SLANGUAGE,
LangSel,
sizeof(LangSel));
SendMessageW(hLanguageList,
CB_SELECTSTRING,
-1,
(LPARAM)LangSel);
}
/* Extra Parameters page dialog callback */
INT_PTR
CALLBACK
ExtraOptsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
CreateLanguagesList(GetDlgItem(hwndDlg, IDC_LANGUAGE_COMBO));
break;
case WM_COMMAND:
break;
case WM_NOTIFY:
{
LPNMHDR Lpnm = (LPNMHDR)lParam;
/* If push apply button */
if (Lpnm->code == (UINT)PSN_APPLY)
{
// TODO: Implement
}
}
break;
}
return FALSE;
}
/* EOF */
+138
View File
@@ -0,0 +1,138 @@
/*
* PROJECT: ReactOS International Control Panel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/cpl/intl/intl.c
* PURPOSE: ReactOS International Control Panel
* PROGRAMMERS: Eric Kohl
* Alexey Zavyalov ([email protected])
*/
/* INCLUDES *****************************************************************/
#include <windows.h>
#include <commctrl.h>
#include <cpl.h>
#include "resource.h"
#include "intl.h"
/* GLOBALS ******************************************************************/
#define NUM_APPLETS (1)
#define NUM_SHEETS 2
LONG APIENTRY Applet(HWND hwnd, UINT uMsg, LONG wParam, LONG lParam);
HINSTANCE hApplet;
APPLET Applets[NUM_APPLETS] =
{
{IDC_CPLICON, IDS_CPLNAME, IDS_CPLDESCRIPTION, Applet}
};
/* FUNCTIONS ****************************************************************/
static
VOID
InitPropSheetPage(PROPSHEETPAGE *PsPage, WORD IdDlg, DLGPROC DlgProc)
{
ZeroMemory(PsPage, sizeof(PROPSHEETPAGE));
PsPage->dwSize = sizeof(PROPSHEETPAGE);
PsPage->dwFlags = PSP_DEFAULT;
PsPage->hInstance = hApplet;
PsPage->pszTemplate = MAKEINTRESOURCE(IdDlg);
PsPage->pfnDlgProc = DlgProc;
}
/* Create applets */
LONG
APIENTRY
Applet(HWND hwnd, UINT uMsg, LONG wParam, LONG lParam)
{
PROPSHEETPAGE PsPage[NUM_SHEETS];
PROPSHEETHEADER psh;
TCHAR Caption[MAX_STR_SIZE];
LoadString(hApplet, IDS_CPLNAME, Caption, sizeof(Caption) / sizeof(TCHAR));
ZeroMemory(&psh, sizeof(PROPSHEETHEADER));
psh.dwSize = sizeof(PROPSHEETHEADER);
psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USECALLBACK | PSH_PROPTITLE;
psh.hwndParent = NULL;
psh.hInstance = hApplet;
psh.hIcon = LoadIcon(hApplet, MAKEINTRESOURCE(IDC_CPLICON));
psh.pszCaption = Caption;
psh.nPages = sizeof(PsPage) / sizeof(PROPSHEETPAGE);
psh.nStartPage = 0;
psh.ppsp = PsPage;
InitPropSheetPage(&PsPage[0], IDD_REGOPTSPAGE, RegOptsProc);
InitPropSheetPage(&PsPage[1], IDD_EXTRAOPTSPAGE, ExtraOptsProc);
return (LONG)(PropertySheet(&psh) != -1);
}
/* Control Panel Callback */
LONG
CALLBACK
CPlApplet(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
{
switch(uMsg)
{
case CPL_INIT:
{
return TRUE;
}
case CPL_GETCOUNT:
{
return NUM_APPLETS;
}
case CPL_INQUIRE:
{
CPLINFO *CplInfo = (CPLINFO*)lParam2;
UINT uAppIndex = (UINT)lParam1;
CplInfo->lData = 0;
CplInfo->idIcon = Applets[uAppIndex].idIcon;
CplInfo->idName = Applets[uAppIndex].idName;
CplInfo->idInfo = Applets[uAppIndex].idDescription;
break;
}
case CPL_DBLCLK:
{
UINT uAppIndex = (UINT)lParam1;
Applets[uAppIndex].AppletProc(hwndCPl, uMsg, lParam1, lParam2);
break;
}
}
return FALSE;
}
/* Standart DLL entry */
BOOL
STDCALL
DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{
INITCOMMONCONTROLSEX InitControls;
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
{
InitControls.dwSize = sizeof(INITCOMMONCONTROLSEX);
InitControls.dwICC = ICC_LISTVIEW_CLASSES | ICC_UPDOWN_CLASS | ICC_BAR_CLASSES;
InitCommonControlsEx(&InitControls);
hApplet = hinstDLL;
break;
}
}
return TRUE;
}
/* EOF */
+8
View File
@@ -0,0 +1,8 @@
LIBRARY intl.cpl
EXPORTS
CPlApplet@16
RegOptsProc@16
ExtraOptsProc@16
; EOF
+31
View File
@@ -0,0 +1,31 @@
#ifndef __INTL_H
#define __INTL_H
/* GLOBALS ******************************************************************/
#define MAX_STR_SIZE 128
#define MAX_FMT_SIZE 30
typedef struct
{
int idIcon;
int idName;
int idDescription;
APPLET_PROC AppletProc;
} APPLET, *PAPPLET;
extern HINSTANCE hApplet;
/* locale.c */
INT_PTR
CALLBACK
RegOptsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
/* extra.c */
INT_PTR
CALLBACK
ExtraOptsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
#endif /* __INTL_H */
/* EOF */
+18
View File
@@ -0,0 +1,18 @@
<module name="intl_new" type="win32dll" extension=".cpl" baseaddress="${BASEADDRESS_INTL}" installbase="system32" installname="intl_new.cpl" usewrc="false">
<importlibrary definition="intl.def" />
<include base="intl">.</include>
<define name="UNICODE" />
<define name="_UNICODE" />
<define name="__REACTOS__" />
<define name="__USE_W32API" />
<define name="_WIN32_IE">0x600</define>
<define name="_WIN32_WINNT">0x501</define>
<library>kernel32</library>
<library>user32</library>
<library>comctl32</library>
<library>advapi32</library>
<file>intl.c</file>
<file>locale.c</file>
<file>extra.c</file>
<file>intl.rc</file>
</module>
+20
View File
@@ -0,0 +1,20 @@
#include <windows.h>
#include "resource.h"
#define REACTOS_VERSION_DLL
#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Control Panel\0"
#define REACTOS_STR_INTERNAL_NAME "intl\0"
#define REACTOS_STR_ORIGINAL_FILENAME "intl.cpl\0"
#include <reactos/version.rc>
IDC_CPLICON ICON "resources/applet.ico"
IDC_FLAGS ICON "resources/flags.ico"
/*
* Everything specific to any language goes in one of the specific
* files. Note that you can and may override resources which also have
* a neutral version. This is to get localized bitmaps for example.
*/
#include "En.rc"
+301
View File
@@ -0,0 +1,301 @@
/*
* PROJECT: ReactOS International Control Panel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/cpl/intl/locale.h
* PURPOSE: Regional parameters page
* PROGRAMMERS: Eric Kohl
* Alexey Zavyalov ([email protected])
*/
/* INCLUDES *****************************************************************/
#include <windows.h>
#include <commctrl.h>
#include <cpl.h>
#include "intl.h"
#include "resource.h"
/* GLOBALS ******************************************************************/
#define SAMPLE_NUMBER L"123456789"
#define NO_FLAG 0
HWND hLocaleList, hGeoList;
/* FUNCTIONS ****************************************************************/
/* Location enumerate procedure */
BOOL
CALLBACK
LocationsEnumProc(GEOID gId)
{
TCHAR loc[MAX_STR_SIZE];
int index;
GetGeoInfo(gId, GEO_FRIENDLYNAME, loc, MAX_FMT_SIZE, LANG_SYSTEM_DEFAULT);
index = SendMessageW(hGeoList,
CB_ADDSTRING,
0,
(LPARAM)loc);
SendMessageW(hGeoList,
CB_SETITEMDATA,
index,
(LPARAM)gId);
return TRUE;
}
/* Enumerate all system locations identifiers */
static
VOID
CreateLocationsList(HWND hWnd)
{
GEOID userGeoID;
TCHAR loc[MAX_STR_SIZE];
hGeoList = hWnd;
EnumSystemGeoID(GEOCLASS_NATION, 0, LocationsEnumProc);
// Select current location
userGeoID = GetUserGeoID(GEOCLASS_NATION);
GetGeoInfo(userGeoID,
GEO_FRIENDLYNAME,
loc,
MAX_FMT_SIZE,
LANG_SYSTEM_DEFAULT);
SendMessageW(hGeoList,
CB_SELECTSTRING,
-1,
(LPARAM)loc);
}
/* Locale enumerate procedure */
BOOL
CALLBACK
LocalesEnumProc(LPTSTR lpLocale)
{
LCID lcid;
TCHAR lang[MAX_STR_SIZE];
int index;
lcid = wcstoul(lpLocale, NULL, 16);
GetLocaleInfo(lcid, LOCALE_SLANGUAGE, lang, sizeof(lang));
index = SendMessageW(hLocaleList,
CB_ADDSTRING,
0,
(LPARAM)lang);
SendMessageW(hLocaleList,
CB_SETITEMDATA,
index,
(LPARAM)lcid);
return TRUE;
}
/* Enumerate all installed locale identifiers */
static
VOID
CreateLanguagesList(HWND hWnd)
{
TCHAR langSel[MAX_STR_SIZE];
hLocaleList = hWnd;
EnumSystemLocalesW(LocalesEnumProc, LCID_INSTALLED);
// Select current locale
GetLocaleInfo(GetUserDefaultLCID(),
LOCALE_SLANGUAGE,
langSel,
sizeof(langSel));
SendMessageW(hLocaleList,
CB_SELECTSTRING,
-1,
(LPARAM)langSel);
}
/* Update all locale samples */
static
VOID
UpdateLocaleSample(HWND hwndDlg, LCID lcidLocale)
{
WCHAR OutBuffer[MAX_FMT_SIZE];
/* Get number format sample */
GetNumberFormatW(lcidLocale, NO_FLAG, SAMPLE_NUMBER, NULL, OutBuffer,
MAX_FMT_SIZE);
SendMessageW(GetDlgItem(hwndDlg, IDC_NUMSAMPLE_EDIT),
WM_SETTEXT, 0, (LPARAM)OutBuffer);
/* Get monetary format sample */
GetCurrencyFormatW(lcidLocale, LOCALE_USE_CP_ACP, SAMPLE_NUMBER, NULL,
OutBuffer, MAX_FMT_SIZE);
SendMessageW(GetDlgItem(hwndDlg, IDC_MONEYSAMPLE_EDIT),
WM_SETTEXT, 0, (LPARAM)OutBuffer);
/* Get time format sample */
GetTimeFormatW(lcidLocale, NO_FLAG, NULL, NULL, OutBuffer, MAX_FMT_SIZE);
SendMessageW(GetDlgItem(hwndDlg, IDC_TIMESAMPLE_EDIT),
WM_SETTEXT,
0,
(LPARAM)OutBuffer);
/* Get short date format sample */
GetDateFormatW(lcidLocale, DATE_SHORTDATE, NULL, NULL, OutBuffer,
MAX_FMT_SIZE);
SendMessageW(GetDlgItem(hwndDlg, IDC_SHORTTIMESAMPLE_EDIT), WM_SETTEXT,
0, (LPARAM)OutBuffer);
/* Get long date sample */
GetDateFormatW(lcidLocale, DATE_LONGDATE, NULL, NULL, OutBuffer,
MAX_FMT_SIZE);
SendMessageW(GetDlgItem(hwndDlg, IDC_FULLTIMESAMPLE_EDIT),
WM_SETTEXT, 0, (LPARAM)OutBuffer);
}
/* Setting up new locale */
static
VOID
SetNewLocale(LCID LcidLocale)
{
int RetCode;
TCHAR OutBuff[MAX_STR_SIZE];
int LocaleCounter;
HKEY LocaleKey;
TCHAR Value[9];
DWORD ValueSize;
//SetUserDefaultLCID(LcidLocale); // Not implemented in MS :(
if(!IsValidLocale(LcidLocale, LCID_INSTALLED))
{
MessageBoxW(NULL, L"Invalid locale.", L"Critical error",
MB_OK | MB_ICONERROR);
return;
}
//HACKHACK: I'm sure there is a better way to do this
for(LocaleCounter = LOCALE_ILANGUAGE;
LocaleCounter <= LOCALE_SISO3166CTRYNAME; LocaleCounter++)
{
RetCode = GetLocaleInfoW(LcidLocale,
(LCTYPE)LocaleCounter,
OutBuff,
sizeof(OutBuff));
if(RetCode == ERROR_INVALID_PARAMETER)
continue;
SetLocaleInfoW(LOCALE_USER_DEFAULT, (LCTYPE)LocaleCounter, OutBuff);
}
RetCode = RegOpenKeyW(HKEY_CURRENT_USER,
L"Control Panel\\International",
&LocaleKey);
if(RetCode != ERROR_SUCCESS)
{
MessageBoxW(NULL,
L"Problem opening HKCU\\Control Panel\\International key",
L"Critical error", MB_OK | MB_ICONERROR);
return;
}
wsprintf(Value, L"%04X", (DWORD)LcidLocale);
ValueSize = (wcslen(Value) + 1) * sizeof(WCHAR);
RegSetValueExW(LocaleKey, L"Locale", 0, REG_SZ, (BYTE *)Value, ValueSize);
RegCloseKey(LocaleKey);
}
/* Regional Parameters page dialog callback */
INT_PTR
CALLBACK
RegOptsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int CurrSel;
LCID NewLCID;
GEOID NewLocation;
switch(uMsg)
{
case WM_INITDIALOG:
CreateLocationsList(GetDlgItem(hwndDlg, IDC_LOCATION_COMBO));
CreateLanguagesList(GetDlgItem(hwndDlg, IDC_SETREG_COMBO));
/* Update locale samples */
UpdateLocaleSample(hwndDlg, LOCALE_USER_DEFAULT);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_SETUP_BUTTON:
// setup button code...
MessageBox(NULL, L"Not implemented yet", L"Info",
MB_OK | MB_ICONINFORMATION);
break;
/* If selected other locale */
case IDC_SETREG_COMBO:
if (HIWORD(wParam) == CBN_SELCHANGE ||
HIWORD(wParam) == CBN_EDITCHANGE)
{
CurrSel = SendMessageW((HWND)lParam, CB_GETCURSEL,
0, 0);
NewLCID = SendMessageW((HWND)lParam, CB_GETITEMDATA,
CurrSel, 0);
UpdateLocaleSample(hwndDlg,
MAKELCID(NewLCID, SORT_DEFAULT));
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
}
break;
case IDC_LOCATION_COMBO:
if (HIWORD(wParam) == CBN_SELCHANGE ||
HIWORD(wParam) == CBN_EDITCHANGE)
{
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
}
break;
}
break;
case WM_NOTIFY:
{
LPNMHDR lpnm = (LPNMHDR)lParam;
/* If push apply button */
if (lpnm->code == (UINT)PSN_APPLY)
{
/* Set locale */
CurrSel = SendMessageW(GetDlgItem(hwndDlg, IDC_SETREG_COMBO),
CB_GETCURSEL, 0, 0);
NewLCID = SendMessageW(GetDlgItem(hwndDlg, IDC_SETREG_COMBO),
CB_GETITEMDATA, CurrSel, 0);
if (NewLCID == (LCID)CB_ERR) break;
SetNewLocale(MAKELCID(NewLCID, SORT_DEFAULT));
/* Set geo location */
CurrSel = SendMessageW(GetDlgItem(hwndDlg, IDC_LOCATION_COMBO),
CB_GETCURSEL,
0,
0);
NewLocation = SendMessageW(GetDlgItem(hwndDlg, IDC_LOCATION_COMBO),
CB_GETITEMDATA,
CurrSel,
0);
SetUserGeoID(NewLocation);
}
}
break;
}
return FALSE;
}
/* EOF */
+38
View File
@@ -0,0 +1,38 @@
#ifndef __CPL_RESOURCE_H
#define __CPL_RESOURCE_H
/* CPL file info */
#define IDC_CPLICON 1
#define IDC_FLAGS 2
#define IDC_ICON1 3
#define IDS_CPLNAME 10
#define IDS_CPLDESCRIPTION 11
/* Region page options */
#define IDD_REGOPTSPAGE 100
#define IDC_GROUPBOX 101
#define IDC_STATIC 102
#define IDC_SETREG_COMBO 103
#define IDC_SETUP_BUTTON 104
#define IDC_NUMSAMPLE_EDIT 105
#define IDC_MONEYSAMPLE_EDIT 106
#define IDC_TIMESAMPLE_EDIT 107
#define IDC_SHORTTIMESAMPLE_EDIT 108
#define IDC_FULLTIMESAMPLE_EDIT 109
#define IDC_LOCATION_COMBO 110
/* Extra page options */
#define IDD_EXTRAOPTSPAGE 200
#define IDC_LANGUAGE_COMBO 103
/* Other page options */
// ... something
#endif /* __CPL_RESOURCE_H */
/* EOF */
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB