2022-03-17 18:25:16 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "../events/Events.hpp"
|
|
|
|
#include "../defines.hpp"
|
2023-04-27 14:55:13 +02:00
|
|
|
#include "wlr-layer-shell-unstable-v1-protocol.h"
|
2022-03-20 14:00:46 +01:00
|
|
|
#include "../Window.hpp"
|
2024-02-29 14:03:38 +01:00
|
|
|
#include "../desktop/Subsurface.hpp"
|
2024-02-29 15:26:02 +01:00
|
|
|
#include "../desktop/Popup.hpp"
|
2022-05-14 17:23:46 +02:00
|
|
|
#include "AnimatedVariable.hpp"
|
2024-02-29 14:03:38 +01:00
|
|
|
#include "../desktop/WLSurface.hpp"
|
2023-07-19 20:09:49 +02:00
|
|
|
#include "Region.hpp"
|
2022-03-17 18:25:16 +01:00
|
|
|
|
2023-01-25 16:34:13 +01:00
|
|
|
struct SLayerRule {
|
|
|
|
std::string targetNamespace = "";
|
|
|
|
std::string rule = "";
|
|
|
|
};
|
|
|
|
|
2022-03-17 18:25:16 +01:00
|
|
|
struct SLayerSurface {
|
2022-05-14 17:23:46 +02:00
|
|
|
SLayerSurface();
|
2023-12-04 03:08:34 +01:00
|
|
|
~SLayerSurface();
|
2022-05-14 17:23:46 +02:00
|
|
|
|
2024-03-02 01:35:17 +01:00
|
|
|
void applyRules();
|
|
|
|
void startAnimation(bool in, bool instant = false);
|
|
|
|
bool isFadedOut();
|
2024-02-28 16:00:34 +01:00
|
|
|
|
2024-03-02 01:35:17 +01:00
|
|
|
CAnimatedVariable<Vector2D> realPosition;
|
|
|
|
CAnimatedVariable<Vector2D> realSize;
|
2023-03-18 00:16:13 +01:00
|
|
|
|
2024-03-02 01:35:17 +01:00
|
|
|
wlr_layer_surface_v1* layerSurface;
|
|
|
|
wl_list link;
|
2022-03-17 18:25:16 +01:00
|
|
|
|
2024-03-02 01:35:17 +01:00
|
|
|
bool keyboardExclusive = false;
|
2023-05-09 18:01:18 +02:00
|
|
|
|
2024-03-02 01:35:17 +01:00
|
|
|
CWLSurface surface;
|
2024-02-29 15:26:02 +01:00
|
|
|
|
|
|
|
// desktop components
|
|
|
|
std::unique_ptr<CPopup> popupHead;
|
2023-03-20 16:00:58 +01:00
|
|
|
|
2022-03-17 18:25:16 +01:00
|
|
|
DYNLISTENER(destroyLayerSurface);
|
|
|
|
DYNLISTENER(mapLayerSurface);
|
|
|
|
DYNLISTENER(unmapLayerSurface);
|
|
|
|
DYNLISTENER(commitLayerSurface);
|
|
|
|
|
2024-02-28 16:00:34 +01:00
|
|
|
CBox geometry = {0, 0, 0, 0};
|
|
|
|
Vector2D position;
|
|
|
|
zwlr_layer_shell_v1_layer layer;
|
|
|
|
|
|
|
|
bool mapped = false;
|
2022-03-18 22:35:51 +01:00
|
|
|
|
2024-02-28 16:00:34 +01:00
|
|
|
int monitorID = -1;
|
2022-07-25 18:38:40 +02:00
|
|
|
|
2024-02-28 16:00:34 +01:00
|
|
|
std::string szNamespace = "";
|
2022-03-18 22:35:51 +01:00
|
|
|
|
2024-03-02 01:35:17 +01:00
|
|
|
CAnimatedVariable<float> alpha;
|
2024-02-28 16:00:34 +01:00
|
|
|
bool fadingOut = false;
|
|
|
|
bool readyToDelete = false;
|
|
|
|
bool noProcess = false;
|
|
|
|
bool noAnimations = false;
|
2022-07-06 21:57:35 +02:00
|
|
|
|
2024-02-28 16:00:34 +01:00
|
|
|
bool forceBlur = false;
|
|
|
|
int xray = -1;
|
|
|
|
bool ignoreAlpha = false;
|
|
|
|
float ignoreAlphaValue = 0.f;
|
2022-03-18 22:35:51 +01:00
|
|
|
|
2024-02-28 16:00:34 +01:00
|
|
|
std::optional<std::string> animationStyle;
|
2022-07-06 22:12:03 +02:00
|
|
|
|
2022-03-18 22:35:51 +01:00
|
|
|
// For the list lookup
|
2023-01-31 01:03:23 +01:00
|
|
|
bool operator==(const SLayerSurface& rhs) const {
|
2022-03-18 22:35:51 +01:00
|
|
|
return layerSurface == rhs.layerSurface && monitorID == rhs.monitorID;
|
|
|
|
}
|
2022-03-17 20:22:29 +01:00
|
|
|
};
|
|
|
|
|
2023-01-20 19:44:30 +01:00
|
|
|
class CMonitor;
|
|
|
|
|
2022-03-17 20:22:29 +01:00
|
|
|
struct SRenderData {
|
2023-01-25 16:34:13 +01:00
|
|
|
CMonitor* pMonitor;
|
|
|
|
timespec* when;
|
2023-11-04 18:03:05 +01:00
|
|
|
double x, y;
|
2022-03-21 16:13:43 +01:00
|
|
|
|
|
|
|
// for iters
|
2022-12-16 18:17:31 +01:00
|
|
|
void* data = nullptr;
|
2022-03-21 16:13:43 +01:00
|
|
|
wlr_surface* surface = nullptr;
|
2023-11-04 18:03:05 +01:00
|
|
|
double w, h;
|
2022-04-05 18:32:06 +02:00
|
|
|
|
|
|
|
// for rounding
|
|
|
|
bool dontRound = true;
|
2022-04-05 19:28:10 +02:00
|
|
|
|
|
|
|
// for fade
|
2023-01-05 19:25:45 +01:00
|
|
|
float fadeAlpha = 1.f;
|
2022-04-18 18:23:10 +02:00
|
|
|
|
|
|
|
// for alpha settings
|
2022-04-18 18:33:50 +02:00
|
|
|
float alpha = 1.f;
|
2022-05-17 13:16:37 +02:00
|
|
|
|
|
|
|
// for decorations (border)
|
|
|
|
bool decorate = false;
|
2022-05-28 17:48:01 +02:00
|
|
|
|
|
|
|
// for custom round values
|
|
|
|
int rounding = -1; // -1 means not set
|
2022-07-06 22:12:03 +02:00
|
|
|
|
|
|
|
// for blurring
|
2022-12-16 18:17:31 +01:00
|
|
|
bool blur = false;
|
2022-12-04 21:57:41 +01:00
|
|
|
bool blockBlurOptimization = false;
|
2022-07-11 23:38:10 +02:00
|
|
|
|
2022-07-15 19:07:06 +02:00
|
|
|
// only for windows, not popups
|
|
|
|
bool squishOversized = true;
|
2022-08-28 10:14:43 +02:00
|
|
|
|
|
|
|
// for calculating UV
|
|
|
|
CWindow* pWindow = nullptr;
|
2023-12-25 18:04:00 +01:00
|
|
|
|
|
|
|
bool popup = false;
|
2022-03-17 20:22:29 +01:00
|
|
|
};
|
2022-03-17 20:55:04 +01:00
|
|
|
|
2022-07-12 09:49:56 +02:00
|
|
|
struct SExtensionFindingData {
|
2022-12-16 18:17:31 +01:00
|
|
|
Vector2D origin;
|
|
|
|
Vector2D vec;
|
2022-07-12 09:49:56 +02:00
|
|
|
wlr_surface** found;
|
|
|
|
};
|
|
|
|
|
2022-07-08 12:27:05 +02:00
|
|
|
struct SStringRuleNames {
|
2022-12-16 18:17:31 +01:00
|
|
|
std::string layout = "";
|
|
|
|
std::string model = "";
|
2022-07-08 12:27:05 +02:00
|
|
|
std::string variant = "";
|
|
|
|
std::string options = "";
|
2022-12-16 18:17:31 +01:00
|
|
|
std::string rules = "";
|
2022-07-08 12:27:05 +02:00
|
|
|
};
|
|
|
|
|
2022-03-17 20:55:04 +01:00
|
|
|
struct SKeyboard {
|
|
|
|
wlr_input_device* keyboard;
|
|
|
|
|
|
|
|
DYNLISTENER(keyboardMod);
|
|
|
|
DYNLISTENER(keyboardKey);
|
2022-08-18 17:17:33 +02:00
|
|
|
DYNLISTENER(keyboardKeymap);
|
2022-03-17 20:55:04 +01:00
|
|
|
DYNLISTENER(keyboardDestroy);
|
2022-03-18 23:25:26 +01:00
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
bool isVirtual = false;
|
|
|
|
bool active = false;
|
2022-12-16 18:20:51 +01:00
|
|
|
bool enabled = true;
|
2022-06-03 18:59:39 +02:00
|
|
|
|
2024-02-28 00:21:22 +01:00
|
|
|
xkb_layout_index_t activeLayout = 0;
|
|
|
|
xkb_state* xkbTranslationState = nullptr;
|
2022-08-18 17:17:33 +02:00
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
std::string name = "";
|
|
|
|
std::string xkbFilePath = "";
|
2022-06-30 21:26:00 +02:00
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
SStringRuleNames currentRules;
|
2024-02-28 00:21:22 +01:00
|
|
|
int repeatRate = 0;
|
|
|
|
int repeatDelay = 0;
|
|
|
|
int numlockOn = -1;
|
|
|
|
bool resolveBindsBySym = false;
|
2022-06-25 11:50:09 +02:00
|
|
|
|
2024-03-02 02:46:16 +01:00
|
|
|
void updateXKBTranslationState(xkb_keymap* const keymap = nullptr);
|
|
|
|
|
2022-03-18 23:25:26 +01:00
|
|
|
// For the list lookup
|
2023-01-31 01:03:23 +01:00
|
|
|
bool operator==(const SKeyboard& rhs) const {
|
2022-03-18 23:25:26 +01:00
|
|
|
return keyboard == rhs.keyboard;
|
|
|
|
}
|
2022-03-20 12:11:57 +01:00
|
|
|
};
|
|
|
|
|
2022-04-17 21:40:04 +02:00
|
|
|
struct SMouse {
|
2024-03-02 22:04:55 +01:00
|
|
|
wlr_input_device* mouse = nullptr;
|
2022-04-17 21:40:04 +02:00
|
|
|
|
2024-03-02 22:04:55 +01:00
|
|
|
std::string name = "";
|
2022-04-17 21:40:04 +02:00
|
|
|
|
2024-03-02 22:04:55 +01:00
|
|
|
bool virt = false;
|
2022-04-17 21:40:04 +02:00
|
|
|
|
2024-03-02 22:04:55 +01:00
|
|
|
bool connected = false; // means connected to the cursor
|
2022-06-30 21:26:00 +02:00
|
|
|
|
2022-05-12 12:13:02 +02:00
|
|
|
DYNLISTENER(destroyMouse);
|
2022-04-17 21:40:04 +02:00
|
|
|
|
2023-01-31 01:03:23 +01:00
|
|
|
bool operator==(const SMouse& b) const {
|
2022-04-17 21:40:04 +02:00
|
|
|
return mouse == b.mouse;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-07-27 12:36:56 +02:00
|
|
|
class CMonitor;
|
2022-04-02 13:41:15 +02:00
|
|
|
|
2022-03-22 18:29:13 +01:00
|
|
|
struct SSeat {
|
2022-12-16 18:17:31 +01:00
|
|
|
wlr_seat* seat = nullptr;
|
|
|
|
wl_client* exclusiveClient = nullptr;
|
2022-04-17 21:40:04 +02:00
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
SMouse* mouse = nullptr;
|
2022-03-31 17:25:23 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
struct SDrag {
|
2022-12-16 18:17:31 +01:00
|
|
|
wlr_drag* drag = nullptr;
|
2022-03-31 17:25:23 +02:00
|
|
|
|
|
|
|
DYNLISTENER(destroy);
|
|
|
|
|
|
|
|
// Icon
|
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
bool iconMapped = false;
|
2022-03-31 17:25:23 +02:00
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
wlr_drag_icon* dragIcon = nullptr;
|
2022-09-25 20:07:48 +02:00
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
Vector2D pos;
|
2022-03-31 17:25:23 +02:00
|
|
|
|
|
|
|
DYNLISTENER(destroyIcon);
|
|
|
|
DYNLISTENER(mapIcon);
|
|
|
|
DYNLISTENER(unmapIcon);
|
|
|
|
DYNLISTENER(commitIcon);
|
2022-06-09 12:46:55 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
struct STablet {
|
|
|
|
DYNLISTENER(Tip);
|
|
|
|
DYNLISTENER(Axis);
|
|
|
|
DYNLISTENER(Button);
|
|
|
|
DYNLISTENER(Proximity);
|
|
|
|
DYNLISTENER(Destroy);
|
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
wlr_tablet* wlrTablet = nullptr;
|
2022-06-09 12:46:55 +02:00
|
|
|
wlr_tablet_v2_tablet* wlrTabletV2 = nullptr;
|
2022-12-16 18:17:31 +01:00
|
|
|
wlr_input_device* wlrDevice = nullptr;
|
2022-06-09 12:46:55 +02:00
|
|
|
|
2023-12-09 05:07:28 +01:00
|
|
|
bool relativeInput = false;
|
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
std::string name = "";
|
2022-06-30 21:26:00 +02:00
|
|
|
|
2024-02-27 23:11:59 +01:00
|
|
|
std::string boundOutput = "";
|
|
|
|
|
2023-08-21 01:15:00 +02:00
|
|
|
//
|
|
|
|
bool operator==(const STablet& b) const {
|
|
|
|
return wlrDevice == b.wlrDevice;
|
2022-06-09 12:46:55 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct STabletTool {
|
2022-12-16 18:17:31 +01:00
|
|
|
wlr_tablet_tool* wlrTabletTool = nullptr;
|
2022-06-09 12:46:55 +02:00
|
|
|
wlr_tablet_v2_tablet_tool* wlrTabletToolV2 = nullptr;
|
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
wlr_tablet_v2_tablet* wlrTabletOwnerV2 = nullptr;
|
2022-06-09 12:46:55 +02:00
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
wlr_surface* pSurface = nullptr;
|
2022-06-09 19:47:05 +02:00
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
double tiltX = 0;
|
|
|
|
double tiltY = 0;
|
2022-06-09 12:46:55 +02:00
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
bool active = true;
|
2022-06-09 12:46:55 +02:00
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
std::string name = "";
|
2022-06-30 21:26:00 +02:00
|
|
|
|
2022-06-09 12:46:55 +02:00
|
|
|
DYNLISTENER(TabletToolDestroy);
|
|
|
|
DYNLISTENER(TabletToolSetCursor);
|
|
|
|
|
2023-01-31 01:03:23 +01:00
|
|
|
bool operator==(const STabletTool& b) const {
|
2022-06-09 12:46:55 +02:00
|
|
|
return wlrTabletTool == b.wlrTabletTool;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct STabletPad {
|
|
|
|
wlr_tablet_v2_tablet_pad* wlrTabletPadV2 = nullptr;
|
2022-12-16 18:17:31 +01:00
|
|
|
STablet* pTabletParent = nullptr;
|
2022-12-21 16:11:39 +01:00
|
|
|
wlr_input_device* pWlrDevice = nullptr;
|
2022-06-09 12:46:55 +02:00
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
std::string name = "";
|
2022-06-30 21:26:00 +02:00
|
|
|
|
2022-06-09 12:46:55 +02:00
|
|
|
DYNLISTENER(Attach);
|
|
|
|
DYNLISTENER(Button);
|
|
|
|
DYNLISTENER(Strip);
|
|
|
|
DYNLISTENER(Ring);
|
|
|
|
DYNLISTENER(Destroy);
|
|
|
|
|
2023-01-31 01:03:23 +01:00
|
|
|
bool operator==(const STabletPad& b) const {
|
2022-06-09 12:46:55 +02:00
|
|
|
return wlrTabletPadV2 == b.wlrTabletPadV2;
|
|
|
|
}
|
2022-06-12 22:57:03 +02:00
|
|
|
};
|
2022-07-06 15:42:37 +02:00
|
|
|
|
|
|
|
struct SIdleInhibitor {
|
|
|
|
wlr_idle_inhibitor_v1* pWlrInhibitor = nullptr;
|
2022-12-16 18:17:31 +01:00
|
|
|
CWindow* pWindow = nullptr;
|
2022-07-06 15:42:37 +02:00
|
|
|
|
|
|
|
DYNLISTENER(Destroy);
|
|
|
|
|
2023-01-31 01:03:23 +01:00
|
|
|
bool operator==(const SIdleInhibitor& b) const {
|
2022-07-06 15:42:37 +02:00
|
|
|
return pWlrInhibitor == b.pWlrInhibitor;
|
|
|
|
}
|
|
|
|
};
|
2022-07-07 11:52:12 +02:00
|
|
|
|
|
|
|
struct SSwipeGesture {
|
2022-12-16 18:17:31 +01:00
|
|
|
CWorkspace* pWorkspaceBegin = nullptr;
|
2022-07-07 11:52:12 +02:00
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
double delta = 0;
|
2022-07-07 11:52:12 +02:00
|
|
|
|
2023-08-23 22:40:19 +02:00
|
|
|
int initialDirection = 0;
|
2023-08-30 17:23:35 +02:00
|
|
|
float avgSpeed = 0;
|
|
|
|
int speedPoints = 0;
|
2024-03-17 16:43:59 +01:00
|
|
|
int touch_id = 0;
|
2022-07-07 11:52:12 +02:00
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
CMonitor* pMonitor = nullptr;
|
2022-08-05 13:03:37 +02:00
|
|
|
};
|
|
|
|
|
2023-03-14 13:57:50 +01:00
|
|
|
struct STextInputV1;
|
|
|
|
|
2022-08-05 13:03:37 +02:00
|
|
|
struct STextInput {
|
2024-03-19 16:54:33 +01:00
|
|
|
wlr_text_input_v3* pWlrInput = nullptr;
|
|
|
|
STextInputV1* pV1Input = nullptr;
|
|
|
|
wlr_surface* focusedSurface = nullptr;
|
2022-08-05 13:03:37 +02:00
|
|
|
|
|
|
|
DYNLISTENER(textInputEnable);
|
|
|
|
DYNLISTENER(textInputDisable);
|
|
|
|
DYNLISTENER(textInputCommit);
|
|
|
|
DYNLISTENER(textInputDestroy);
|
2022-08-05 16:21:08 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
struct SIMEKbGrab {
|
|
|
|
wlr_input_method_keyboard_grab_v2* pWlrKbGrab = nullptr;
|
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
wlr_keyboard* pKeyboard = nullptr;
|
2022-08-05 16:21:08 +02:00
|
|
|
|
|
|
|
DYNLISTENER(grabDestroy);
|
2022-08-05 17:07:01 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
struct SIMEPopup {
|
|
|
|
wlr_input_popup_surface_v2* pSurface = nullptr;
|
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
int x, y;
|
|
|
|
int realX, realY;
|
|
|
|
bool visible;
|
|
|
|
Vector2D lastSize;
|
2022-08-05 17:07:01 +02:00
|
|
|
|
|
|
|
DYNLISTENER(mapPopup);
|
|
|
|
DYNLISTENER(unmapPopup);
|
|
|
|
DYNLISTENER(destroyPopup);
|
|
|
|
DYNLISTENER(commitPopup);
|
|
|
|
|
|
|
|
DYNLISTENER(focusedSurfaceUnmap);
|
|
|
|
|
2023-01-31 01:03:23 +01:00
|
|
|
bool operator==(const SIMEPopup& other) const {
|
2022-08-05 17:07:01 +02:00
|
|
|
return pSurface == other.pSurface;
|
|
|
|
}
|
2022-08-19 20:01:51 +02:00
|
|
|
};
|
2022-09-21 15:39:25 +02:00
|
|
|
|
|
|
|
struct STouchDevice {
|
|
|
|
wlr_input_device* pWlrDevice = nullptr;
|
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
std::string name = "";
|
2022-10-07 16:03:52 +02:00
|
|
|
|
2022-12-16 18:17:31 +01:00
|
|
|
std::string boundOutput = "";
|
2022-10-14 13:38:44 +02:00
|
|
|
|
2022-09-21 15:39:25 +02:00
|
|
|
DYNLISTENER(destroy);
|
|
|
|
|
2023-01-31 01:03:23 +01:00
|
|
|
bool operator==(const STouchDevice& other) const {
|
2022-09-21 15:39:25 +02:00
|
|
|
return pWlrDevice == other.pWlrDevice;
|
|
|
|
}
|
|
|
|
};
|
2022-10-04 21:07:21 +02:00
|
|
|
|
|
|
|
struct SSwitchDevice {
|
|
|
|
wlr_input_device* pWlrDevice = nullptr;
|
|
|
|
|
2023-03-16 17:30:22 +01:00
|
|
|
int status = -1; // uninitialized
|
|
|
|
|
2022-10-04 21:07:21 +02:00
|
|
|
DYNLISTENER(destroy);
|
|
|
|
DYNLISTENER(toggle);
|
|
|
|
|
2023-01-31 01:03:23 +01:00
|
|
|
bool operator==(const SSwitchDevice& other) const {
|
2022-10-04 21:07:21 +02:00
|
|
|
return pWlrDevice == other.pWlrDevice;
|
|
|
|
}
|
|
|
|
};
|
2023-09-28 22:48:33 +02:00
|
|
|
|
|
|
|
struct STearingController {
|
|
|
|
wlr_tearing_control_v1* pWlrHint = nullptr;
|
|
|
|
|
|
|
|
DYNLISTENER(set);
|
|
|
|
DYNLISTENER(destroy);
|
|
|
|
|
2024-02-29 16:01:56 +01:00
|
|
|
bool operator==(const STearingController& other) const {
|
2023-09-28 22:48:33 +02:00
|
|
|
return pWlrHint == other.pWlrHint;
|
|
|
|
}
|
|
|
|
};
|
2024-02-28 00:14:56 +01:00
|
|
|
|
|
|
|
struct SShortcutInhibitor {
|
|
|
|
wlr_keyboard_shortcuts_inhibitor_v1* pWlrInhibitor = nullptr;
|
|
|
|
|
|
|
|
DYNLISTENER(destroy);
|
|
|
|
|
2024-02-29 16:01:56 +01:00
|
|
|
bool operator==(const SShortcutInhibitor& other) const {
|
2024-02-28 00:14:56 +01:00
|
|
|
return pWlrInhibitor == other.pWlrInhibitor;
|
|
|
|
}
|
|
|
|
};
|