|
|
|
@ -212,136 +212,204 @@
|
|
|
|
|
<el-dialog
|
|
|
|
|
title="⚠️ 实时告警通知"
|
|
|
|
|
:visible.sync="realtimeAlarmDialog"
|
|
|
|
|
width="800px"
|
|
|
|
|
width="900px"
|
|
|
|
|
append-to-body
|
|
|
|
|
:close-on-click-modal="false"
|
|
|
|
|
:close-on-press-escape="false"
|
|
|
|
|
class="realtime-alarm-dialog"
|
|
|
|
|
>
|
|
|
|
|
<div v-if="currentRealtimeAlarm" class="alarm-content">
|
|
|
|
|
<!-- 设备信息 -->
|
|
|
|
|
<div class="alarm-section">
|
|
|
|
|
<h3 class="section-title">📟 设备信息</h3>
|
|
|
|
|
<el-row :gutter="16">
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<div class="info-item">
|
|
|
|
|
<span class="label">设备ID:</span>
|
|
|
|
|
<span class="value">{{ currentRealtimeAlarm.monitorId }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<div class="info-item">
|
|
|
|
|
<span class="label">告警时间:</span>
|
|
|
|
|
<span class="value">{{ formatAlarmTime(currentRealtimeAlarm.recordTime) }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
</el-row>
|
|
|
|
|
</div>
|
|
|
|
|
<el-tabs v-model="realtimeActiveTab" type="card">
|
|
|
|
|
<!-- 告警详情标签页 -->
|
|
|
|
|
<el-tab-pane label="告警详情" name="alarmDetail">
|
|
|
|
|
<div v-if="currentRealtimeAlarm" class="alarm-content">
|
|
|
|
|
<!-- 设备信息 -->
|
|
|
|
|
<div class="alarm-section">
|
|
|
|
|
<h3 class="section-title">📟 设备信息</h3>
|
|
|
|
|
<el-row :gutter="16">
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<div class="info-item">
|
|
|
|
|
<span class="label">设备ID:</span>
|
|
|
|
|
<span class="value">{{ currentRealtimeAlarm.monitorId }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<div class="info-item">
|
|
|
|
|
<span class="label">告警时间:</span>
|
|
|
|
|
<span class="value">{{ formatAlarmTime(currentRealtimeAlarm.recordTime) }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
</el-row>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 设备当前数据 -->
|
|
|
|
|
<div class="alarm-section" v-if="currentRealtimeAlarm.deviceParam">
|
|
|
|
|
<h3 class="section-title">📊 设备当前数据</h3>
|
|
|
|
|
<el-row :gutter="16">
|
|
|
|
|
<el-col :span="8" v-if="currentRealtimeAlarm.deviceParam.temperature !== null">
|
|
|
|
|
<div class="data-item">
|
|
|
|
|
<span class="data-label">温度:</span>
|
|
|
|
|
<span class="data-value">{{ currentRealtimeAlarm.deviceParam.temperature }}°C</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="8" v-if="currentRealtimeAlarm.deviceParam.humidity !== null">
|
|
|
|
|
<div class="data-item">
|
|
|
|
|
<span class="data-label">湿度:</span>
|
|
|
|
|
<span class="data-value">{{ currentRealtimeAlarm.deviceParam.humidity }}%</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="8" v-if="currentRealtimeAlarm.deviceParam.illuminance !== null">
|
|
|
|
|
<div class="data-item">
|
|
|
|
|
<span class="data-label">照度:</span>
|
|
|
|
|
<span class="data-value">{{ currentRealtimeAlarm.deviceParam.illuminance }}lx</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="8" v-if="currentRealtimeAlarm.deviceParam.noise !== null">
|
|
|
|
|
<div class="data-item">
|
|
|
|
|
<span class="data-label">噪声:</span>
|
|
|
|
|
<span class="data-value">{{ currentRealtimeAlarm.deviceParam.noise }}dB</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="8" v-if="currentRealtimeAlarm.deviceParam.concentration !== null">
|
|
|
|
|
<div class="data-item">
|
|
|
|
|
<span class="data-label">气体浓度:</span>
|
|
|
|
|
<span class="data-value">{{ currentRealtimeAlarm.deviceParam.concentration }}ppm</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="8" v-if="currentRealtimeAlarm.deviceParam.vibrationSpeed !== null">
|
|
|
|
|
<div class="data-item">
|
|
|
|
|
<span class="data-label">振动速度:</span>
|
|
|
|
|
<span class="data-value">{{ currentRealtimeAlarm.deviceParam.vibrationSpeed || currentRealtimeAlarm.deviceParam.VibrationSpeed }}mm/s</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="8" v-if="currentRealtimeAlarm.deviceParam.vibrationDisplacement !== null || currentRealtimeAlarm.deviceParam.VibrationDisplacement !== null">
|
|
|
|
|
<div class="data-item">
|
|
|
|
|
<span class="data-label">振动位移:</span>
|
|
|
|
|
<span class="data-value">{{ currentRealtimeAlarm.deviceParam.vibrationDisplacement || currentRealtimeAlarm.deviceParam.VibrationDisplacement }}um</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="8" v-if="currentRealtimeAlarm.deviceParam.vibrationAcceleration !== null || currentRealtimeAlarm.deviceParam.VibrationAcceleration !== null">
|
|
|
|
|
<div class="data-item">
|
|
|
|
|
<span class="data-label">振动加速度:</span>
|
|
|
|
|
<span class="data-value">{{ currentRealtimeAlarm.deviceParam.vibrationAcceleration || currentRealtimeAlarm.deviceParam.VibrationAcceleration }}g</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="8" v-if="currentRealtimeAlarm.deviceParam.vibrationTemp !== null || currentRealtimeAlarm.deviceParam.VibrationTemp !== null">
|
|
|
|
|
<div class="data-item">
|
|
|
|
|
<span class="data-label">振动温度:</span>
|
|
|
|
|
<span class="data-value">{{ currentRealtimeAlarm.deviceParam.vibrationTemp || currentRealtimeAlarm.deviceParam.VibrationTemp }}℃</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
</el-row>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- 设备当前数据 -->
|
|
|
|
|
<div class="alarm-section" v-if="currentRealtimeAlarm.deviceParam">
|
|
|
|
|
<h3 class="section-title">📊 设备当前数据</h3>
|
|
|
|
|
<el-row :gutter="16">
|
|
|
|
|
<el-col :span="8" v-if="currentRealtimeAlarm.deviceParam.temperature !== null">
|
|
|
|
|
<div class="data-item">
|
|
|
|
|
<span class="data-label">温度:</span>
|
|
|
|
|
<span class="data-value">{{ currentRealtimeAlarm.deviceParam.temperature }}°C</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="8" v-if="currentRealtimeAlarm.deviceParam.humidity !== null">
|
|
|
|
|
<div class="data-item">
|
|
|
|
|
<span class="data-label">湿度:</span>
|
|
|
|
|
<span class="data-value">{{ currentRealtimeAlarm.deviceParam.humidity }}%</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="8" v-if="currentRealtimeAlarm.deviceParam.illuminance !== null">
|
|
|
|
|
<div class="data-item">
|
|
|
|
|
<span class="data-label">照度:</span>
|
|
|
|
|
<span class="data-value">{{ currentRealtimeAlarm.deviceParam.illuminance }}lx</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="8" v-if="currentRealtimeAlarm.deviceParam.noise !== null">
|
|
|
|
|
<div class="data-item">
|
|
|
|
|
<span class="data-label">噪声:</span>
|
|
|
|
|
<span class="data-value">{{ currentRealtimeAlarm.deviceParam.noise }}dB</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="8" v-if="currentRealtimeAlarm.deviceParam.concentration !== null">
|
|
|
|
|
<div class="data-item">
|
|
|
|
|
<span class="data-label">气体浓度:</span>
|
|
|
|
|
<span class="data-value">{{ currentRealtimeAlarm.deviceParam.concentration }}ppm</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="8" v-if="currentRealtimeAlarm.deviceParam.vibrationSpeed !== null">
|
|
|
|
|
<div class="data-item">
|
|
|
|
|
<span class="data-label">振动速度:</span>
|
|
|
|
|
<span class="data-value">{{ currentRealtimeAlarm.deviceParam.vibrationSpeed || currentRealtimeAlarm.deviceParam.VibrationSpeed }}mm/s</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="8" v-if="currentRealtimeAlarm.deviceParam.vibrationDisplacement !== null || currentRealtimeAlarm.deviceParam.VibrationDisplacement !== null">
|
|
|
|
|
<div class="data-item">
|
|
|
|
|
<span class="data-label">振动位移:</span>
|
|
|
|
|
<span class="data-value">{{ currentRealtimeAlarm.deviceParam.vibrationDisplacement || currentRealtimeAlarm.deviceParam.VibrationDisplacement }}um</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="8" v-if="currentRealtimeAlarm.deviceParam.vibrationAcceleration !== null || currentRealtimeAlarm.deviceParam.VibrationAcceleration !== null">
|
|
|
|
|
<div class="data-item">
|
|
|
|
|
<span class="data-label">振动加速度:</span>
|
|
|
|
|
<span class="data-value">{{ currentRealtimeAlarm.deviceParam.vibrationAcceleration || currentRealtimeAlarm.deviceParam.VibrationAcceleration }}g</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="8" v-if="currentRealtimeAlarm.deviceParam.vibrationTemp !== null || currentRealtimeAlarm.deviceParam.VibrationTemp !== null">
|
|
|
|
|
<div class="data-item">
|
|
|
|
|
<span class="data-label">振动温度:</span>
|
|
|
|
|
<span class="data-value">{{ currentRealtimeAlarm.deviceParam.vibrationTemp || currentRealtimeAlarm.deviceParam.VibrationTemp }}℃</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
</el-row>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 触发的告警规则 -->
|
|
|
|
|
<div class="alarm-section" v-if="currentRealtimeAlarm.alarmRules && currentRealtimeAlarm.alarmRules.length > 0">
|
|
|
|
|
<h3 class="section-title">🚨 触发的告警规则</h3>
|
|
|
|
|
<div class="alarm-rules">
|
|
|
|
|
<div
|
|
|
|
|
v-for="(rule, index) in currentRealtimeAlarm.alarmRules"
|
|
|
|
|
:key="index"
|
|
|
|
|
class="rule-item"
|
|
|
|
|
>
|
|
|
|
|
<div class="rule-header">
|
|
|
|
|
<span class="rule-name">{{ rule.ruleName }}</span>
|
|
|
|
|
<el-tag :type="rule.triggerRule === 0 ? 'danger' : 'warning'" size="small">
|
|
|
|
|
{{ rule.triggerRule === 0 ? '大于阈值' : '小于阈值' }}
|
|
|
|
|
</el-tag>
|
|
|
|
|
<!-- 触发的告警规则 -->
|
|
|
|
|
<div class="alarm-section" v-if="currentRealtimeAlarm.alarmRules && currentRealtimeAlarm.alarmRules.length > 0">
|
|
|
|
|
<h3 class="section-title">🚨 触发的告警规则</h3>
|
|
|
|
|
<div class="alarm-rules">
|
|
|
|
|
<div
|
|
|
|
|
v-for="(rule, index) in currentRealtimeAlarm.alarmRules"
|
|
|
|
|
:key="index"
|
|
|
|
|
class="rule-item"
|
|
|
|
|
>
|
|
|
|
|
<div class="rule-header">
|
|
|
|
|
<span class="rule-name">{{ rule.ruleName }}</span>
|
|
|
|
|
<el-tag :type="rule.triggerRule === 0 ? 'danger' : 'warning'" size="small">
|
|
|
|
|
{{ rule.triggerRule === 0 ? '大于阈值' : '小于阈值' }}
|
|
|
|
|
</el-tag>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="rule-details">
|
|
|
|
|
<span class="detail-item">阈值:{{ rule.triggerValue }}</span>
|
|
|
|
|
<span class="detail-item">监测字段:{{ getFieldName(rule.monitorField) }}</span>
|
|
|
|
|
<span class="detail-item" v-if="rule.cause">备注:{{ rule.cause }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="rule-details">
|
|
|
|
|
<span class="detail-item">阈值:{{ rule.triggerValue }}</span>
|
|
|
|
|
<span class="detail-item">监测字段:{{ getFieldName(rule.monitorField) }}</span>
|
|
|
|
|
<span class="detail-item" v-if="rule.cause">备注:{{ rule.cause }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 告警内容详情 -->
|
|
|
|
|
<div class="alarm-section" v-if="currentRealtimeAlarm.alarmContents && currentRealtimeAlarm.alarmContents.length > 0">
|
|
|
|
|
<h3 class="section-title">📋 告警内容详情</h3>
|
|
|
|
|
<div class="alarm-contents">
|
|
|
|
|
<div
|
|
|
|
|
v-for="(content, index) in currentRealtimeAlarm.alarmContents"
|
|
|
|
|
:key="index"
|
|
|
|
|
class="content-item"
|
|
|
|
|
>
|
|
|
|
|
<el-alert
|
|
|
|
|
:title="content"
|
|
|
|
|
type="error"
|
|
|
|
|
:closable="false"
|
|
|
|
|
show-icon
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</el-tab-pane>
|
|
|
|
|
|
|
|
|
|
<!-- 告警内容详情 -->
|
|
|
|
|
<div class="alarm-section" v-if="currentRealtimeAlarm.alarmContents && currentRealtimeAlarm.alarmContents.length > 0">
|
|
|
|
|
<h3 class="section-title">📋 告警内容详情</h3>
|
|
|
|
|
<div class="alarm-contents">
|
|
|
|
|
<div
|
|
|
|
|
v-for="(content, index) in currentRealtimeAlarm.alarmContents"
|
|
|
|
|
:key="index"
|
|
|
|
|
class="content-item"
|
|
|
|
|
>
|
|
|
|
|
<el-alert
|
|
|
|
|
:title="content"
|
|
|
|
|
type="error"
|
|
|
|
|
:closable="false"
|
|
|
|
|
show-icon
|
|
|
|
|
/>
|
|
|
|
|
<!-- 处置措施标签页 -->
|
|
|
|
|
<el-tab-pane label="处置措施" name="realtimeActionSteps">
|
|
|
|
|
<div v-if="currentRealtimeAlarm">
|
|
|
|
|
<el-alert
|
|
|
|
|
:title="`设备:${currentRealtimeAlarm.monitorId} | 告警时间:${formatAlarmTime(currentRealtimeAlarm.recordTime)}`"
|
|
|
|
|
type="warning"
|
|
|
|
|
:closable="false"
|
|
|
|
|
style="margin-bottom: 20px;"
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<div v-loading="realtimeActionStepsLoading">
|
|
|
|
|
<div v-if="realtimeActionSteps.length === 0" class="no-steps">
|
|
|
|
|
<el-empty description="该告警规则暂无配置处置措施"></el-empty>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div v-else>
|
|
|
|
|
<el-timeline>
|
|
|
|
|
<el-timeline-item
|
|
|
|
|
v-for="(step, index) in realtimeActionSteps"
|
|
|
|
|
:key="step.objId"
|
|
|
|
|
:timestamp="`步骤 ${step.stepSequence}`"
|
|
|
|
|
placement="top"
|
|
|
|
|
type="primary"
|
|
|
|
|
size="large"
|
|
|
|
|
>
|
|
|
|
|
<el-card class="step-card">
|
|
|
|
|
<div slot="header" class="clearfix">
|
|
|
|
|
<span class="step-title">第{{ step.stepSequence }}步</span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 步骤描述 -->
|
|
|
|
|
<div class="step-description">
|
|
|
|
|
<p>{{ step.description }}</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 步骤图片 -->
|
|
|
|
|
<div v-if="step.stepImages && step.stepImages.length > 0" class="step-images">
|
|
|
|
|
<div class="images-title">参考图片:</div>
|
|
|
|
|
<div class="image-gallery">
|
|
|
|
|
<div
|
|
|
|
|
v-for="image in step.stepImages"
|
|
|
|
|
:key="image.objId"
|
|
|
|
|
class="image-item"
|
|
|
|
|
@click="previewImage(getFullImageUrl(image.imageUrl))"
|
|
|
|
|
>
|
|
|
|
|
<img :src="getFullImageUrl(image.imageUrl)" :alt="image.description" />
|
|
|
|
|
<div v-if="image.description" class="image-desc">{{ image.description }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 步骤备注 -->
|
|
|
|
|
<div v-if="step.remark" class="step-remark">
|
|
|
|
|
<el-tag type="info" size="small">备注:{{ step.remark }}</el-tag>
|
|
|
|
|
</div>
|
|
|
|
|
</el-card>
|
|
|
|
|
</el-timeline-item>
|
|
|
|
|
</el-timeline>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</el-tab-pane>
|
|
|
|
|
</el-tabs>
|
|
|
|
|
|
|
|
|
|
<div slot="footer" class="dialog-footer">
|
|
|
|
|
<el-button
|
|
|
|
@ -423,7 +491,12 @@ export default {
|
|
|
|
|
alarmQueueStatusText: '',
|
|
|
|
|
queueStatusColor: '',
|
|
|
|
|
alarmQueueLength: 0,
|
|
|
|
|
queueStatusTimer: null
|
|
|
|
|
queueStatusTimer: null,
|
|
|
|
|
|
|
|
|
|
// 实时告警处置措施相关
|
|
|
|
|
realtimeActiveTab: 'alarmDetail',
|
|
|
|
|
realtimeActionSteps: [],
|
|
|
|
|
realtimeActionStepsLoading: false
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
created() {
|
|
|
|
@ -617,12 +690,18 @@ export default {
|
|
|
|
|
this.alarmProcessedCallback = onProcessed
|
|
|
|
|
this.alarmTimeoutCallback = onTimeout
|
|
|
|
|
|
|
|
|
|
// 重置标签页到告警详情
|
|
|
|
|
this.realtimeActiveTab = 'alarmDetail'
|
|
|
|
|
|
|
|
|
|
// 显示告警弹窗
|
|
|
|
|
this.realtimeAlarmDialog = true
|
|
|
|
|
|
|
|
|
|
// 播放提示音
|
|
|
|
|
this.playAlarmSound()
|
|
|
|
|
|
|
|
|
|
// 自动加载第一个告警规则的处置措施
|
|
|
|
|
this.loadRealtimeActionSteps(alarm)
|
|
|
|
|
|
|
|
|
|
console.log('告警弹窗已显示,告警ID:', alarm.id, '优先级:', alarm.priority)
|
|
|
|
|
},
|
|
|
|
|
// 播放告警提示音
|
|
|
|
@ -812,6 +891,11 @@ export default {
|
|
|
|
|
this.currentAlarmId = null
|
|
|
|
|
this.alarmProcessedCallback = null
|
|
|
|
|
this.alarmTimeoutCallback = null
|
|
|
|
|
|
|
|
|
|
// 清理实时告警处置措施数据
|
|
|
|
|
this.realtimeActiveTab = 'alarmDetail'
|
|
|
|
|
this.realtimeActionSteps = []
|
|
|
|
|
this.realtimeActionStepsLoading = false
|
|
|
|
|
},
|
|
|
|
|
// 格式化告警时间
|
|
|
|
|
formatAlarmTime(time) {
|
|
|
|
@ -926,6 +1010,29 @@ export default {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
// 加载实时告警的处置措施
|
|
|
|
|
async loadRealtimeActionSteps(alarm) {
|
|
|
|
|
if (!alarm || !alarm.alarmRules || alarm.alarmRules.length === 0) {
|
|
|
|
|
this.realtimeActionSteps = []
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.realtimeActionStepsLoading = true
|
|
|
|
|
try {
|
|
|
|
|
// 使用第一个告警规则的字段信息来获取处置措施
|
|
|
|
|
const firstRule = alarm.alarmRules[0]
|
|
|
|
|
const fieldName = this.getFieldName(firstRule.monitorField)
|
|
|
|
|
|
|
|
|
|
const response = await getEmsAlarmActionStepsByAlarmInfo(alarm.monitorId, fieldName)
|
|
|
|
|
this.realtimeActionSteps = response.data || []
|
|
|
|
|
console.log('实时告警处置措施加载成功:', this.realtimeActionSteps.length, '个步骤')
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('加载实时告警处置措施失败:', error)
|
|
|
|
|
this.realtimeActionSteps = []
|
|
|
|
|
} finally {
|
|
|
|
|
this.realtimeActionStepsLoading = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|