| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885 |
- import QtQuick 2.15
- import QtQuick.Controls 2.15
- import QtQuick.Layouts 1.15
- import StandardOfIron 1.0
- Rectangle {
- id: root
- property var selected_mission: null
- property string active_region_id: selected_mission && selected_mission.world_region_id ? selected_mission.world_region_id : ""
- property real map_orbit_yaw: 180
- property real map_orbit_pitch: 90
- property real map_orbit_distance: 1.2
- property real map_pan_u: 0
- property real map_pan_v: 0
- property real terrain_height_scale: 0.15
- property bool show_province_fills: true
- property string hover_province_name: ""
- property string hover_province_owner: ""
- property real hover_mouse_x: 0
- property real hover_mouse_y: 0
- property var province_labels: []
- property int label_refresh: 0
- property var campaign_state: null
- property var campaign_state_sources: ["assets/campaign_map/campaign_state.json", "qrc:/assets/campaign_map/campaign_state.json", "qrc:/StandardOfIron/assets/campaign_map/campaign_state.json", "qrc:/qt/qml/StandardOfIron/assets/campaign_map/campaign_state.json"]
- property var owner_color_map: ({
- "rome": [0.82, 0.12, 0.1, 0.45],
- "carthage": [0.8, 0.56, 0.28, 0.45],
- "neutral": [0.25, 0.25, 0.25, 0.25]
- })
- property var region_camera_positions: ({
- "transalpine_gaul": {
- "yaw": 200,
- "pitch": 50,
- "distance": 2
- },
- "cisalpine_gaul": {
- "yaw": 185,
- "pitch": 48,
- "distance": 1.9
- },
- "etruria": {
- "yaw": 180,
- "pitch": 52,
- "distance": 1.8
- },
- "southern_italy": {
- "yaw": 175,
- "pitch": 50,
- "distance": 1.9
- },
- "carthage_core": {
- "yaw": 170,
- "pitch": 55,
- "distance": 2.2
- }
- })
- signal regionSelected(string region_id)
- function focus_on_region(region_id) {
- if (!region_id || region_id === "")
- return ;
- var camera_pos = region_camera_positions[region_id];
- if (camera_pos) {
- map_orbit_yaw = camera_pos.yaw;
- map_orbit_pitch = camera_pos.pitch;
- map_orbit_distance = camera_pos.distance;
- map_pan_u = 0;
- map_pan_v = 0;
- }
- }
- function load_provinces() {
- if (campaignMapLoader.item) {
- var labels = campaignMapLoader.item.province_labels;
- if (labels && labels.length > 0) {
- province_labels = labels;
- label_refresh += 1;
- apply_campaign_state();
- }
- }
- }
- function load_campaign_state() {
- if (campaign_state)
- return ;
- load_campaign_state_from(0);
- }
- function load_campaign_state_from(index) {
- if (index >= campaign_state_sources.length)
- return ;
- var xhr = new XMLHttpRequest();
- xhr.open("GET", campaign_state_sources[index]);
- xhr.onreadystatechange = function() {
- if (xhr.readyState !== XMLHttpRequest.DONE)
- return ;
- if (xhr.status !== 200 && xhr.status !== 0) {
- load_campaign_state_from(index + 1);
- return ;
- }
- try {
- var data = JSON.parse(xhr.responseText);
- if (data && data.provinces && data.provinces.length > 0) {
- if (!campaign_state) {
- campaign_state = data;
- apply_campaign_state();
- }
- }
- } catch (e) {
- load_campaign_state_from(index + 1);
- }
- };
- xhr.send();
- }
- function owner_color_for(owner) {
- var key = owner ? owner.toLowerCase() : "neutral";
- if (owner_color_map[key])
- return owner_color_map[key];
- return owner_color_map.neutral;
- }
- function apply_campaign_state() {
- if (!campaignMapLoader.item)
- return ;
- if (!campaign_state || !campaign_state.provinces)
- return ;
- var owner_by_id = {
- };
- for (var i = 0; i < campaign_state.provinces.length; i++) {
- var entry = campaign_state.provinces[i];
- if (entry && entry.id)
- owner_by_id[entry.id] = entry.owner || "neutral";
- }
- var entries = [];
- if (province_labels && province_labels.length > 0) {
- for (var j = 0; j < province_labels.length; j++) {
- var prov = province_labels[j];
- if (!prov || !prov.id)
- continue;
- var owner = owner_by_id[prov.id] || prov.owner || "neutral";
- var color = owner_color_for(owner);
- entries.push({
- "id": prov.id,
- "owner": owner,
- "color": color
- });
- }
- } else {
- for (var k = 0; k < campaign_state.provinces.length; k++) {
- var state_prov = campaign_state.provinces[k];
- if (!state_prov || !state_prov.id)
- continue;
- var fallback_owner = state_prov.owner || "neutral";
- var fallback_color = owner_color_for(fallback_owner);
- entries.push({
- "id": state_prov.id,
- "owner": fallback_owner,
- "color": fallback_color
- });
- }
- }
- if (entries.length > 0)
- campaignMapLoader.item.apply_province_state(entries);
- }
- function reset_view() {
- if (selected_mission && selected_mission.world_region_id) {
- focus_on_region(selected_mission.world_region_id);
- return ;
- }
- map_orbit_yaw = 180;
- map_orbit_pitch = 90;
- map_orbit_distance = 1.2;
- map_pan_u = 0;
- map_pan_v = 0;
- }
- function label_uv_for(prov) {
- if (prov && prov.label_uv && prov.label_uv.length === 2)
- return prov.label_uv;
- if (!prov || !prov.triangles || prov.triangles.length === 0)
- return null;
- var sum_u = 0;
- var sum_v = 0;
- var count = 0;
- var step = Math.max(1, Math.floor(prov.triangles.length / 200));
- for (var i = 0; i < prov.triangles.length; i += step) {
- var pt = prov.triangles[i];
- if (!pt || pt.length < 2)
- continue;
- sum_u += pt[0];
- sum_v += pt[1];
- count += 1;
- }
- if (count === 0)
- return null;
- return [sum_u / count, sum_v / count];
- }
- color: "#28445C"
- radius: Theme.radiusMedium
- Component.onCompleted: {
- load_provinces();
- load_campaign_state();
- }
- onSelected_missionChanged: {
- if (selected_mission && selected_mission.world_region_id) {
- focus_on_region(selected_mission.world_region_id);
- } else {
- map_orbit_yaw = 180;
- map_orbit_pitch = 90;
- map_orbit_distance = 1.2;
- map_pan_u = 0;
- map_pan_v = 0;
- }
- }
- onCampaign_stateChanged: {
- apply_campaign_state();
- }
- Item {
- id: mapViewport
- anchors.fill: parent
- anchors.margins: Theme.spacingSmall
- clip: true
- Loader {
- id: campaignMapLoader
- anchors.fill: parent
- active: root.visible && (typeof mainWindow === 'undefined' || !mainWindow.gameStarted)
- onStatusChanged: {
- if (status === Loader.Ready) {
- root.load_provinces();
- root.apply_campaign_state();
- }
- }
- sourceComponent: Component {
- CampaignMapView {
- id: campaign_map
- anchors.fill: parent
- orbit_yaw: root.map_orbit_yaw
- orbit_pitch: root.map_orbit_pitch
- orbit_distance: root.map_orbit_distance
- pan_u: root.map_pan_u
- pan_v: root.map_pan_v
- terrain_height_scale: root.terrain_height_scale
- show_province_fills: root.show_province_fills
- current_mission: root.selected_mission && root.selected_mission.order_index !== undefined ? root.selected_mission.order_index : 7
- hover_province_id: {
- if (root.active_region_id !== "")
- return root.active_region_id;
- var info = province_info_at_screen(root.hover_mouse_x, root.hover_mouse_y);
- return info && info.id ? info.id : "";
- }
- onOrbit_yaw_changed: root.label_refresh += 1
- onOrbit_pitch_changed: root.label_refresh += 1
- onOrbit_distance_changed: root.label_refresh += 1
- onPan_u_changed: root.label_refresh += 1
- onPan_v_changed: root.label_refresh += 1
- onCurrent_mission_changed: root.label_refresh += 1
- onWidthChanged: root.label_refresh += 1
- onHeightChanged: root.label_refresh += 1
- Behavior on orbit_yaw {
- NumberAnimation {
- duration: 600
- easing.type: Easing.InOutQuad
- }
- }
- Behavior on orbit_pitch {
- NumberAnimation {
- duration: 600
- easing.type: Easing.InOutQuad
- }
- }
- Behavior on orbit_distance {
- NumberAnimation {
- duration: 600
- easing.type: Easing.InOutQuad
- }
- }
- }
- }
- }
- Row {
- id: mapControlRow
- anchors.top: parent.top
- anchors.right: parent.right
- anchors.margins: Theme.spacingMedium
- spacing: Theme.spacingSmall
- z: 8
- visible: campaignMapLoader.item
- Rectangle {
- id: pitchDownButton
- height: 24
- width: pitchDownLabel.implicitWidth + 12
- radius: 4
- color: "#f5f0e6"
- border.color: "#8b7355"
- border.width: 1
- opacity: pitchDownArea.containsMouse ? 1 : 0.9
- Label {
- id: pitchDownLabel
- anchors.centerIn: parent
- text: qsTr("Tilt -")
- color: "#2d241c"
- font.pointSize: Theme.fontSizeTiny
- font.bold: true
- }
- MouseArea {
- id: pitchDownArea
- anchors.fill: parent
- hoverEnabled: true
- cursorShape: Qt.PointingHandCursor
- onClicked: root.map_orbit_pitch = Math.max(5, root.map_orbit_pitch - 5)
- }
- }
- Rectangle {
- id: pitchUpButton
- height: 24
- width: pitchUpLabel.implicitWidth + 12
- radius: 4
- color: "#f5f0e6"
- border.color: "#8b7355"
- border.width: 1
- opacity: pitchUpArea.containsMouse ? 1 : 0.9
- Label {
- id: pitchUpLabel
- anchors.centerIn: parent
- text: qsTr("Tilt +")
- color: "#2d241c"
- font.pointSize: Theme.fontSizeTiny
- font.bold: true
- }
- MouseArea {
- id: pitchUpArea
- anchors.fill: parent
- hoverEnabled: true
- cursorShape: Qt.PointingHandCursor
- onClicked: root.map_orbit_pitch = Math.min(90, root.map_orbit_pitch + 5)
- }
- }
- Rectangle {
- id: resetViewButton
- height: 24
- width: resetViewLabel.implicitWidth + 16
- radius: 4
- color: "#f5f0e6"
- border.color: "#8b7355"
- border.width: 1
- opacity: resetViewArea.containsMouse ? 1 : 0.9
- Label {
- id: resetViewLabel
- anchors.centerIn: parent
- text: qsTr("Reset view")
- color: "#2d241c"
- font.pointSize: Theme.fontSizeTiny
- font.bold: true
- }
- MouseArea {
- id: resetViewArea
- anchors.fill: parent
- hoverEnabled: true
- cursorShape: Qt.PointingHandCursor
- onClicked: root.reset_view()
- }
- }
- }
- MouseArea {
- property real last_x: 0
- property real last_y: 0
- property real drag_distance: 0
- anchors.fill: parent
- hoverEnabled: true
- acceptedButtons: Qt.LeftButton | Qt.RightButton
- onPressed: function(mouse) {
- last_x = mouse.x;
- last_y = mouse.y;
- drag_distance = 0;
- }
- onPositionChanged: function(mouse) {
- var dx = mouse.x - last_x;
- var dy = mouse.y - last_y;
- if ((mouse.buttons & Qt.RightButton) || (mouse.buttons & Qt.LeftButton && (mouse.modifiers & Qt.ShiftModifier))) {
- var pan_scale = 0.0015 * root.map_orbit_distance;
- root.map_pan_u -= dx * pan_scale;
- root.map_pan_v += dy * pan_scale;
- } else if (mouse.buttons & Qt.LeftButton) {
- root.map_orbit_yaw += dx * 0.4;
- root.map_orbit_pitch = Math.max(5, Math.min(90, root.map_orbit_pitch + dy * 0.4));
- }
- drag_distance += Math.abs(dx) + Math.abs(dy);
- last_x = mouse.x;
- last_y = mouse.y;
- root.hover_mouse_x = mouse.x;
- root.hover_mouse_y = mouse.y;
- if (root.active_region_id === "" && campaignMapLoader.item) {
- var info = campaignMapLoader.item.province_info_at_screen(mouse.x, mouse.y);
- var id = info && info.id ? info.id : "";
- root.hover_province_name = info && info.name ? info.name : "";
- root.hover_province_owner = info && info.owner ? info.owner : "";
- }
- }
- onExited: {
- if (root.active_region_id === "") {
- root.hover_province_name = "";
- root.hover_province_owner = "";
- }
- }
- onReleased: function(mouse) {
- if (mouse.button !== Qt.LeftButton)
- return ;
- if (drag_distance > 6)
- return ;
- if (!campaignMapLoader.item)
- return ;
- var info = campaignMapLoader.item.province_info_at_screen(mouse.x, mouse.y);
- var id = info && info.id ? info.id : "";
- if (id !== "")
- root.regionSelected(id);
- }
- onWheel: function(wheel) {
- var step = wheel.angleDelta.y > 0 ? 0.9 : 1.1;
- var next_distance = root.map_orbit_distance * step;
- if (campaignMapLoader.item)
- root.map_orbit_distance = Math.min(campaignMapLoader.item.max_orbit_distance, Math.max(campaignMapLoader.item.min_orbit_distance, next_distance));
- wheel.accepted = true;
- }
- }
- Repeater {
- model: root.province_labels
- delegate: Repeater {
- property var _cities: (modelData && modelData.cities) ? modelData.cities : []
- model: _cities
- delegate: Item {
- property var city_data: modelData
- property var _city_uv: city_data.uv && city_data.uv.length === 2 ? city_data.uv : null
- property int _refresh: root.label_refresh
- property var _pos: (_city_uv !== null && _refresh >= 0 && campaignMapLoader.item) ? campaignMapLoader.item.screen_pos_for_uv(_city_uv[0], _city_uv[1]) : Qt.point(0, 0)
- visible: _city_uv !== null && city_data.name && city_data.name.length > 0
- z: 4
- x: _pos.x
- y: _pos.y
- Rectangle {
- width: 6
- height: 6
- radius: 3
- color: "#f2e6c8"
- border.color: "#2d241c"
- border.width: 1
- x: -width / 2
- y: -height / 2
- }
- Text {
- text: city_data.name
- color: "#111111"
- font.pointSize: Theme.fontSizeTiny
- font.bold: true
- style: Text.Outline
- styleColor: "#f2e6c8"
- x: 6
- y: -height / 2
- }
- }
- }
- }
- Repeater {
- id: missionMarkerRepeater
- property var mission_region_map: ({
- "transalpine_gaul": {
- "uv": [0.28, 0.35],
- "name": "Rhône"
- },
- "cisalpine_gaul": {
- "uv": [0.42, 0.38],
- "name": "N. Italy"
- },
- "etruria": {
- "uv": [0.44, 0.48],
- "name": "Trasimene"
- },
- "southern_italy": {
- "uv": [0.5, 0.53],
- "name": "Cannae"
- },
- "carthage_core": {
- "uv": [0.4, 0.78],
- "name": "Zama"
- }
- })
- model: root.selected_mission ? 1 : 0
- delegate: Item {
- property var region_info: missionMarkerRepeater.mission_region_map[root.active_region_id] || null
- property var marker_uv: region_info ? region_info.uv : null
- property int _refresh: root.label_refresh
- property var _pos: (marker_uv !== null && _refresh >= 0 && campaignMapLoader.item) ? campaignMapLoader.item.screen_pos_for_uv(marker_uv[0], marker_uv[1]) : Qt.point(0, 0)
- visible: marker_uv !== null && root.active_region_id !== ""
- z: 6
- x: _pos.x
- y: _pos.y
- Rectangle {
- width: 24
- height: 24
- radius: 12
- color: "#cc8f47"
- border.color: "#ffffff"
- border.width: 2
- x: -width / 2
- y: -height / 2
- opacity: 0.9
- Text {
- anchors.centerIn: parent
- text: "⚔"
- color: "#ffffff"
- font.pointSize: Theme.fontSizeSmall
- font.bold: true
- }
- SequentialAnimation on scale {
- loops: Animation.Infinite
- running: visible
- NumberAnimation {
- from: 1
- to: 1.15
- duration: 800
- easing.type: Easing.InOutQuad
- }
- NumberAnimation {
- from: 1.15
- to: 1
- duration: 800
- easing.type: Easing.InOutQuad
- }
- }
- }
- Text {
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.top: parent.top
- anchors.topMargin: -24
- text: region_info ? region_info.name : ""
- color: "#ffffff"
- font.pointSize: Theme.fontSizeSmall
- font.bold: true
- style: Text.Outline
- styleColor: "#000000"
- }
- }
- }
- Item {
- id: hannibalIcon
- property int _refresh: root.label_refresh
- property var _pos: (_refresh >= 0 && campaignMapLoader.item) ? campaignMapLoader.item.hannibal_icon_position() : Qt.point(0, 0)
- property var _iconSources: ["qrc:/StandardOfIron/assets/visuals/hannibal.png", "qrc:/assets/visuals/hannibal.png", "assets/visuals/hannibal.png", "qrc:/qt/qml/StandardOfIron/assets/visuals/hannibal.png"]
- property int _iconIndex: 0
- visible: campaignMapLoader.item && _pos.x > 0 && _pos.y > 0 && root.selected_mission
- z: 10
- x: _pos.x
- y: _pos.y
- Rectangle {
- width: 44
- height: 44
- x: -width / 2
- y: -height / 2
- radius: 6
- color: "#2a1f1a"
- border.color: "#d4a857"
- border.width: 2
- opacity: 0.95
- Rectangle {
- anchors.fill: parent
- anchors.margins: 2
- radius: 4
- color: "transparent"
- border.color: "#6b4423"
- border.width: 1
- }
- }
- Image {
- source: hannibalIcon._iconSources[hannibalIcon._iconIndex]
- width: 36
- height: 36
- x: -width / 2
- y: -height / 2
- smooth: true
- mipmap: true
- fillMode: Image.PreserveAspectFit
- cache: true
- asynchronous: false
- onStatusChanged: {
- if (status === Image.Error && hannibalIcon._iconIndex + 1 < hannibalIcon._iconSources.length) {
- hannibalIcon._iconIndex += 1;
- source = hannibalIcon._iconSources[hannibalIcon._iconIndex];
- }
- }
- }
- Rectangle {
- width: 50
- height: 50
- x: -width / 2
- y: -height / 2
- radius: width / 2
- color: "transparent"
- border.color: "#d4a857"
- border.width: 2
- opacity: 0.4
- SequentialAnimation on opacity {
- loops: Animation.Infinite
- running: hannibalIcon.visible
- NumberAnimation {
- from: 0.4
- to: 0
- duration: 1500
- easing.type: Easing.OutCubic
- }
- PauseAnimation {
- duration: 500
- }
- }
- SequentialAnimation on scale {
- loops: Animation.Infinite
- running: hannibalIcon.visible
- NumberAnimation {
- from: 1
- to: 1.3
- duration: 1500
- easing.type: Easing.OutCubic
- }
- NumberAnimation {
- from: 1.3
- to: 1
- duration: 0
- }
- PauseAnimation {
- duration: 500
- }
- }
- }
- }
- Rectangle {
- id: hover_tooltip
- visible: (root.active_region_id !== "" || (campaignMapLoader.item && campaignMapLoader.item.hover_province_id !== "" && root.hover_province_name !== "")) && root.active_region_id === ""
- x: Math.min(parent.width - width - Theme.spacingSmall, Math.max(Theme.spacingSmall, root.hover_mouse_x + 12))
- y: Math.min(parent.height - height - Theme.spacingSmall, Math.max(Theme.spacingSmall, root.hover_mouse_y + 12))
- width: tooltip_layout.implicitWidth + 16
- height: tooltip_layout.implicitHeight + 16
- radius: 4
- color: "#f5f0e6"
- border.color: "#8b7355"
- border.width: 2
- opacity: 0.95
- z: 10
- ColumnLayout {
- id: tooltip_layout
- anchors.centerIn: parent
- spacing: 2
- Label {
- text: root.hover_province_name
- color: "#2d241c"
- font.bold: true
- font.pointSize: Theme.fontSizeSmall
- }
- Label {
- text: qsTr("Control: ") + root.hover_province_owner
- color: "#4a3f32"
- font.pointSize: Theme.fontSizeTiny
- }
- }
- }
- Rectangle {
- anchors.left: parent.left
- anchors.bottom: parent.bottom
- anchors.margins: Theme.spacingMedium
- width: legend_layout.implicitWidth + 16
- height: legend_layout.implicitHeight + 16
- radius: 4
- color: "#f5f0e6"
- border.color: "#8b7355"
- border.width: 2
- opacity: 0.95
- ColumnLayout {
- id: legend_layout
- anchors.centerIn: parent
- spacing: Theme.spacingTiny
- Label {
- text: qsTr("Legend")
- color: "#2d241c"
- font.pointSize: Theme.fontSizeSmall
- font.bold: true
- }
- Repeater {
- model: [{
- "name": qsTr("Rome"),
- "color": "#d01f1a"
- }, {
- "name": qsTr("Carthage"),
- "color": "#cc8f47"
- }, {
- "name": qsTr("Neutral"),
- "color": "#3a3a3a"
- }]
- delegate: RowLayout {
- spacing: Theme.spacingTiny
- Rectangle {
- width: 12
- height: 12
- radius: 2
- color: modelData.color
- border.color: "#5a4a3a"
- border.width: 1
- }
- Label {
- text: modelData.name
- color: "#4a3f32"
- font.pointSize: Theme.fontSizeTiny
- }
- }
- }
- }
- }
- Label {
- anchors.right: parent.right
- anchors.bottom: parent.bottom
- anchors.margins: Theme.spacingMedium
- text: qsTr("🖱️ Drag to rotate • Shift/Right-drag to pan • Scroll to zoom")
- color: "#4a3f32"
- font.pointSize: Theme.fontSizeTiny
- style: Text.Outline
- styleColor: "#f5f0e6"
- }
- Rectangle {
- visible: root.active_region_id !== ""
- anchors.right: parent.right
- anchors.top: parent.top
- anchors.margins: Theme.spacingMedium
- width: active_region_label.implicitWidth + 16
- height: active_region_label.implicitHeight + 12
- radius: 4
- color: "#cc8f47"
- border.color: "#8b6332"
- border.width: 2
- opacity: 0.95
- z: 10
- Label {
- id: active_region_label
- anchors.centerIn: parent
- text: qsTr("📍 Mission Region")
- color: "#2d241c"
- font.pointSize: Theme.fontSizeSmall
- font.bold: true
- }
- }
- }
- }
|