Merge branch 'dev_robotaxi-d_230612_3.3.0' into 3.3.0merge2master

This commit is contained in:
yangyakun
2023-07-07 15:25:07 +08:00
348 changed files with 10472 additions and 7214 deletions

View File

@@ -3,14 +3,14 @@ package com.mogo.eagle.core.function.call.autopilot
import android.os.SystemClock
import chassis.SpecialVehicleTaskCmdOuterClass
import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters
import com.mogo.eagle.core.data.biz.trafficlight.TrafficLightResult
import com.mogo.eagle.core.data.deva.badcase.BagManagerEntity
import com.mogo.eagle.core.data.config.FunctionBuildConfig
import com.mogo.eagle.core.data.constants.MogoServicePaths
import com.mogo.eagle.core.data.deva.badcase.BagManagerEntity
import com.mogo.eagle.core.data.deva.bizconfig.FuncBizConfig
import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_ALIAS_CODE_EAGLE_START_AUTOPILOT
import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_LINK_ADAS
import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_LINK_LOG_WEB_SOCKET_AUTOPILOT
import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_SOURCE_ADAS
import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_TYPE_SOCKET_AUTOPILOT
import com.mogo.eagle.core.data.biz.trafficlight.TrafficLightResult
import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_CODE_OCH_TAXI_START_AUTOPILOT_MOFANG
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotControlProvider
import com.mogo.eagle.core.function.call.base.CallerBase
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
@@ -20,8 +20,8 @@ import com.zhjt.mogo.adas.data.sweeper.task.SweeperTask.StartTaskResp
import com.zhjt.mogo.adas.data.sweeper.task.SweeperTaskSuspendResume.SuspendResumeTaskReq
import com.zhjt.mogo.adas.data.sweeper.task.confirm.SweeperTaskConfirm.TaskConfirmResp
import com.zhjt.mogo.adas.data.sweeper.task.stop.SweeperTaskStop.StopTaskResp
import com.zhjt.mogo.adas.data.AdasConstants
import com.zhjt.service.chain.ChainLog
import com.zhjt.service.chain.TracingConstants
import com.zhjt.service_biz.BizConfig
import kotlin.random.Random
@@ -61,14 +61,6 @@ object CallerAutoPilotControlManager {
*
* @param controlParameters 开启自动驾驶的控制参数
*/
@ChainLog(
linkChainLog = CHAIN_LINK_LOG_WEB_SOCKET_AUTOPILOT,
linkCode = CHAIN_LINK_ADAS,
endpoint = TracingConstants.Endpoint.PAD,
nodeAliasCode = CHAIN_ALIAS_CODE_EAGLE_START_AUTOPILOT,
paramIndexes = [0],
clientPkFileName = "sn"
)
fun startAutoPilot(controlParameters: AutopilotControlParameters?) {
if (controlParameters == null) {
//LogUtils.eTag(TAG, "自动驾驶控制参数异常,请检查参数信息")
@@ -85,12 +77,10 @@ object CallerAutoPilotControlManager {
* @param controlParameters 开启自动驾驶的控制参数
*/
@ChainLog(
linkChainLog = CHAIN_LINK_LOG_WEB_SOCKET_AUTOPILOT,
linkCode = CHAIN_LINK_ADAS,
endpoint = TracingConstants.Endpoint.PAD,
nodeAliasCode = CHAIN_ALIAS_CODE_EAGLE_START_AUTOPILOT,
linkChainLog = CHAIN_TYPE_SOCKET_AUTOPILOT,
linkCode = CHAIN_SOURCE_ADAS,
nodeAliasCode = CHAIN_CODE_OCH_TAXI_START_AUTOPILOT_MOFANG,
paramIndexes = [0],
clientPkFileName = "sn"
)
fun startAutoPilotByMoFang(controlParameters: AutopilotControlParameters?) {
providerApi?.startAutoPilotByMoFang(controlParameters)
@@ -292,7 +282,7 @@ object CallerAutoPilotControlManager {
/**
* 获取全部参数
* 结果回调{@link OnAdasListener#onGetParamResp(MessagePad.Header, MessagePad.SetParamReq)}
* 结果回调{@link OnAdasListener#onGetParamResp(MessagePad.Header, MessagePad.SetParamReq, AdasParam)}
*
* @return boolean
*/
@@ -302,12 +292,12 @@ object CallerAutoPilotControlManager {
/**
* 参数获取请求
* 结果回调{@link OnAdasListener#onGetParamResp(MessagePad.Header, MessagePad.SetParamReq)}
* 结果回调{@link OnAdasListener#onGetParamResp(MessagePad.Header, MessagePad.SetParamReq, AdasParam)}
*
* @param paramType 参数类型{@link com.zhidao.support.adas.high.common.Constants.PARAM_TYPE}
* @param paramType 参数类型:libraries/mogo-adas-data/src/main/proto/personal/adas_constants.proto
* @return boolean
*/
fun sendGetParamReq(paramType: Int): Boolean? {
fun sendGetParamReq(paramType: AdasConstants.MapSystemParamType): Boolean? {
return providerApi?.sendGetParamReq(paramType)
}
/**

View File

@@ -7,10 +7,8 @@ import com.mogo.eagle.core.function.call.base.CallerBase
import com.mogo.eagle.core.utilcode.util.GsonUtils
import mogo.telematics.pad.MessagePad
import mogo_msg.MogoReportMsg
import system_master.*
import java.util.concurrent.ConcurrentHashMap
import kotlin.properties.Delegates
import system_master.SystemStatusInfo
import kotlin.properties.Delegates
/**
* 域控制器相关的回调监听
@@ -24,7 +22,7 @@ object CallerAutoPilotStatusListenerManager : CallerBase<IMoGoAutopilotStatusLis
private var mAutopilotStatusInfo: AutopilotStatusInfo = AutopilotStatusInfo()
private var lineId: Long? by Delegates.observable(0) { _, _, newValue ->
if(newValue == null){
if (newValue == null) {
return@observable
}
M_LISTENERS.forEach {
@@ -33,12 +31,38 @@ object CallerAutoPilotStatusListenerManager : CallerBase<IMoGoAutopilotStatusLis
}
}
private var autopilotState: Int by Delegates.observable(0) { _, oldValue, newValue ->
if (oldValue != newValue) {
M_LISTENERS.forEach {
val listener = it.value
listener.onAutopilotStatusResponse(newValue)
}
}
}
private var dockerV: String by Delegates.observable("") { _, oldValue, newValue ->
if (!oldValue.contentEquals(newValue)) {
M_LISTENERS.forEach {
val listener = it.value
listener.onAutopilotDockerInfo(newValue)
}
}
}
@Volatile
private var autoPilotMessageCode: String = ""
@Volatile
private var autoPilotMessageContent: String = ""
override fun doSomeAfterAddListener(tag: String, listener: IMoGoAutopilotStatusListener) {
listener.onAutopilotStatusResponse(mAutopilotStatusInfo)
listener.onAutopilotStatusResponse(autopilotState)
if(dockerV.isNotEmpty()){
listener.onAutopilotDockerInfo(dockerV)
}
}
/**
* 查询AutoPilot状态
*/
@@ -46,6 +70,29 @@ object CallerAutoPilotStatusListenerManager : CallerBase<IMoGoAutopilotStatusLis
return mAutopilotStatusInfo
}
fun getState(): Int {
return mAutopilotStatusInfo.state
}
fun getLineId(): Long {
return lineId ?: 0L
}
fun getDockerVersion():String?{
return mAutopilotStatusInfo.dockVersion
}
fun getConnectStates():Boolean{
return mAutopilotStatusInfo.connectStatus
}
/**
* 获取当前时刻WGS84 卫星时间
*/
fun getCurWgs84SatelliteTime(): Double {
return mAutopilotStatusInfo.satelliteTime
}
/**
* 查询AutoPilot状态
*/
@@ -60,7 +107,7 @@ object CallerAutoPilotStatusListenerManager : CallerBase<IMoGoAutopilotStatusLis
/**
* 通过Gnss定位更新来同步更新自动驾驶状态
*/
fun updateAutoPilotLatLon(satelliteTime: Double, lon: Double, lat: Double) {
fun updateAutoPilotLocAndTime(satelliteTime: Double, lon: Double, lat: Double) {
mAutopilotStatusInfo.locationLat = lat
mAutopilotStatusInfo.locationLon = lon
mAutopilotStatusInfo.satelliteTime = satelliteTime
@@ -68,29 +115,17 @@ object CallerAutoPilotStatusListenerManager : CallerBase<IMoGoAutopilotStatusLis
invokeAutoPilotStatus()
}
/**
* 获取当前时刻WGS84 lat
*/
fun getCurWgs84Lat(): Double {
return mAutopilotStatusInfo.locationLat
fun updateAutoPilotStatus(autopilotState: Int, autopilotMode: Int) {
mAutopilotStatusInfo.state = autopilotState
this.autopilotState = autopilotState
mAutopilotStatusInfo.pilotmode = autopilotMode
invokeAutoPilotStatus()
}
/**
* 获取当前时刻WGS84 lon
*/
fun getCurWgs84Lon(): Double {
return mAutopilotStatusInfo.locationLon
}
/**
* 获取当前时刻WGS84 卫星时间
*/
fun getCurWgs84SatelliteTime(): Double {
return mAutopilotStatusInfo.satelliteTime
}
override fun doSomeAfterAddListener(tag: String, listener: IMoGoAutopilotStatusListener) {
listener.onAutopilotStatusResponse(mAutopilotStatusInfo)
fun updateAutoPilotDockerInfo(dockerV: String) {
this.dockerV = dockerV
mAutopilotStatusInfo.dockVersion = dockerV
invokeAutoPilotStatus()
}
/**
@@ -109,7 +144,6 @@ object CallerAutoPilotStatusListenerManager : CallerBase<IMoGoAutopilotStatusLis
fun invokeAutoPilotStatus(autopilotStatusInfo: AutopilotStatusInfo) {
mAutopilotStatusInfo = autopilotStatusInfo
M_LISTENERS.forEach {
val tag = it.key
val listener = it.value
listener.onAutopilotStatusResponse(mAutopilotStatusInfo)
}
@@ -122,7 +156,6 @@ object CallerAutoPilotStatusListenerManager : CallerBase<IMoGoAutopilotStatusLis
@Synchronized
fun invokeArriveAtStation(arrivalNotification: MessagePad.ArrivalNotification?) {
M_LISTENERS.forEach {
val tag = it.key
val listener = it.value
listener.onAutopilotArriveAtStation(arrivalNotification)
}
@@ -134,7 +167,6 @@ object CallerAutoPilotStatusListenerManager : CallerBase<IMoGoAutopilotStatusLis
@Synchronized
fun invokeAutopilotSNRequest() {
M_LISTENERS.forEach {
val tag = it.key
val listener = it.value
listener.onAutopilotSNRequest()
}
@@ -180,7 +212,7 @@ object CallerAutoPilotStatusListenerManager : CallerBase<IMoGoAutopilotStatusLis
*/
fun updateAutopilotControlParameters(autopilotControlParameters: AutopilotControlParameters? = null) {
mAutopilotStatusInfo.autopilotControlParameters = autopilotControlParameters
lineId = autopilotControlParameters?.autoPilotLine?.lineId?:0
lineId = autopilotControlParameters?.autoPilotLine?.lineId ?: 0
invokeAutoPilotStatus(mAutopilotStatusInfo)
}
}

View File

@@ -0,0 +1,17 @@
package com.mogo.eagle.core.function.call.autopilot
import com.mogo.eagle.core.function.api.autopilot.*
import com.mogo.eagle.core.function.call.base.*
import com.zhjt.mogo.adas.data.bean.*
import mogo.telematics.pad.*
object CallerAutopilotGetParamResponseDispatcher: CallerBase<IMoGoGetParamResponseListener>() {
fun dispatchResponse(header: MessagePad.Header, getParamResp: MessagePad.SetParamReq, adasParam: AdasParam) {
M_LISTENERS.forEach {
val listener = it.value
listener.onGetParamResp(header, getParamResp, adasParam)
}
}
}

View File

@@ -37,18 +37,6 @@ object CallerAutopilotIdentifyListenerManager : CallerBase<IMoGoAutopilotIdentif
}
}
/**
* 报警信息 回调
*/
@Synchronized
fun invokeAutopilotWarnMessage(warn: MessagePad.Warn?) {
M_LISTENERS.forEach {
val tag = it.key
val listener = it.value
listener.onAutopilotWarnMessage(warn)
}
}
/**
* 感知红绿灯
*/

View File

@@ -1,6 +1,5 @@
package com.mogo.eagle.core.function.call.autopilot
import com.mogo.commons.debug.DebugConfig
import com.mogo.eagle.core.data.enums.DataSourceType
import com.mogo.eagle.core.data.map.MogoLocation
import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLocationGCJ02Listener
@@ -109,11 +108,6 @@ object CallerChassisLocationGCJ02ListenerManager : CallerBase<IMoGoChassisLocati
M_LISTENERS_HZ_LAST_SEND_TIME[tag] = TimeUtils.getNowMills()
val listener = it.value
listener.onChassisLocationGCJ02(mogoLocation)
// FileUtils.writeToFile(
// "/sdcard/Download/",
// "location_gcj02.txt",
// "${mogoLocation.longitude},${mogoLocation.latitude},${sourceType}\n"
// )
}

View File

@@ -94,11 +94,6 @@ object CallerChassisLocationWGS84ListenerManager : CallerBase<IMoGoChassisLocati
M_LISTENERS_HZ_LAST_SEND_TIME[tag] = TimeUtils.getNowMills()
val listener = it.value
listener.onChassisLocationWGS84(mogoLocation)
// FileUtils.writeToFile(
// "/sdcard/Download/",
// "location_wgs84.txt",
// "${mogoLocation.longitude},${mogoLocation.latitude},${sourceType}\n"
// )
}

View File

@@ -2,20 +2,31 @@ package com.mogo.eagle.core.function.call.autopilot
import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisSteeringStateListener
import com.mogo.eagle.core.function.call.base.CallerBase
import kotlin.properties.Delegates
/**
* 车辆方向盘转向角 回调监听
*/
object CallerChassisSteeringStateListenerManager : CallerBase<IMoGoChassisSteeringStateListener>() {
private var steering: Float? by Delegates.observable(0.0f) { _, oldValue, newValue ->
if (newValue == null) {
return@observable
}
if (oldValue == newValue) {
return@observable
}
M_LISTENERS.forEach {
val listener = it.value
listener.onAutopilotSteeringData(newValue)
}
}
/**
* 车辆方向盘转向角回调
* @param steering 方向盘转向角
*/
fun invokeAutopilotSteeringData(steering: Float){
M_LISTENERS.forEach{
val listener = it.value
listener.onAutopilotSteeringData(steering)
}
fun invokeAutopilotSteeringData(steering: Float) {
this.steering = steering
}
}

View File

@@ -19,6 +19,13 @@ object CallerPlanningRottingListenerManager : CallerBase<IMoGoPlanningRottingLis
}
}
/**
* 获取global path cache
*/
fun getGlobalPathCache(): MessagePad.GlobalPathResp? {
return globalPathResp
}
/**
* 路径规划 回调
* @param globalPathResp 自动驾驶网约车回调数据
@@ -33,4 +40,5 @@ object CallerPlanningRottingListenerManager : CallerBase<IMoGoPlanningRottingLis
}
}
}

View File

@@ -6,6 +6,15 @@ import com.mogo.eagle.core.function.call.base.CallerBase
object CallerDevaToolsListenerManager : CallerBase<IMoGoDevaToolsListener>() {
private var gpsStatus: Boolean = true
private var tracingStatus: Boolean = true
override fun doSomeAfterAddListener(tag: String, listener: IMoGoDevaToolsListener) {
super.doSomeAfterAddListener(tag, listener)
listener.gpsStatus(gpsStatus)
listener.tracingStatus(tracingStatus)
}
fun invokeDevaToolsLogCatchStart() {
M_LISTENERS.forEach {
val listener = it.value
@@ -62,4 +71,19 @@ object CallerDevaToolsListenerManager : CallerBase<IMoGoDevaToolsListener>() {
}
}
fun invokeGpsStatus(status: Boolean) {
gpsStatus = status
M_LISTENERS.forEach {
val listener = it.value
listener.gpsStatus(status)
}
}
fun invokeTracingStatus(status: Boolean) {
tracingStatus = status
M_LISTENERS.forEach {
val listener = it.value
listener.tracingStatus(status)
}
}
}

View File

@@ -15,8 +15,11 @@ import com.mogo.eagle.core.data.msgbox.MsgBoxBean
import com.mogo.eagle.core.function.api.devatools.IDevaToolsProvider
import com.mogo.eagle.core.function.api.devatools.apm.*
import com.mogo.eagle.core.function.api.devatools.download.*
import com.mogo.eagle.core.function.api.devatools.logcat.*
import com.mogo.eagle.core.function.api.devatools.mofang.*
import com.mogo.eagle.core.function.api.upgrade.*
import com.mogo.eagle.core.function.api.devatools.strict.*
import com.mogo.eagle.core.function.api.lookaround.*
import com.mogo.eagle.core.function.call.base.CallerBase
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
@@ -255,4 +258,10 @@ object CallerDevaToolsManager {
fun upgradeProvider(): IMoGoUpgradeProvider? = devaToolsProviderApi?.upgradeProvider()
fun strict(): IStrictModeProvider? = devaToolsProviderApi?.strict()
fun lookAroundProvider(): IMoGoLookAroundProvider? = devaToolsProviderApi?.lookAroundDataProvider()
fun mofang(): IMoGoMoFangProvider? = devaToolsProviderApi?.mofang()
fun logcat(): IMoGoLogRecordProvider? = devaToolsProviderApi?.logRecord()
}

View File

@@ -198,4 +198,29 @@ object CallerHmiManager {
fun updateStatusBarDownloadView(insert: Boolean, tag: String, progress: Int) {
hmiProviderApi?.updateStatusBarDownloadView(insert, tag, progress)
}
/**
* 展示M1车型的360环视控件
*/
fun showM1360LookAround() {
hmiProviderApi?.show360LookAround()
}
/**
* 隐藏M1车型的360环视控件
*/
fun hidM1360LookAround() {
hmiProviderApi?.hide360LookAround()
}
/**
* 返回M1车型的360环视弹窗是否正在展示
*/
fun isM1360LookAroundShowing(): Boolean {
return hmiProviderApi?.is360LookAroundShowing() ?: false
}
fun showStatusSummaryDialog() {
hmiProviderApi?.showStatusSummaryDialog()
}
}

View File

@@ -2,6 +2,7 @@ package com.mogo.eagle.core.function.call.hmi
import android.view.ViewGroup
import com.mogo.eagle.core.function.api.hmi.view.IViewControlListener
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotActionsListenerManager
import com.mogo.eagle.core.function.call.base.CallerBase
/**
@@ -23,13 +24,20 @@ object CallerHmiViewControlListenerManager : CallerBase<IViewControlListener>()
M_LISTENERS[tag]?.setStatusBarDarkOrLight(light)
}
fun invokeFuncMode(funcTag:String, boolean: Boolean){
M_LISTENERS.forEach {
val listener = it.value
listener.updateFuncMode(funcTag, boolean)
}
}
fun updateStatusBarRightView(
tag: String,
insert: Boolean,
viewTag: String,
viewGroup: ViewGroup
) {
M_LISTENERS[tag]?.updateStatusBarRightView(insert, tag, viewGroup)
M_LISTENERS[tag]?.updateStatusBarRightView(insert, viewTag, viewGroup)
}
fun updateStatusBarLeftView(
@@ -38,7 +46,7 @@ object CallerHmiViewControlListenerManager : CallerBase<IViewControlListener>()
viewTag: String,
viewGroup: ViewGroup
) {
M_LISTENERS[tag]?.updateStatusBarLeftView(insert, tag, viewGroup)
M_LISTENERS[tag]?.updateStatusBarLeftView(insert, viewTag, viewGroup)
}
fun updateStatusBarDownloadView(tag: String, insert: Boolean, viewTag: String, progress: Int) {

View File

@@ -10,8 +10,8 @@ object CallerMapIdentifyManager {
get() = ARouter.getInstance().build( MogoServicePaths.PATH_MAP_BIZ)
.navigation() as IMogoRoma
fun romaTrigger(romaStatus:Boolean, requestSuccess:((Boolean) -> Unit)? = null){
romaApi.trigger(romaStatus, requestSuccess)
fun romaTrigger(romaStatus:Boolean){
romaApi.trigger(romaStatus)
}
}

View File

@@ -6,11 +6,22 @@ import com.mogo.eagle.core.function.call.base.CallerBase
object CallerMapRomaListener : CallerBase<IMoGoRomaListener>() {
private var roma = false
private var romaStatus = -1
private var romaMsg: String = ""
override fun doSomeAfterAddListener(tag: String, listener: IMoGoRomaListener) {
listener.romaStatus(roma)
}
fun invokeMapRomaStatus(status: Int, msg: String) {
romaStatus = status
romaMsg = msg
M_LISTENERS.forEach {
val listener = it.value
listener.mapRomaStatus(romaStatus, romaMsg)
}
}
fun invokeMapRoma(romaStatus: Boolean) {
roma = romaStatus
M_LISTENERS.forEach {

View File

@@ -1,21 +0,0 @@
package com.mogo.eagle.core.function.call.mofang
import com.mogo.eagle.core.function.api.devatools.mofang.IMoGoMoFangListener
import com.mogo.eagle.core.function.call.base.CallerBase
/**
* 魔方按键的处理
*/
object CallerMofangListenerManager : CallerBase<IMoGoMoFangListener>() {
fun invokeMofangHandle(keyCode: Int, action: Int): Boolean {
var isConsume = false
M_LISTENERS.forEach {
val tag = it.key
val listener = it.value
if (listener.onMofangHandle(keyCode, action))
isConsume = true
}
return isConsume
}
}

View File

@@ -1,11 +1,12 @@
package com.mogo.eagle.core.function.call.msgbox
import android.content.Context
import android.util.Log
import com.mogo.eagle.core.data.constants.MogoServicePaths
import com.mogo.eagle.core.data.deva.chain.ChainConstant
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
import com.mogo.eagle.core.function.api.datacenter.msgbox.IMsgBoxProvider
import com.mogo.eagle.core.function.call.base.CallerBase
import com.zhjt.service.chain.ChainLog
object CallerMsgBoxManager {
@@ -24,6 +25,12 @@ object CallerMsgBoxManager {
/**
* 存储数据到消息盒子
*/
@ChainLog(
linkChainLog = ChainConstant.CHAIN_TYPE_V2X,
linkCode = ChainConstant.CHAIN_SOURCE_CLOUD,
nodeAliasCode = ChainConstant.CHAIN_CODE_MSG_BOX,
paramIndexes = [0]
)
fun saveMsgBox(bean: MsgBoxBean) {
providerApi?.saveMsg(bean)
}

View File

@@ -0,0 +1,30 @@
package com.mogo.eagle.core.function.call.telematic
import android.util.Log
import com.mogo.eagle.core.function.api.telematic.IConnectStatusListener
import com.mogo.eagle.core.function.api.telematic.IReceivedMsgListener
import com.mogo.eagle.core.function.call.base.CallerBase
object CallerTelematicStatusListenerManager: CallerBase<IConnectStatusListener>() {
private const val TAG = "CallerTelematicStatusListenerManager"
private var isServerStarted = false
override fun doSomeAfterAddListener(tag: String, listener: IConnectStatusListener) {
super.doSomeAfterAddListener(tag, listener)
listener.onServerStatusChanged(isServerStarted)
}
fun invokeServerStatusChanged(isStarted: Boolean) {
isServerStarted = isStarted
M_LISTENERS.forEach {
val listener = it.value
try {
listener.onServerStatusChanged(isStarted)
} catch (e: Exception) {
Log.e(TAG, "转发出现异常:${e.message}")
}
}
}
}