自定义适配器接入说明
ToBid做为聚合SDK支持开发者自定义广告网络。开发者需要按照下方文档实现各自定义网络广告类型。具体可参考Demo中custom模块代码。
1. 核心流程实现
- 定义Adapter类名,包括配置Adapter以及各广告类型对应Adapter,并遵循相关协议;
- 在ToBid开发者平台配置相关信息,详情参见平台部分文档;
- 实现协议方法完成初始化(含隐私合规)、广告加载、展示方法及回调,详见下方说明;
2. 常见问题
- 自定义Adapter需要按照示例中相应方法含义调用,否则会影响收益。
- 及时更新协议版本号为ToBid支持的最新版本,否则可能无法使用。
- 自定义Adapter广告load之前需要确保开发者实现了WMCustomAdapterProxy协议并初始化network成功,network版本号不能为空。
- 自定义Adapter广告load成功或者失败只能调用一次。
- 所有调用自定义adapter的方法均在主线程,请勿进行耗时操作。
- 自定义Adapter支持广告频次控制、广告间隔控制、AB测试。
- 自定义Adapter不支持show时预加载、Service bidding、多阶底价。支持Client bidding。
- 自定义Adapter广告对象的show、click等回调需要在load广告回调之后。
- ToBid已经处理了Banner的轮播,自定义Banner需要禁用轮播。
3. 初始化
开发者需要继承WMCustomAdapterProxy并实现下列方法来完成自定义网络的初始化操作。
| 方法名 | 说明 |
|---|---|
| initializeADN(Context context, Map<String, Object> serverExtra) | 开发者需要在此方法中实现adn的初始化操作。 参数说明: context:上下文对象。 serverExtra:后台填写的自定义参数。 |
| String getNetworkSdkVersion() | 获取ADN渠道SDK的版本号。 |
| int baseOnToBidCustomAdapterVersion() | 基于ToBid_Sdk的自定义适配器接口的版本号。 当ToBid_Sdk的自定义适配器接口变更或者升级时该版本号增加、ToBid_Sdk会验证。 媒体开发者需要及时变更改版本号常量并注意接口变化。 |
| notifyPrivacyStatusChange() | initializeADN 后首次调用一次。 当ToBid隐私状态改变时触发。 |
通知ToBid初始化结果。
| 方法名 | 说明 |
|---|---|
| callInitSuccess() | 通知sdk初始化成功,初始化成功需要通知sdk,不然会导致广告加载不出来 |
| callInitFail(int code, String message) | 通知sdk初始化失败,参数code :失败错误码,如果自定义广告网络没有code,可以使用tobid的WindMillError.ERROR_AD_ADAPTER_LOAD.getErrorCode(),message:错误信息 |
代码示例如下:
public class PangleCustomerProxy extends WMCustomAdapterProxy {
@Override
public void initializeADN(Context context, Map<String, Object> serverExtra) {
}
@Override
public String getNetworkSdkVersion() {
return "1.0";
}
@Override
public int baseOnToBidCustomAdapterVersion() {
return WMConstants.TO_BID_CUSTOM_ADAPTER_VERSION_1;
}
@Override
public void notifyPrivacyStatusChange() {
}
}4. 广告类型
自定义适配器提供开屏、插屏、激励、Banner、原生等5种广告类型接入。
4.1 开屏广告
开发者需要继承WMCustomSplashAdapter并实现下列方法来完成自定义网络开屏广告的加载与展示。
| 方法名 | 说明 |
|---|---|
| 4.6.60(及以上)版本已删除。将 Activity 参数改为了 Context。 | |
| loadAd(Context context, ViewGroup viewGroup, Map<String, Object> localExtra, Map<String, Object> serverExtra) | 开发者需要在此方法中实现开屏广告的请求操作。 参数说明: context:上下文对象。 viewGroup:开屏广告容器。 localExtra:构建开屏广告对象时开发者传入的本地参数。 serverExtra:后台填写的自定义参数。 |
| showAd(Activity activity, ViewGroup viewGroup, Map<String, Object> serverExtra) | 开发者需要在此方法中实现开屏广告的展示操作。 参数说明: activity:上下文对象。 viewGroup:开屏广告容器。 serverExtra:后台填写的自定义参数。 |
| boolean isReady() | 广告是否加载好。 |
| notifyBiddingResult(boolean isWin, String price, Map<String, Object> referBidInfo) | 通知bidding结果、仅客户端Bidding广告类型使用、可选实现。 参数说明: isWin:胜出还是失败。 price:胜出价格。 referBidInfo:竞价回传参考信息。 |
| IWMSplashEyeAd getSplashEyeAd() | 返回开屏点睛广告对象、仅开屏点睛广告需要实现。(可选) |
| destroyAd() | 销毁广告对象。 |
通知ToBid开屏广告加载状态。
| 方法名 | 说明 |
|---|---|
| callLoadSuccess() | 通知ToBid广告加载成功。 |
| callLoadBiddingSuccess(BidPrice price) | 通知ToBid广告Bidding成功、仅限客户端biding广告使用(可选、在callLoadSuccess之前调用)。 参数说明: price:价格信息对象、可传入价格和货币单位。 |
| callLoadFail(WMAdapterError adapterError) | 通知ToBid广告加载失败。 参数说明: adapterError:报错信息对象、可传入错误码和错误信息。 |
| callSplashAdShow() | 通知ToBid广告曝光。 |
| callSplashAdClick() | 通知ToBid广告点击。 |
| callSplashAdClosed() | 通知ToBid广告关闭。 |
| callSplashAdSkipped() | 通知ToBid广告跳过。 |
| callSplashAdShowError(WMAdapterError adapterError) | 通知ToBid广告展示失败。 参数说明: adapterError:报错信息对象、可传入错误码和错误信息。 |
代码示例如下:
public class PangleCustomerSplash extends WMCustomSplashAdapter {
@Override
public void loadAd(Context context, ViewGroup viewGroup, Map<String, Object> localExtra, Map<String, Object> serverExtra) {
}
@Override
public void showAd(Activity activity, ViewGroup viewGroup, Map<String, Object> serverExtra) {
}
@Override
public boolean isReady() {
return false;
}
@Override
public void destroyAd() {
}
@Override
public void notifyBiddingResult(boolean isWin, String price, Map<String, Object> referBidInfo) {
}
}4.2 Banner广告
开发者需要继承WMCustomBannerAdapter并实现下列方法来完成自定义网络Banner广告的加载与展示。
| 方法名 | 说明 |
|---|---|
| 4.6.60(及以上)版本已删除。将 Activity 参数改为了 Context。 | |
| loadAd(Context context, Map<String, Object> localExtra, Map<String, Object> serverExtra) | 开发者需要在此方法中实现Banner广告的请求操作。 参数说明: context:上下文对象。 localExtra:构建Banner广告对象时开发者传入的本地参数。 serverExtra:后台填写的自定义参数。 |
| View getBannerView() | 开发者需要在此方法中返回Banner广告view。 |
| boolean isReady() | 广告是否加载好。 |
| notifyBiddingResult(boolean isWin, String price, Map<String, Object> referBidInfo) | 通知bidding结果、仅客户端Bidding广告类型使用、可选实现。 参数说明: isWin:胜出还是失败。 price:胜出价格。 referBidInfo:竞价回传参考信息。 |
| destroyAd() | 销毁广告对象。 |
通知ToBid Banner广告的加载状态。
| 方法名 | 说明 |
|---|---|
| callLoadSuccess() | 通知ToBid广告加载成功。 |
| callLoadBiddingSuccess(BidPrice price) | 通知ToBid广告Bidding成功、仅限客户端biding广告使用(可选、在callLoadSuccess之前调用)。 参数说明: price:价格信息对象、可传入价格和货币单位。 |
| callLoadFail(WMAdapterError adapterError) | 通知ToBid广告加载失败。 参数说明: adapterError:报错信息对象、可传入错误码和错误信息。 |
| callBannerAdShow() | 通知ToBid广告曝光。 |
| callBannerAdClick() | 通知ToBid广告点击。 |
| callBannerAdClosed() | 通知ToBid广告关闭。 |
| callBannerAdShowError(WMAdapterError adapterError) | 通知ToBid广告展示失败。 参数说明: adapterError:报错信息对象、可传入错误码和错误信息。 |
代码示例如下:
public class PangleCustomerBanner extends WMCustomBannerAdapter {
@Override
public void loadAd(Context context, Map<String, Object> localExtra, Map<String, Object> serverExtra) {
}
@Override
public View getBannerView() {
return null;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void destroyAd() {
}
@Override
public void notifyBiddingResult(boolean isWin, String price, Map<String, Object> referBidInfo) {
}
}4.3 激励视频广告
开发者需要继承WMCustomRewardAdapter并实现下列方法来完成自定义网络激励视频广告的加载与展示。
| 方法名 | 说明 |
|---|---|
| 4.6.60(及以上)版本已删除。将 Activity 参数改为了 Context。 | |
| loadAd(Context context, Map<String, Object> localExtra, Map<String, Object> serverExtra) | 开发者需要在此方法中实现激励视频广告的请求操作。 参数说明: context:上下文对象。 localExtra:构建激励视频广告对象时开发者传入的本地参数。 serverExtra:后台填写的自定义参数。 |
| showAd(Activity activity, HashMap<String, String> localExtra, Map<String, Object> serverExtra) | 开发者需要在此方法中实现激励视频广告的展示操作。 参数说明: activity:上下文对象。 localExtra:构建激励视频广告对象时开发者传入的本地参数。 serverExtra:后台填写的自定义参数。 |
| boolean isReady() | 广告是否加载好。 |
| notifyBiddingResult(boolean isWin, String price, Map<String, Object> referBidInfo) | 通知bidding结果、仅客户端Bidding广告类型使用、可选实现。 参数说明: isWin:胜出还是失败。 price:胜出价格。 referBidInfo:竞价回传参考信息。 |
| destroyAd() | 销毁广告对象。 |
通知ToBid激励视频广告加载状态。
| 方法名 | 说明 |
|---|---|
| callLoadSuccess() | 通知ToBid广告加载成功。 |
| callLoadBiddingSuccess(BidPrice price) | 通知ToBid广告Bidding成功、仅限客户端biding广告使用(可选、在callLoadSuccess之前调用)。 参数说明: price:价格信息对象、可传入价格和货币单位。 |
| callLoadFail(WMAdapterError adapterError) | 通知ToBid广告加载失败。 参数说明: adapterError:报错信息对象、可传入错误码和错误信息。 |
| callVideoAdShow() | 通知ToBid广告曝光。 |
| callVideoAdClick() | 通知ToBid广告点击。 |
| callVideoAdClosed() | 通知ToBid广告关闭。 |
| callVideoAdPlayComplete() | 通知ToBid广告播放完成。 |
| callVideoAdPlayError(WMAdapterError adapterError) | 通知ToBid广告播放失败。 参数说明: adapterError:报错信息对象、可传入错误码和错误信息。 |
| callVideoAdReward(boolean isReward) | 通知ToBid广告奖励。 |
| callVideoAdSkipped() | 通知ToBid广告跳过。 |
代码示例如下:
public class PangleCustomerReward extends WMCustomRewardAdapter {
@Override
public void loadAd(Context context, Map<String, Object> localExtra, Map<String, Object> serverExtra) {
}
@Override
public void showAd(Activity activity, HashMap<String, String> localExtra, Map<String, Object> serverExtra) {
}
@Override
public boolean isReady() {
return false;
}
@Override
public void destroyAd() {
}
@Override
public void notifyBiddingResult(boolean isWin, String price, Map<String, Object> referBidInfo) {
}
}4.4 插屏广告
开发者需要继承WMCustomInterstitialAdapter并实现下列方法来完成自定义网络插屏广告的加载与展示。
| 方法名 | 说明 |
|---|---|
| 4.6.60(及以上)版本已删除。将 Activity 参数改为了 Context。 | |
| loadAd(Context context, Map<String, Object> localExtra, Map<String, Object> serverExtra) | 开发者需要在此方法中实现插屏广告的请求操作。 参数说明: context:上下文对象。 localExtra:构建插屏广告对象时开发者传入的本地参数。 serverExtra:后台填写的自定义参数。 |
| showAd(Activity activity, HashMap<String, String> localExtra, Map<String, Object> serverExtra) | 开发者需要在此方法中实现插屏广告的展示操作。 参数说明: activity:上下文对象。 localExtra:构建插屏广告对象时开发者传入的本地参数。 serverExtra:后台填写的自定义参数。 |
| boolean isReady() | 广告是否加载好。 |
| notifyBiddingResult(boolean isWin, String price, Map<String, Object> referBidInfo) | 通知bidding结果、仅客户端Bidding广告类型使用、可选实现。 参数说明: isWin:胜出还是失败。 price:胜出价格。 referBidInfo:竞价回传参考信息。 |
| destroyAd() | 销毁广告对象。 |
通知ToBid开屏广告加载状态。
| 方法名 | 说明 |
|---|---|
| callLoadSuccess() | 通知ToBid广告加载成功。 |
| callLoadBiddingSuccess(BidPrice price) | 通知ToBid广告Bidding成功、仅限客户端biding广告使用(可选、在callLoadSuccess之前调用)。 参数说明: price:价格信息对象、可传入价格和货币单位。 |
| callLoadFail(WMAdapterError adapterError) | 通知ToBid广告加载失败。 参数说明: adapterError:报错信息对象、可传入错误码和错误信息。 |
| callVideoAdShow() | 通知ToBid广告曝光。 |
| callVideoAdClick() | 通知ToBid广告点击。 |
| callVideoAdClosed() | 通知ToBid广告关闭。 |
| callVideoAdPlayComplete() | 通知ToBid广告播放完成。 |
| callVideoAdPlayError(WMAdapterError adapterError) | 通知ToBid广告播放失败。 参数说明: adapterError:报错信息对象、可传入错误码和错误信息。 |
| callVideoAdSkipped() | 通知ToBid广告跳过。 |
代码示例如下:
public class PangleCustomerInterstitial extends WMCustomInterstitialAdapter {
@Override
public void loadAd(Context context, Map<String, Object> localExtra, Map<String, Object> serverExtra) {
}
@Override
public void showAd(Activity activity, HashMap<String, String> localExtra, Map<String, Object> serverExtra) {
}
@Override
public boolean isReady() {
return false;
}
@Override
public void destroyAd() {
}
@Override
public void notifyBiddingResult(boolean isWin, String price, Map<String, Object> referBidInfo) {
}
}4.5 原生广告
开发者需要继承WMCustomNativeAdapter并实现下列方法来完成自定义网络原生广告的加载与展示。
| 方法名 | 说明 |
|---|---|
| loadAd(Context context, Map<String, Object> localExtra, Map<String, Object> serverExtra) | 开发者需要在此方法中实现原生广告的请求操作。 参数说明: context:上下文对象。 localExtra:构建原生广告对象时开发者传入的本地参数。 serverExtra:后台填写的自定义参数。 |
| List<WMNativeAdData> getNativeAdDataList() | 开发者需要在此方法中返回请求到的原生广告单元包装对象。 |
| boolean isReady() | 广告是否加载好。 |
| notifyBiddingResult(boolean isWin, String price, Map<String, Object> referBidInfo) | 通知bidding结果、仅客户端Bidding广告类型使用、可选实现。 参数说明: isWin:胜出还是失败。 price:胜出价格。 referBidInfo:竞价回传参考信息。 |
| destroyAd() | 销毁广告对象。 |
通知ToBid原生广告加载状态。
| 方法名 | 说明 |
|---|---|
| callLoadSuccess(List<WMNativeAdData> list) | 通知ToBid广告加载成功。 参数说明: list:请求到的原生广告单元包装对象。 |
| callLoadBiddingSuccess(BidPrice price) | 通知ToBid广告Bidding成功、仅限客户端biding广告使用(可选、在callLoadSuccess之前调用)。 参数说明: price:价格信息对象、可传入价格和货币单位。 |
| callLoadFail(WMAdapterError adapterError) | 通知ToBid广告加载失败。 参数说明: adapterError:报错信息对象、可传入错误码和错误信息。 |
| callNativeAdShow(WMNativeAdData adData) | 通知ToBid广告曝光。 参数说明: adData:曝光的原生广告单元包装对象。 |
| callNativeAdClick(WMNativeAdData adData) | 通知ToBid广告点击。 参数说明: adData:点击的原生广告单元包装对象。 |
| callNativeAdLangPageShow(WMNativeAdData adData) | 通知ToBid原生广告点击后的landpage页展示(可选)。 参数说明: adData:展示的原生广告单元包装对象。 |
| callNativeAdShowError(WMAdapterError adapterError) | 通知ToBid广告展示失败。 参数说明: adapterError:报错信息对象、可传入错误码和错误信息。 |
代码示例如下:
public class PangleCustomerNative extends WMCustomNativeAdapter {
@Override
public void loadAd(Context context, Map<String, Object> localExtra, Map<String, Object> serverExtra) {
}
@Override
public boolean isReady() {
return false;
}
@Override
public List<WMNativeAdData> getNativeAdDataList() {
return null;
}
@Override
public void destroyAd() {
}
@Override
public void notifyBiddingResult(boolean isWin, String price, Map<String, Object> referBidInfo) {
}
}WMNativeAdData接口对象说明。
| 方法名 | 说明 |
|---|---|
| String getCTAText() | 获取点击按钮CTA文本内容。(仅自渲染需实现) |
| String getTitle() | 获取广告Tittle。(仅自渲染需实现) |
| String getDesc() | 获取广告描述。(仅自渲染需实现) |
| Bitmap getAdLogo() | 获取广告Logo。(仅自渲染需实现) |
| String getIconUrl() | 获取广告icon地址。(仅自渲染需实现) |
| View getAdChoice() | 获取广告隐私view(可返回null)。(仅自渲染需实现) |
| int getAdPatternType() | 获取广告样式。(仅自渲染需实现) 返回值: WMNativeAdDataType.NATIVE_VIDEO_AD WMNativeAdDataType.NATIVE_GROUP_IMAGE_AD WMNativeAdDataType.NATIVE_BIG_IMAGE_AD WMNativeAdDataType.NATIVE_SMALL_IMAGE_AD WMNativeAdDataType.NATIVE_UNKNOWN |
| connectAdToView(Activity activity, WMNativeAdContainer adContainer, WMNativeAdRender adRender) | 将容器和view链接起来、适配其他家sdk的自渲染广告。(仅自渲染需实现) 参数说明: activity:上下文对象。 adContainer:原生自渲染广告容器。 adRender:原生广告渲染对象。 |
| bindViewForInteraction(Context context, View view, List<View> clickableViews, List<View> creativeViewList, View disLikeView) | 绑定原生自渲染广告交互。(仅自渲染需实现) 参数说明: context:上下文对象。 view:自渲染的根View。 clickableViews:可点击的View的列表。 creativeViewList:用于下载或者拨打电话的View。 disLikeView:dislike按钮。 |
| bindImageViews(Context context, List<ImageView> imageViews, int defaultImageRes) | 渲染原生自渲染广告图片。(仅自渲染需实现) 参数说明: context:上下文对象。 imageViews:展示图片的View集合。 defaultImageRes:渲染图片失败时默认的图片。 |
| bindMediaView(Context context, ViewGroup mediaLayout) | 绑定原生自渲染视频。(仅自渲染需实现) 参数说明: context:上下文对象。 mediaLayout:装video的容器。 |
| startVideo() | 控制视频开始播放。(仅自渲染需实现) |
| pauseVideo() | 控制视频暂停。(仅自渲染需实现) |
| resumeVideo() | 恢复视频播放。(仅自渲染需实现) |
| void stopVideo() | 停止视频播放。(仅自渲染需实现) |
| View getExpressAdView() | 返回模版广告view。(仅模版需实现) |
| render() | 渲染模版广告。(仅模版需实现) |
| boolean isExpressAd() | 是自渲染还是模版渲染广告单元。(模版和自渲染都需实现) |
| int getInteractionType() | 获取广告交互类型。(模版和自渲染都需实现) 返回值: WMConstants.INTERACTION_TYPE_DOWNLOAD WMConstants.INTERACTION_TYPE_BROWSER WMConstants.INTERACTION_TYPE_UNKNOWN |
| int getNetworkId() | 获取渠道Id。(模版和自渲染都需实现) |
| setInteractionListener(NativeAdInteractionListener adInteractionListener) | 设置广告交互监听的接口。(模版和自渲染都需实现) |
| setMediaListener(NativeADMediaListener nativeADMediaListener) | 设置视频状态监听接口。(模版和自渲染都需实现) |
| setDislikeInteractionCallback(Activity activity, DislikeInteractionCallback dislikeInteractionCallback) | 设置Dislike交互监听。(模版和自渲染都需实现) 参数说明: activity:当前activity对象。 dislikeInteractionCallback:dislike交互监听对象。 |
| setDownloadListener(AppDownloadListener appDownloadListener) | 设置交互类型为下载类广告的下载状态监听。(模版和自渲染都需实现) 参数说明: appDownloadListener:下载状态监听接口。 |
| destroy() | 销毁广告单元对象。(模版和自渲染都需实现) |
5. 客户端Bidding
5.1 介绍
使自定义ADN的广告加载提供实时价格反馈渠道,参与到ToBid的竞价逻辑中。在一定程度上实现开发者收益最大化。
5.2 方法说明
ToBid支持自定义网络客户端Bidding功能、在各广告类型CustomAdapter中使用。具体可参考Demo中下方接口的使用。
| 方法名 | 说明 |
|---|---|
| callLoadBiddingSuccess(BidPrice price) | 通知ToBid广告Bidding成功、仅限客户端biding广告使用(可选、在callLoadSuccess之前调用)。 参数说明: price:价格信息对象、可传入价格和货币单位。 |
| int getBiddingType() | 该方法返回Bidding广告类型。 类型说明: WMConstants.AD_TYPE_NORMAL:普通广告。 WMConstants.AD_TYPE_SERVER_BIDING:服务端Bidding(s2s)。 WMConstants.AD_TYPE_CLIENT_BIDING:客户端Bidding(c2s)。 |
| notifyBiddingResult(boolean isWin, String price, Map<String,Object> referBidInfo) | ToBidSdk会通知开发者bidding结果、仅客户端Bidding广告类型使用、可选实现。 参数说明: isWin:胜出还是失败。 price:胜出价格。 referBidInfo: 出价方的参考信息。 |
5.2.1 referBidInfo 字段定义说明
| 字段名称 | 描述 | 获取最高定价字段名 | 获取最高定价字段默认值 |
|---|---|---|---|
winner_ecpm | 代表竞胜方ecpm | 瀑布流阶段最高价(已ready广告) | - |
winner_channel | 竞胜方渠道 | 瀑布流阶段最高价对应的渠道(已ready广告) | - |
loser_ecpm | - | 竞败方价格 | - |
loser_channel | - | 竞败方渠道 | - |
bidding_ecpm | bidding竞价二价 | HB阶段的最高价格 | - |
bidding_channel | bidding竞价二价格对应渠道 | HB阶段的最高价格对应的渠道 | - |
waterfall_ecpm | 瀑布流阶段HB排序后第一个广告渠道方二价 | - | - |
waterfall_channel | 瀑布流阶段HB排序后第一个广告渠道方 | - | - |
5.3 示例参考
摘自Demo中WMCustomRewardAdapter类实现,如下:
public class PangleCustomerReward extends WMCustomRewardAdapter {
private String TAG = PangleCustomerReward.this.getClass().getSimpleName();
private TTRewardVideoAd ttRewardVideoAd;
/**
* 收到广告缓存成功
*
* @param ttRewardVideoAd
*/
@Override
public void onRewardVideoCached(TTRewardVideoAd ttRewardVideoAd) {
Log.d(TAG, "onRewardVideoCached");
callLoadSuccess();//通知ToBidSdk广告加载成功
}
/**
* 收到广告加载成功
*
* @param ad
*/
@Override
public void onRewardVideoAdLoad(TTRewardVideoAd ad) {
Log.d(TAG, "onRewardVideoAdLoad");
ttRewardVideoAd = ad;
if (getBiddingType() == WMConstants.AD_TYPE_CLIENT_BIDING) {
String eCpm = "0";
Map<String, Object> mediaExtraInfo = ttRewardVideoAd.getMediaExtraInfo();
if (mediaExtraInfo != null) {
Object price = mediaExtraInfo.get("price");
if (price != null) {
eCpm = String.valueOf(price);
}
}
callLoadBiddingSuccess(new BidPrice(eCpm));//通知ToBidSdk广告获取价格成功
}
}
@Override
public void notifyBiddingResult(boolean isWin, String price, Map<String, Object> referBidInfo) {
Log.d(TAG, "notifyBiddingResult " + isWin + ":" + price);
if (ttRewardVideoAd != null) {
if (isWin) {
ttRewardVideoAd.win(Double.parseDouble(price));
} else {
ttRewardVideoAd.loss(Double.parseDouble(price), "102", "");
}
}
}
}