Преглед на файлове

提交设备转移,配置家具可看到实时点位

wangming преди 1 месец
родител
ревизия
51743faba9

+ 1 - 1
src/pages/home/home.vue

@@ -95,7 +95,7 @@
             </movable-view>
         </movable-area> -->
 
-        <view class="bot_version"> v3.0.15 </view>
+        <view class="bot_version"> v3.0.16</view>
         <view
             class="shareInfo"
             @click="goDeviceShare()"

+ 48 - 32
src/pagesA/adDevice/adDevice.vue

@@ -25,15 +25,15 @@
                     :class="{ 'fade-in': showDeviceInfo }"
                 >
                     <image src="../../static/ln_small.png" alt=""></image>
-                    <text>{{ clientId }}</text>
+                    <view class="deviceText">{{ clientId }}</view>
                 </view>
                 <view class="wifiScan" @click="scanCode" v-if="!clientId">
                     <image src="../../static/wifiScan.png" alt=""></image>
+                    <view class="wifiText" v-if="!clientId"
+                        >点击扫一扫识别设备</view
+                    >
                 </view>
-                <view class="wifiText" v-if="!clientId"
-                    >点击扫一扫识别设备</view
-                >
-                <view class="wifItem" style="margin-top: 90rpx">
+                <!-- <view class="wifItem" style="margin-top: 90rpx">
                     <image src="../../static/wifiIcon.png" alt=""></image>
                     <text>无线网账户</text>
                     <input
@@ -54,7 +54,7 @@
                         style="width: 60%"
                     />
                 </view>
-                <view class="btn" @click="startDisNet">开始配网</view>
+                <view class="btn" @click="startDisNet">开始配网</view> -->
             </view>
             <view class="clientInfo">
                 <view class="wifItem">
@@ -170,7 +170,7 @@
                         </view>
                     </view>
                     <view class="wifItem" style="margin-top: 30rpx">
-                        <text>正北向夹角(°)</text>
+                        <text>指示灯方向</text>
                         <view class="inputBox">
                             <picker
                                 @change="bindPickerChangeTwo"
@@ -332,13 +332,13 @@ export default {
                 });
                 return;
             }
-            if (!this.wifiPassword) {
-                uni.showModal({
-                    content: "请先开始配网!",
-                    showCancel: 1500,
-                });
-                return;
-            }
+            // if (!this.wifiPassword) {
+            //     uni.showModal({
+            //         content: "请先开始配网!",
+            //         showCancel: 1500,
+            //     });
+            //     return;
+            // }
             if (!this.devName) {
                 uni.showModal({
                     content: "请输入设备名称!",
@@ -430,7 +430,9 @@ export default {
                             uni.reLaunch({
                                 url:
                                     "/pagesA/roomSetting/roomSetting?devId=" +
-                                    res.data.data.devId,
+                                    res.data.data.devId +
+                                    "&clientId=" +
+                                    res.data.data.clientId,
                             });
                         } else {
                             uni.showToast({
@@ -458,7 +460,9 @@ export default {
                             uni.reLaunch({
                                 url:
                                     "/pagesA/roomSetting/roomSetting?devId=" +
-                                    res.data.data.devId,
+                                    res.data.data.devId +
+                                    "&clientId=" +
+                                    res.data.data.clientId,
                             });
                         } else {
                             uni.showToast({
@@ -594,7 +598,7 @@ export default {
         },
     },
     onLoad(options) {
-        this.refreshWifi();
+        // this.refreshWifi();
         if (JSON.stringify(options) != "{}") {
             this.devInfo = JSON.parse(options.devInfo);
             this.setDevInfo(this.devInfo);
@@ -602,7 +606,6 @@ export default {
         } else {
             console.log("没有参数");
         }
-        // this.$refs.alarModel.connectMQTTwo();
     },
 
     onUnload(options) {
@@ -651,7 +654,8 @@ export default {
 
     .bodyContent {
         width: 700rpx;
-        height: 740rpx;
+        height: 600rpx;
+        position: relative;
         margin: 20rpx auto 0 auto;
         background: #ffffff;
         border-radius: 38rpx;
@@ -660,6 +664,10 @@ export default {
         .deviceInfo {
             display: flex;
             flex-direction: column;
+            position: absolute;
+            top: 24%;
+            left: 36%;
+            transform: translate(-50%, -50%);
             padding: 0 auto;
             padding-top: 40rpx;
             width: 200rpx;
@@ -671,11 +679,15 @@ export default {
                 width: 200rpx;
                 height: 200rpx;
             }
-            text {
+            .wifiText {
                 margin-top: 20rpx;
                 text-align: center;
                 font-weight: 500;
             }
+            .deviceText {
+                text-align: center;
+                // margin-left: -10px;
+            }
         }
 
         .deviceInfo.fade-in {
@@ -685,20 +697,24 @@ export default {
 
         .wifiScan {
             margin: 0 auto;
-            padding-top: 75rpx;
             width: 188rpx;
             height: 188rpx;
+            position: absolute;
+            top: 30%;
+            left: 36%;
             image {
                 width: 188rpx;
                 height: 188rpx;
             }
+            .wifiText {
+                width: 208rpx;
+                margin: 20rpx auto;
+                color: #95a4b3;
+                font-size: 24rpx;
+                text-align: center;
+            }
         }
-        .wifiText {
-            margin-top: 20rpx;
-            color: #95a4b3;
-            font-size: 24rpx;
-            text-align: center;
-        }
+
         .wifItem {
             width: 640rpx;
             height: 40rpx;
@@ -809,7 +825,7 @@ export default {
     background: #f4f4f4;
     .header_two {
         width: 750rpx;
-        height: 700rpx;
+        height: 620rpx;
         border-bottom-left-radius: 35rpx;
         border-bottom-right-radius: 35rpx;
         background: linear-gradient(180deg, #faede2 0%, #ffffff 100%);
@@ -848,8 +864,8 @@ export default {
         .airCantInfo {
             margin: 40rpx auto 0 auto;
             opacity: 20%;
-            width: 400rpx;
-            height: 400rpx;
+            width: 200rpx;
+            height: 200rpx;
             border: 18rpx solid;
             border-color: #333333;
             display: flex;
@@ -862,9 +878,9 @@ export default {
             }
         }
         .airbody {
-            margin: 140rpx auto 0 auto;
+            margin: 100rpx auto 0 auto;
             width: 700rpx;
-            height: 540rpx;
+            height: 750rpx;
             background: #ffffff;
             border-radius: 38rpx;
             padding: 38rpx 38rpx;

+ 8 - 2
src/pagesA/deviceDetail/deviceDetail.vue

@@ -29,10 +29,14 @@
                             left: `${item.left / 2}px`,
                             transform: `rotate(${item.rotate}deg)`,
                             'transform-origin': 'center center',
+                            zIndex: 4444,
                         }"
+                        @touchmove.prevent="onTouchMove(index, $event)"
+                        @touchstart="onTouchStart(index, $event)"
+                        @touchend="onTouchEnd(index, $event)"
                     >
                         <image
-                            class="module-img"
+                            style="width: 100%; height: 100%; display: block"
                             :src="`../../static/furnitures/${item.type}.png`"
                             mode=""
                         />
@@ -398,7 +402,6 @@ export default {
             inactivityTimer: null,
             left: 0,
             top: 0,
-            clientIdProp: null,
             breathRate: "",
             breathShow: false,
             breathRpmList: [],
@@ -454,6 +457,7 @@ export default {
             },
             index: 0,
             showModle: false,
+            unsubscribeFn: null,
         };
     },
     computed: {},
@@ -1051,6 +1055,7 @@ export default {
 
         .center {
             position: absolute;
+            overflow: hidden;
             background-color: #fff;
             border: 14rpx solid #333333;
             background-image: url("https://hflnxx.oss-cn-shanghai.aliyuncs.com/IMAGE/20250919/toilet_bg.png");
@@ -1075,6 +1080,7 @@ export default {
 
         .tranStyle {
             position: absolute;
+            overflow: hidden;
             background-color: #fff;
             border: 9rpx solid #333333;
             background-image: url("https://hflnxx.oss-cn-shanghai.aliyuncs.com/IMAGE/20250919/toilet_bg.png");

+ 196 - 1
src/pagesA/deviceSetting/deviceSetting.vue

@@ -45,8 +45,16 @@
                 ></image>
             </view>
 
+            <view class="wifItem" @click="showRemoveDevice">
+                <text>设备转移</text>
+                <image
+                    src="../../static/rightArrow.png"
+                    style="width: 30rpx; height: 30rpx"
+                ></image>
+            </view>
+
             <view class="wifItem" @click="unbindDevice">
-                <text>解绑设备</text>
+                <text>设备解绑</text>
                 <image
                     src="../../static/rightArrow.png"
                     style="width: 30rpx; height: 30rpx"
@@ -59,6 +67,37 @@
             </view>
         </view>
         <tenMinutes v-if="isIniTenMinutes" />
+        <view class="modal-mask" v-if="removeDeviceModle">
+            <view class="modal-container">
+                <view class="modal-header">
+                    <text class="title">设备转移</text>
+                    <image
+                        src="../../static/closePng.png"
+                        @click="removeDeviceModle = false"
+                        class="close-btn"
+                    >
+                    </image>
+                </view>
+
+                <view class="modal-content">
+                    <input
+                        class="input"
+                        placeholder="请输入要转移的手机号"
+                        type="number"
+                        v-model="sharedPhone"
+                    />
+                </view>
+
+                <view class="modal-buttons">
+                    <button
+                        class="btn phone-btn"
+                        @click="handlePhoneAnalysis()"
+                    >
+                        <text>确认转移</text>
+                    </button>
+                </view>
+            </view>
+        </view>
     </view>
 </template>
 <script>
@@ -69,6 +108,8 @@ export default {
             devName: "",
             position: "",
             isIniTenMinutes: "",
+            sharedPhone: "",
+            removeDeviceModle: false,
         };
     },
     methods: {
@@ -142,6 +183,63 @@ export default {
                     JSON.stringify(this.devInfo),
             });
         },
+        showRemoveDevice() {
+            this.removeDeviceModle = true;
+        },
+        handlePhoneAnalysis() {
+            if (!this.sharedPhone) {
+                uni.showToast({
+                    title: "请输入手机号",
+                    icon: "none",
+                    duration: 1500,
+                });
+                return;
+            }
+
+            let reg_tel =
+                /^(13[0-9]|14[01456879]|15[0-3,5-9]|16[2567]|17[0-8]|18[0-9]|19[0-3,5-9])\d{8}$/;
+            if (!reg_tel.test(this.sharedPhone)) {
+                uni.showModal({
+                    content: "请填写正确手机号!",
+                    showCancel: false,
+                });
+                return;
+            }
+            this.$http
+                .post(
+                    "wap/device/transfer",
+                    {
+                        userId: uni.getStorageSync("userId"),
+                        devId: this.devInfo.devId,
+                        phone: this.sharedPhone,
+                    },
+                    {
+                        header: {
+                            "Content-Type": "application/json;charset=UTF-8",
+                            token: uni.getStorageSync("tokenValue") || "",
+                        },
+                    }
+                )
+                .then((res) => {
+                    if (res.data.code == 200) {
+                        uni.showToast({
+                            title: "转移成功",
+                            icon: "success",
+                            duration: 1500,
+                        });
+                        this.removeDeviceModle = false;
+                        this.sharedPhone = "";
+                    } else {
+                        uni.showToast({
+                            title: "转移失败",
+                            icon: "none",
+                            duration: 1500,
+                        });
+                        this.removeDeviceModle = false;
+                        this.sharedPhone = "";
+                    }
+                });
+        },
     },
     onLoad(options) {
         this.isIniTenMinutes = true;
@@ -222,5 +320,102 @@ export default {
             }
         }
     }
+    .modal-mask {
+        position: fixed;
+        top: 0;
+        left: 0;
+        right: 0;
+        bottom: 0;
+        background: rgba(0, 0, 0, 0.5);
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        z-index: 333;
+
+        .modal-container {
+            width: 80%;
+            background: #fff;
+            border-radius: 16rpx;
+            // overflow: hidden;
+            animation: fadeIn 0.3s;
+
+            .modal-header {
+                padding: 30rpx;
+                text-align: center;
+                border-bottom: 1rpx solid #f5f5f5;
+                position: relative;
+                .title {
+                    font-size: 36rpx;
+                    display: block;
+                    margin-bottom: 10rpx;
+                }
+
+                .close-btn {
+                    position: absolute;
+                    width: 40rpx;
+                    height: 40rpx;
+                    top: 20rpx;
+                    right: 20rpx;
+                }
+            }
+
+            .modal-content {
+                padding: 20rpx 20rpx;
+
+                .input {
+                    text-align: right;
+                    flex: 1;
+                    border: none;
+                    background: transparent;
+                    font-size: 28rpx;
+                    color: #333;
+                }
+            }
+
+            .modal-buttons {
+                display: flex;
+                flex-direction: column;
+                padding: 20rpx;
+
+                .btn {
+                    flex: 1;
+                    height: 90rpx;
+                    margin: 15rpx 0;
+                    border-radius: 45rpx;
+                    display: flex;
+                    align-items: center;
+                    justify-content: center;
+                    font-size: 32rpx;
+                    border: none;
+                    background: none;
+                    position: relative;
+                }
+
+                .btn-icon {
+                    width: 40rpx;
+                    height: 40rpx;
+                    margin-right: 15rpx;
+                }
+
+                .phone-btn {
+                    background: linear-gradient(
+                        105.95deg,
+                        #ba978a 0%,
+                        #a27867 100%
+                    );
+                    color: white;
+                }
+
+                .link-btn {
+                    background: linear-gradient(
+                        105.95deg,
+                        #a27867 0%,
+                        #74483d 100%
+                    );
+                    color: white;
+                }
+            }
+        }
+    }
 }
 </style>

+ 292 - 45
src/pagesA/roomSetting/roomSetting.vue

@@ -17,52 +17,80 @@
                     <text>3</text>
                 </view>
             </view>
-            <view
-                class="airCantInfo"
-                :style="{
-                    width: `${length / 150}px`,
-                    height: `${width / 150}px`,
-                }"
-            >
+            <view class="radar-box">
                 <view
-                    v-for="(item, index) in modules"
-                    :key="index"
-                    class="module-content"
+                    :style="{
+                        width: `${length / 200}px`,
+                        height: `${width / 200}px`,
+                        position: 'relative',
+                    }"
+                    :class="[
+                        width < 25500 && length < 25000
+                            ? 'tranStyle'
+                            : 'center',
+                    ]"
                 >
                     <view
-                        :class="item.type"
-                        :style="{
-                            width: `${item.width / 2}px`,
-                            height: `${item.length / 2}px`,
-                            top: `${item.top / 2}px`,
-                            left: `${item.left / 2}px`,
-                            transform: `rotate(${item.rotate}deg)`,
-                            'transform-origin': 'center center',
-                        }"
-                        @touchmove.prevent="onTouchMove(index, $event)"
-                        @touchstart="onTouchStart(index, $event)"
-                        @touchend="onTouchEnd(index, $event)"
+                        v-for="(item, index) in modules"
+                        :key="index"
+                        class="moduleContent"
                     >
-                        <image
-                            style="width: 100%; height: 100%; display: block"
-                            :src="`../../static/furnitures/${item.type}.png`"
-                            mode=""
-                        />
+                        <view
+                            :class="item.type"
+                            :style="{
+                                width: `${item.width / 2}px`,
+                                height: `${item.length / 2}px`,
+                                top: `${item.top / 2}px`,
+                                left: `${item.left / 2}px`,
+                                transform: `rotate(${item.rotate}deg)`,
+                                'transform-origin': 'center center',
+                            }"
+                            @touchmove.prevent="onTouchMove(index, $event)"
+                            @touchstart="onTouchStart(index, $event)"
+                            @touchend="onTouchEnd(index, $event)"
+                        >
+                            <image
+                                class="module-img"
+                                :src="`../../static/furnitures/${item.type}.png`"
+                                mode=""
+                            />
+                        </view>
                     </view>
-                    <image
-                        class="redar-pic"
-                        src="../../static/rander.png"
-                        mode=""
-                        :style="{
-                            transform:
-                                'translate(' +
-                                -xOffset / 80 +
-                                'rpx,' +
-                                -yOffset / 80 +
-                                'rpx)',
-                        }"
-                    />
+                    <template>
+                        <view v-for="item in targetPoints" :key="item.id">
+                            <image
+                                class="action-icon-M"
+                                :style="{
+                                    position: 'absolute',
+                                    transform: `translate3d(${
+                                        item.displayX / 2
+                                    }px, ${
+                                        -item.displayY / 2
+                                    }px, 0) translate(-50%, -50%)`,
+                                    zIndex: 9999,
+                                    transition: 'transform 1s linear',
+                                    willChange: 'transform',
+                                }"
+                                :src="`../../static/${lnbAction}.png`"
+                                mode=""
+                            />
+                        </view>
+                    </template>
                 </view>
+
+                <!-- <image
+                class="redar-pic"
+                src="../../static/rander.png"
+                mode=""
+                :style="{
+                    transform:
+                        'translate(' +
+                        -xOffset / 100 +
+                        'rpx,' +
+                        -yOffset / 100 +
+                        'rpx)',
+                }"
+            /> -->
             </view>
             <view class="airbody">
                 <view class="header_top">
@@ -246,6 +274,7 @@
     </view>
 </template>
 <script>
+import MqttService from "../../utils/globalMqtt.js";
 export default {
     name: "my",
     data() {
@@ -391,6 +420,14 @@ export default {
                     length: 40,
                 },
             ],
+            lnbAction: "action8",
+            // mqtt模块
+            targetPoints: {},
+            inactivityTimer: null,
+            left: 0,
+            top: 0,
+            clientIdProp: null,
+            clientId: null,
         };
     },
     computed: {},
@@ -711,13 +748,155 @@ export default {
                     }
                 });
         },
+
+        handleMessage(topic, message, clientId) {
+            // 清除不活动定时器
+            clearTimeout(this.inactivityTimer);
+            this.inactivityTimer = setTimeout(() => {
+                this.targetPoints = {};
+                console.log("长时间没有点位消除");
+            }, 1500);
+            // 验证topic格式
+            const match = topic.match(/^\/dev\/(.+)\/tracker_targets$/);
+            if (!match || match[1] !== clientId) return;
+
+            try {
+                const data = JSON.parse(message.toString());
+                // if (data.health) {
+                //     if (
+                //         data.health.breath_rpm ||
+                //         data.health.breath_rpm === 0
+                //     ) {
+                //         this.receptHealth(Math.floor(data.health.breath_rpm));
+                //     } else {
+                //     }
+                // }
+                // console.log(data.tracker_targets, "MQTT消息解析成功22222");
+                this.processTrackerData(data.tracker_targets);
+            } catch (e) {
+                console.error("MQTT消息解析失败", e);
+            }
+        },
+
+        processTrackerData(arr) {
+            if (Array.isArray(arr) && arr.length > 0 && Array.isArray(arr[0])) {
+                this.targetPoints = {};
+                const currentIds = new Set();
+                const newTargetPoints = {};
+                // 处理每个追踪目标
+                arr.forEach((item) => {
+                    if (!Array.isArray(item) || item.length < 4) return;
+
+                    const [x, y, z, id] = item;
+                    currentIds.add(id.toString());
+
+                    // 处理新点或更新现有点
+                    if (!this.targetPoints[id]) {
+                        newTargetPoints[id] = this.createNewTargetPoint(
+                            x,
+                            y,
+                            z,
+                            id
+                        );
+                    } else {
+                        newTargetPoints[id] = this.updateExistingTargetPoint(
+                            this.targetPoints[id],
+                            x,
+                            y,
+                            z,
+                            2
+                        );
+                    }
+                });
+
+                // 移除不存在的点
+                Object.keys(this.targetPoints).forEach((id) => {
+                    if (!currentIds.has(id)) {
+                        delete this.targetPoints[id];
+                    }
+                });
+
+                // 更新目标点
+                this.targetPoints = {
+                    ...this.targetPoints,
+                    ...newTargetPoints,
+                };
+                if (Array.isArray(this.targetPoints)) {
+                    this.targetPoints = this.targetPoints.filter(
+                        (item) => item !== null && item !== undefined
+                    );
+                }
+            }
+        },
+        createNewTargetPoint(x, y, z, id) {
+            return {
+                x,
+                y,
+                z,
+                id,
+                displayX: x - Number(this.xxStart),
+                displayY: y - Number(this.yyEnd),
+                lastX: x,
+                lastY: y,
+            };
+        },
+        updateExistingTargetPoint(existingPoint, x, y, z, THRESHOLD) {
+            const dx = x - existingPoint.lastX;
+            const dy = y - existingPoint.lastY;
+            const distance = Math.sqrt(dx * dx + dy * dy);
+
+            if (distance > THRESHOLD) {
+                return {
+                    ...existingPoint,
+                    x,
+                    y,
+                    z,
+                    lastX: x,
+                    lastY: y,
+                    displayX: x - Number(this.xxStart),
+                    displayY: y - Number(this.yyEnd),
+                };
+            }
+
+            return existingPoint;
+        },
     },
     onLoad(options) {
         this.devId = options.devId;
+        this.clientId = options.clientId;
+
+        console.log(options, "options111111");
         this.getdevInfo(this.devId);
         this.getRoomInfo(this.devId);
     },
-    onShow() {},
+    onShow() {
+        const topic = `/dev/${this.clientId}/tracker_targets`;
+        // 使用 MqttService.subscribe 管理订阅
+        this.unsubscribeFn = MqttService.subscribe(
+            "DATA",
+            topic,
+            (message, msgTopic) => {
+                // console.log(`接收到 ${msgTopic} 消息:`, message);
+                // 处理消息
+                const dataMatch = msgTopic.match(
+                    /^\/dev\/(.+)\/tracker_targets$/
+                );
+                if (dataMatch && dataMatch[1] === this.clientId) {
+                    this.handleMessage(msgTopic, message, this.clientId);
+                }
+            }
+        );
+        if (this.unsubscribeFn) {
+            console.log(`✅ 已成功订阅主题: ${topic}`);
+        }
+    },
+
+    onHide() {
+        if (this.unsubscribeFn) {
+            this.unsubscribeFn();
+            this.unsubscribeFn = null;
+        }
+    },
 };
 </script>
 <style lang="less" scoped>
@@ -763,12 +942,79 @@ export default {
                 background-color: #e4c5b9;
             }
         }
-        .airCantInfo {
-            margin: 30rpx auto 0 auto;
-            border: 18rpx solid #1f1f1f;
+        .radar-box {
+            margin: 0 auto;
             position: relative;
-            .module-content > view {
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            width: 710rpx;
+            height: 710rpx;
+            background: #ffffff;
+            border-radius: 37.5rpx;
+            box-sizing: border-box;
+
+            .center {
                 position: absolute;
+                overflow: hidden;
+                background-color: #fff;
+                border: 14rpx solid #333333;
+                background-image: url("https://hflnxx.oss-cn-shanghai.aliyuncs.com/IMAGE/20250919/toilet_bg.png");
+                background-repeat: no-repeat;
+                background-position: center;
+                transform: scale(1.3);
+
+                .moduleContent {
+                    position: relative;
+
+                    view {
+                        position: absolute;
+                    }
+
+                    .module-img {
+                        width: 100%;
+                        height: 100%;
+                        display: block;
+                    }
+                }
+            }
+
+            .tranStyle {
+                position: absolute;
+                overflow: hidden;
+                background-color: #fff;
+                border: 9rpx solid #333333;
+                background-image: url("https://hflnxx.oss-cn-shanghai.aliyuncs.com/IMAGE/20250919/toilet_bg.png");
+                background-repeat: no-repeat;
+                background-position: center;
+                transform: scale(2.3);
+
+                .moduleContent {
+                    // overflow: hidden;
+
+                    // position: relative;
+                    view {
+                        position: absolute;
+                    }
+
+                    .module-img {
+                        width: 100%;
+                        height: 100%;
+                        display: block;
+                    }
+                }
+            }
+
+            .action-icon-G {
+                position: absolute;
+                width: 100rpx;
+                height: 100rpx;
+            }
+
+            .action-icon-M {
+                // position: absolute;
+                width: 50rpx;
+                height: 50rpx;
             }
             .redar-pic {
                 position: absolute;
@@ -779,6 +1025,7 @@ export default {
                 transform: translate(-50%, -50%); /* 先居中 */
             }
         }
+
         .airbody {
             margin: 80rpx auto 0 auto;
             width: 700rpx;

+ 1 - 1
src/pagesA/shareCountList/shareCountList.vue

@@ -98,7 +98,7 @@ export default {
                     }
                 )
                 .then((res) => {
-                    uni.hideLoading();
+                    uni.hideToast();
                     if (res.data.data) {
                         this.shareList = res.data.data;
                     }