diff --git a/interface/resources/qml/hifi/commerce/Checkout.qml b/interface/resources/qml/hifi/commerce/Checkout.qml
index 865bb72921..b9d15b61e4 100644
--- a/interface/resources/qml/hifi/commerce/Checkout.qml
+++ b/interface/resources/qml/hifi/commerce/Checkout.qml
@@ -66,6 +66,14 @@ Rectangle {
}
}
}
+ onSecurityImageResult: {
+ securityImage.source = securityImageSelection.getImagePathFromImageID(imageID);
+ }
+ }
+
+ SecurityImageSelection {
+ id: securityImageSelection;
+ referrerURL: checkoutRoot.itemHref;
}
//
@@ -80,6 +88,20 @@ Rectangle {
anchors.left: parent.left;
anchors.top: parent.top;
+ // Security Image
+ Image {
+ id: securityImage;
+ // Anchors
+ anchors.top: parent.top;
+ anchors.left: parent.left;
+ anchors.leftMargin: 16;
+ height: parent.height - 5;
+ width: height;
+ anchors.verticalCenter: parent.verticalCenter;
+ fillMode: Image.PreserveAspectFit;
+ mipmap: true;
+ }
+
// Title Bar text
RalewaySemiBold {
id: titleBarText;
@@ -87,8 +109,11 @@ Rectangle {
// Text size
size: hifi.fontSizes.overlayTitle;
// Anchors
- anchors.fill: parent;
+ anchors.top: parent.top;
+ anchors.left: securityImage.right;
anchors.leftMargin: 16;
+ anchors.bottom: parent.bottom;
+ width: paintedWidth;
// Style
color: hifi.colors.lightGrayText;
// Alignment
@@ -381,7 +406,7 @@ Rectangle {
// "Buy" button
HifiControlsUit.Button {
id: buyButton;
- enabled: balanceAfterPurchase >= 0 && !alreadyOwned && inventoryReceived && balanceReceived;
+ enabled: balanceAfterPurchase >= 0 && inventoryReceived && balanceReceived;
color: hifi.buttons.black;
colorScheme: hifi.colorSchemes.dark;
anchors.top: parent.top;
@@ -391,9 +416,16 @@ Rectangle {
anchors.right: parent.right;
anchors.rightMargin: 20;
width: parent.width/2 - anchors.rightMargin*2;
- text: (inventoryReceived && balanceReceived) ? (alreadyOwned ? "Already Owned" : "Buy") : "--";
+ text: (inventoryReceived && balanceReceived) ? (alreadyOwned ? "Already Owned: Get Item" : "Buy") : "--";
onClicked: {
- commerce.buy(itemId, parseInt(itemPriceText.text));
+ if (!alreadyOwned) {
+ commerce.buy(itemId, parseInt(itemPriceText.text));
+ } else {
+ if (urlHandler.canHandleUrl(itemHref)) {
+ urlHandler.handleUrl(itemHref);
+ }
+ sendToScript({method: 'checkout_buySuccess', itemId: itemId});
+ }
}
}
}
@@ -427,6 +459,7 @@ Rectangle {
itemHref = message.params.itemHref;
commerce.balance();
commerce.inventory();
+ commerce.getSecurityImage();
break;
default:
console.log('Unrecognized message from marketplaces.js:', JSON.stringify(message));
diff --git a/interface/resources/qml/hifi/commerce/Inventory.qml b/interface/resources/qml/hifi/commerce/Inventory.qml
index 298abebdab..d7ffae7c3c 100644
--- a/interface/resources/qml/hifi/commerce/Inventory.qml
+++ b/interface/resources/qml/hifi/commerce/Inventory.qml
@@ -43,6 +43,14 @@ Rectangle {
inventoryContentsList.model = inventory.assets;
}
}
+ onSecurityImageResult: {
+ securityImage.source = securityImageSelection.getImagePathFromImageID(imageID);
+ }
+ }
+
+ SecurityImageSelection {
+ id: securityImageSelection;
+ referrerURL: inventoryRoot.referrerURL;
}
//
@@ -51,12 +59,26 @@ Rectangle {
Item {
id: titleBarContainer;
// Size
- width: inventoryRoot.width;
+ width: parent.width;
height: 50;
// Anchors
anchors.left: parent.left;
anchors.top: parent.top;
+ // Security Image
+ Image {
+ id: securityImage;
+ // Anchors
+ anchors.top: parent.top;
+ anchors.left: parent.left;
+ anchors.leftMargin: 16;
+ height: parent.height - 5;
+ width: height;
+ anchors.verticalCenter: parent.verticalCenter;
+ fillMode: Image.PreserveAspectFit;
+ mipmap: true;
+ }
+
// Title Bar text
RalewaySemiBold {
id: titleBarText;
@@ -64,8 +86,11 @@ Rectangle {
// Text size
size: hifi.fontSizes.overlayTitle;
// Anchors
- anchors.fill: parent;
+ anchors.top: parent.top;
+ anchors.left: securityImage.right;
anchors.leftMargin: 16;
+ anchors.bottom: parent.bottom;
+ width: paintedWidth;
// Style
color: hifi.colors.lightGrayText;
// Alignment
@@ -73,6 +98,25 @@ Rectangle {
verticalAlignment: Text.AlignVCenter;
}
+ // "Change Security Image" button
+ HifiControlsUit.Button {
+ id: changeSecurityImageButton;
+ color: hifi.buttons.black;
+ colorScheme: hifi.colorSchemes.dark;
+ anchors.top: parent.top;
+ anchors.topMargin: 3;
+ anchors.bottom: parent.bottom;
+ anchors.bottomMargin: 3;
+ anchors.right: parent.right;
+ anchors.rightMargin: 20;
+ width: 200;
+ text: "Change Security Image"
+ onClicked: {
+ securityImageSelection.isManuallyChangingSecurityImage = true;
+ securityImageSelection.visible = true;
+ }
+ }
+
// Separator
HifiControlsUit.Separator {
anchors.left: parent.left;
@@ -166,6 +210,7 @@ Rectangle {
}
ListView {
id: inventoryContentsList;
+ clip: true;
// Anchors
anchors.top: inventoryContentsLabel.bottom;
anchors.topMargin: 8;
@@ -262,6 +307,7 @@ Rectangle {
referrerURL = message.referrerURL;
commerce.balance();
commerce.inventory();
+ commerce.getSecurityImage();
break;
default:
console.log('Unrecognized message from marketplaces.js:', JSON.stringify(message));
diff --git a/interface/resources/qml/hifi/commerce/SecurityImageModel.qml b/interface/resources/qml/hifi/commerce/SecurityImageModel.qml
new file mode 100644
index 0000000000..2fbf28683f
--- /dev/null
+++ b/interface/resources/qml/hifi/commerce/SecurityImageModel.qml
@@ -0,0 +1,42 @@
+//
+// SecurityImageModel.qml
+// qml/hifi/commerce
+//
+// SecurityImageModel
+//
+// Created by Zach Fox on 2017-08-15
+// Copyright 2017 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+import QtQuick 2.5
+
+ListModel {
+ id: root;
+ ListElement{
+ sourcePath: "images/01cat.jpg"
+ securityImageEnumValue: 1;
+ }
+ ListElement{
+ sourcePath: "images/02car.jpg"
+ securityImageEnumValue: 2;
+ }
+ ListElement{
+ sourcePath: "images/03dog.jpg"
+ securityImageEnumValue: 3;
+ }
+ ListElement{
+ sourcePath: "images/04stars.jpg"
+ securityImageEnumValue: 4;
+ }
+ ListElement{
+ sourcePath: "images/05plane.jpg"
+ securityImageEnumValue: 5;
+ }
+ ListElement{
+ sourcePath: "images/06gingerbread.jpg"
+ securityImageEnumValue: 6;
+ }
+}
diff --git a/interface/resources/qml/hifi/commerce/SecurityImageSelection.qml b/interface/resources/qml/hifi/commerce/SecurityImageSelection.qml
new file mode 100644
index 0000000000..7775f1ff9c
--- /dev/null
+++ b/interface/resources/qml/hifi/commerce/SecurityImageSelection.qml
@@ -0,0 +1,271 @@
+//
+// SecurityImageSelection.qml
+// qml/hifi/commerce
+//
+// SecurityImageSelection
+//
+// Created by Zach Fox on 2017-08-15
+// Copyright 2017 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+import Hifi 1.0 as Hifi
+import QtQuick 2.5
+import QtQuick.Controls 1.4
+import "../../styles-uit"
+import "../../controls-uit" as HifiControlsUit
+import "../../controls" as HifiControls
+
+// references XXX from root context
+
+Rectangle {
+ HifiConstants { id: hifi; }
+
+ id: securityImageSelectionRoot;
+ property string referrerURL: "";
+ property bool isManuallyChangingSecurityImage: false;
+ anchors.fill: parent;
+ // Style
+ color: hifi.colors.baseGray;
+ z:999; // On top of everything else
+ visible: false;
+
+ Hifi.QmlCommerce {
+ id: commerce;
+ onSecurityImageResult: {
+ if (!isManuallyChangingSecurityImage) {
+ securityImageSelectionRoot.visible = (imageID == 0);
+ }
+ if (imageID > 0) {
+ for (var itr = 0; itr < gridModel.count; itr++) {
+ var thisValue = gridModel.get(itr).securityImageEnumValue;
+ if (thisValue === imageID) {
+ securityImageGrid.currentIndex = itr;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ Component.onCompleted: {
+ commerce.getSecurityImage();
+ }
+
+ //
+ // TITLE BAR START
+ //
+ Item {
+ id: titleBarContainer;
+ // Size
+ width: securityImageSelectionRoot.width;
+ height: 30;
+ // Anchors
+ anchors.left: parent.left;
+ anchors.top: parent.top;
+
+ // Title Bar text
+ RalewaySemiBold {
+ id: titleBarText;
+ text: "Select a Security Image";
+ // Text size
+ size: hifi.fontSizes.overlayTitle;
+ // Anchors
+ anchors.fill: parent;
+ anchors.leftMargin: 16;
+ // Style
+ color: hifi.colors.lightGrayText;
+ // Alignment
+ horizontalAlignment: Text.AlignHLeft;
+ verticalAlignment: Text.AlignVCenter;
+ }
+
+ // Separator
+ HifiControlsUit.Separator {
+ anchors.left: parent.left;
+ anchors.right: parent.right;
+ anchors.bottom: parent.bottom;
+ }
+ }
+ //
+ // TITLE BAR END
+ //
+
+ //
+ // EXPLANATION START
+ //
+ Item {
+ id: explanationContainer;
+ // Size
+ width: securityImageSelectionRoot.width;
+ height: 85;
+ // Anchors
+ anchors.top: titleBarContainer.bottom;
+ anchors.left: parent.left;
+ anchors.right: parent.right;
+
+ RalewayRegular {
+ id: explanationText;
+ text: "This image will be displayed on secure Inventory and Marketplace Checkout dialogs.
If you don't see your selected image on these dialogs, do not use them!";
+ // Text size
+ size: 16;
+ // Anchors
+ anchors.top: parent.top;
+ anchors.topMargin: 4;
+ anchors.left: parent.left;
+ anchors.leftMargin: 16;
+ anchors.right: parent.right;
+ anchors.rightMargin: 16;
+ // Style
+ color: hifi.colors.lightGrayText;
+ wrapMode: Text.WordWrap;
+ // Alignment
+ horizontalAlignment: Text.AlignHLeft;
+ verticalAlignment: Text.AlignVCenter;
+ }
+
+ // Separator
+ HifiControlsUit.Separator {
+ anchors.left: parent.left;
+ anchors.right: parent.right;
+ anchors.bottom: parent.bottom;
+ }
+ }
+ //
+ // EXPLANATION END
+ //
+
+ //
+ // SECURITY IMAGE GRID START
+ //
+ Item {
+ id: securityImageGridContainer;
+ // Anchors
+ anchors.left: parent.left;
+ anchors.leftMargin: 8;
+ anchors.right: parent.right;
+ anchors.rightMargin: 8;
+ anchors.top: explanationContainer.bottom;
+ anchors.topMargin: 8;
+ anchors.bottom: actionButtonsContainer.top;
+ anchors.bottomMargin: 8;
+
+ SecurityImageModel {
+ id: gridModel;
+ }
+
+ GridView {
+ id: securityImageGrid;
+ clip: true;
+ // Anchors
+ anchors.fill: parent;
+ currentIndex: -1;
+ cellWidth: width / 2;
+ cellHeight: height / 3;
+ model: gridModel;
+ delegate: Item {
+ width: securityImageGrid.cellWidth;
+ height: securityImageGrid.cellHeight;
+ Item {
+ anchors.fill: parent;
+ Image {
+ width: parent.width - 8;
+ height: parent.height - 8;
+ source: sourcePath;
+ anchors.horizontalCenter: parent.horizontalCenter;
+ anchors.verticalCenter: parent.verticalCenter;
+ fillMode: Image.PreserveAspectFit;
+ mipmap: true;
+ }
+ }
+ MouseArea {
+ anchors.fill: parent;
+ onClicked: {
+ securityImageGrid.currentIndex = index;
+ }
+ }
+ }
+ highlight: Rectangle {
+ width: securityImageGrid.cellWidth;
+ height: securityImageGrid.cellHeight;
+ color: hifi.colors.blueHighlight;
+ }
+ }
+ }
+ //
+ // SECURITY IMAGE GRID END
+ //
+
+
+ //
+ // ACTION BUTTONS START
+ //
+ Item {
+ id: actionButtonsContainer;
+ // Size
+ width: securityImageSelectionRoot.width;
+ height: 40;
+ // Anchors
+ anchors.left: parent.left;
+ anchors.bottom: parent.bottom;
+ anchors.bottomMargin: 8;
+
+ // "Cancel" button
+ HifiControlsUit.Button {
+ id: cancelButton;
+ color: hifi.buttons.black;
+ colorScheme: hifi.colorSchemes.dark;
+ anchors.top: parent.top;
+ anchors.topMargin: 3;
+ anchors.bottom: parent.bottom;
+ anchors.bottomMargin: 3;
+ anchors.left: parent.left;
+ anchors.leftMargin: 20;
+ width: parent.width/2 - anchors.leftMargin*2;
+ text: "Cancel"
+ onClicked: {
+ if (!securityImageSelectionRoot.isManuallyChangingSecurityImage) {
+ sendToScript({method: 'securityImageSelection_cancelClicked', referrerURL: securityImageSelectionRoot.referrerURL});
+ } else {
+ securityImageSelectionRoot.visible = false;
+ }
+ }
+ }
+
+ // "Confirm" button
+ HifiControlsUit.Button {
+ id: confirmButton;
+ color: hifi.buttons.black;
+ colorScheme: hifi.colorSchemes.dark;
+ anchors.top: parent.top;
+ anchors.topMargin: 3;
+ anchors.bottom: parent.bottom;
+ anchors.bottomMargin: 3;
+ anchors.right: parent.right;
+ anchors.rightMargin: 20;
+ width: parent.width/2 - anchors.rightMargin*2;
+ text: "Confirm";
+ onClicked: {
+ securityImageSelectionRoot.isManuallyChangingSecurityImage = false;
+ commerce.chooseSecurityImage(gridModel.get(securityImageGrid.currentIndex).securityImageEnumValue);
+ }
+ }
+ }
+ //
+ // ACTION BUTTONS END
+ //
+
+ //
+ // FUNCTION DEFINITIONS START
+ //
+ signal sendToScript(var message);
+
+ function getImagePathFromImageID(imageID) {
+ return (imageID ? gridModel.get(imageID - 1).sourcePath : "");
+ }
+ //
+ // FUNCTION DEFINITIONS END
+ //
+}
diff --git a/interface/resources/qml/hifi/commerce/images/01cat.jpg b/interface/resources/qml/hifi/commerce/images/01cat.jpg
new file mode 100644
index 0000000000..6e7897cb82
Binary files /dev/null and b/interface/resources/qml/hifi/commerce/images/01cat.jpg differ
diff --git a/interface/resources/qml/hifi/commerce/images/02car.jpg b/interface/resources/qml/hifi/commerce/images/02car.jpg
new file mode 100644
index 0000000000..5dd8091e57
Binary files /dev/null and b/interface/resources/qml/hifi/commerce/images/02car.jpg differ
diff --git a/interface/resources/qml/hifi/commerce/images/03dog.jpg b/interface/resources/qml/hifi/commerce/images/03dog.jpg
new file mode 100644
index 0000000000..4a85b80c0c
Binary files /dev/null and b/interface/resources/qml/hifi/commerce/images/03dog.jpg differ
diff --git a/interface/resources/qml/hifi/commerce/images/04stars.jpg b/interface/resources/qml/hifi/commerce/images/04stars.jpg
new file mode 100644
index 0000000000..8f2bf62f83
Binary files /dev/null and b/interface/resources/qml/hifi/commerce/images/04stars.jpg differ
diff --git a/interface/resources/qml/hifi/commerce/images/05plane.jpg b/interface/resources/qml/hifi/commerce/images/05plane.jpg
new file mode 100644
index 0000000000..6504459d8b
Binary files /dev/null and b/interface/resources/qml/hifi/commerce/images/05plane.jpg differ
diff --git a/interface/resources/qml/hifi/commerce/images/06gingerbread.jpg b/interface/resources/qml/hifi/commerce/images/06gingerbread.jpg
new file mode 100644
index 0000000000..54c37faa2f
Binary files /dev/null and b/interface/resources/qml/hifi/commerce/images/06gingerbread.jpg differ
diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp
index 63bfca4f31..573740727f 100644
--- a/interface/src/commerce/QmlCommerce.cpp
+++ b/interface/src/commerce/QmlCommerce.cpp
@@ -19,9 +19,11 @@ HIFI_QML_DEF(QmlCommerce)
QmlCommerce::QmlCommerce(QQuickItem* parent) : OffscreenQmlDialog(parent) {
auto ledger = DependencyManager::get();
+ auto wallet = DependencyManager::get();
connect(ledger.data(), &Ledger::buyResult, this, &QmlCommerce::buyResult);
connect(ledger.data(), &Ledger::balanceResult, this, &QmlCommerce::balanceResult);
connect(ledger.data(), &Ledger::inventoryResult, this, &QmlCommerce::inventoryResult);
+ connect(wallet.data(), &Wallet::securityImageResult, this, &QmlCommerce::securityImageResult);
}
void QmlCommerce::buy(const QString& assetId, int cost, const QString& buyerUsername) {
@@ -48,4 +50,13 @@ void QmlCommerce::inventory() {
auto ledger = DependencyManager::get();
auto wallet = DependencyManager::get();
ledger->inventory(wallet->listPublicKeys());
- }
\ No newline at end of file
+}
+
+void QmlCommerce::chooseSecurityImage(uint imageID) {
+ auto wallet = DependencyManager::get();
+ wallet->chooseSecurityImage(imageID);
+}
+void QmlCommerce::getSecurityImage() {
+ auto wallet = DependencyManager::get();
+ wallet->getSecurityImage();
+}
\ No newline at end of file
diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h
index 0b1d232fd7..5b702bfeff 100644
--- a/interface/src/commerce/QmlCommerce.h
+++ b/interface/src/commerce/QmlCommerce.h
@@ -30,11 +30,14 @@ signals:
// because we can't scalably know of out-of-band changes (e.g., another machine interacting with the block chain).
void balanceResult(int balance, const QString& failureMessage);
void inventoryResult(QJsonObject inventory, const QString& failureMessage);
+ void securityImageResult(uint imageID);
protected:
Q_INVOKABLE void buy(const QString& assetId, int cost, const QString& buyerUsername = "");
Q_INVOKABLE void balance();
Q_INVOKABLE void inventory();
+ Q_INVOKABLE void chooseSecurityImage(uint imageID);
+ Q_INVOKABLE void getSecurityImage();
};
#endif // hifi_QmlCommerce_h
diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp
index 34d89b54b0..9edbeddd6e 100644
--- a/interface/src/commerce/Wallet.cpp
+++ b/interface/src/commerce/Wallet.cpp
@@ -43,4 +43,12 @@ QStringList Wallet::listPublicKeys() {
QString Wallet::signWithKey(const QString& text, const QString& key) {
qCInfo(commerce) << "Signing text.";
return "fixme signed";
-}
\ No newline at end of file
+}
+
+void Wallet::chooseSecurityImage(uint imageID) {
+ _chosenSecurityImage = (SecurityImage)imageID;
+ emit securityImageResult(imageID);
+}
+void Wallet::getSecurityImage() {
+ emit securityImageResult(_chosenSecurityImage);
+}
diff --git a/interface/src/commerce/Wallet.h b/interface/src/commerce/Wallet.h
index 79de5e81da..86638b5c75 100644
--- a/interface/src/commerce/Wallet.h
+++ b/interface/src/commerce/Wallet.h
@@ -26,9 +26,29 @@ public:
bool generateKeyPair();
QStringList listPublicKeys();
QString signWithKey(const QString& text, const QString& key);
+ void chooseSecurityImage(uint imageID);
+ void getSecurityImage();
+
+signals:
+ void securityImageResult(uint imageID);
+
+protected:
+ // ALWAYS add SecurityImage enum values to the END of the enum.
+ // They must be in the same order as the images are listed in
+ // SecurityImageSelection.qml
+ enum SecurityImage {
+ NONE = 0,
+ Cat,
+ Car,
+ Dog,
+ Stars,
+ Plane,
+ Gingerbread
+ };
private:
QStringList _publicKeys{};
+ SecurityImage _chosenSecurityImage = SecurityImage::NONE;
};
#endif // hifi_Wallet_h
diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js
index 9378a1d95b..84d7d44689 100644
--- a/scripts/system/marketplaces/marketplaces.js
+++ b/scripts/system/marketplaces/marketplaces.js
@@ -21,6 +21,7 @@
var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("../html/js/marketplacesInject.js");
var MARKETPLACE_CHECKOUT_QML_PATH = Script.resourcesPath() + "qml/hifi/commerce/Checkout.qml";
var MARKETPLACE_INVENTORY_QML_PATH = Script.resourcesPath() + "qml/hifi/commerce/Inventory.qml";
+ var MARKETPLACE_SECURITY_QML_PATH = Script.resourcesPath() + "qml/hifi/commerce/SecurityImageSelection.qml";
var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png";
// var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png";
@@ -87,7 +88,7 @@
function onScreenChanged(type, url) {
onMarketplaceScreen = type === "Web" && url === MARKETPLACE_URL_INITIAL;
- wireEventBridge(type === "QML" && (url === MARKETPLACE_CHECKOUT_QML_PATH || url === MARKETPLACE_INVENTORY_QML_PATH));
+ wireEventBridge(type === "QML" && (url === MARKETPLACE_CHECKOUT_QML_PATH || url === MARKETPLACE_INVENTORY_QML_PATH || url === MARKETPLACE_SECURITY_QML_PATH));
// for toolbar mode: change button to active when window is first openend, false otherwise.
marketplaceButton.editProperties({ isActive: onMarketplaceScreen });
if (type === "Web" && url.indexOf(MARKETPLACE_URL) !== -1) {
@@ -217,8 +218,11 @@
case 'inventory_backClicked':
tablet.gotoWebScreen(message.referrerURL, MARKETPLACES_INJECT_SCRIPT_URL);
break;
+ case 'securityImageSelection_cancelClicked':
+ tablet.gotoWebScreen(message.referrerURL, MARKETPLACES_INJECT_SCRIPT_URL);
+ break;
default:
- print('Unrecognized message from Checkout.qml or Inventory.qml: ' + JSON.stringify(message));
+ print('Unrecognized message from Checkout.qml, Inventory.qml, or SecurityImageSelection.qml: ' + JSON.stringify(message));
}
}