Commit df319c9f authored by wanglei's avatar wanglei

大图广告

parent 227c7d67
......@@ -27,23 +27,26 @@
tools:targetApi="34">
<activity
android:name=".activity.recyclebin.RecycleBinActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
android:exported="true"
android:launchMode="singleTop"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity">
<!-- <intent-filter>-->
<!-- <action android:name="android.intent.action.MAIN" />-->
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- <category android:name="android.intent.category.LAUNCHER" />-->
<!-- </intent-filter>-->
</activity>
<activity
android:name=".activity.SplashActivity"
android:exported="true"
android:launchMode="singleTask"
android:theme="@style/splash.theme">
<!-- <intent-filter>-->
<!-- <action android:name="android.intent.action.MAIN" />-->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<!-- <category android:name="android.intent.category.LAUNCHER" />-->
<!-- </intent-filter>-->
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".activity.screenshot.ScreenShotAnimationActivity"
......
......@@ -6,6 +6,7 @@ import android.content.Intent
import android.os.Bundle
import com.base.filerecoveryrecyclebin.activity.SplashActivity
import com.base.filerecoveryrecyclebin.ads.admob.AdmobOpenUtils
import com.base.filerecoveryrecyclebin.ads.max.AdMaxInit.initAdMax
import com.base.filerecoveryrecyclebin.bean.ConstObject.ifAgreePrivacy
import com.base.filerecoveryrecyclebin.fcm.FCMManager
import com.base.filerecoveryrecyclebin.fcm.RecoveryTimerManager
......@@ -55,8 +56,14 @@ class MyApplication : BaseApplication() {
}
if (ifAgreePrivacy) {
InstallHelps.init()
MobileAds.initialize(this) { initializationStatus ->
if (ConfigHelper.admobTrueMaxFlase) {
MobileAds.initialize(this) { initializationStatus ->
}
} else {
initAdMax()
}
}
initLifeListener()
}
......
package com.base.filerecoveryrecyclebin.ads
package com.base.filerecoveryrecyclebin.ads.admob
import android.app.Activity
import android.os.Bundle
......
......@@ -9,10 +9,9 @@ import com.base.filerecoveryrecyclebin.BuildConfig
import com.base.filerecoveryrecyclebin.R
import com.base.filerecoveryrecyclebin.ads.AdDisplayUtils
import com.base.filerecoveryrecyclebin.ads.AdmobCommonUtils.isMultiClick
import com.base.filerecoveryrecyclebin.ads.AdmobEvent
import com.base.filerecoveryrecyclebin.ads.AdmobEvent.clickAd
import com.base.filerecoveryrecyclebin.ads.AdmobEvent.pullAd
import com.base.filerecoveryrecyclebin.ads.AdmobEvent.showAd
import com.base.filerecoveryrecyclebin.ads.admob.AdmobEvent.clickAd
import com.base.filerecoveryrecyclebin.ads.admob.AdmobEvent.pullAd
import com.base.filerecoveryrecyclebin.ads.admob.AdmobEvent.showAd
import com.base.filerecoveryrecyclebin.help.BaseApplication
import com.base.filerecoveryrecyclebin.help.ConfigHelper
import com.base.filerecoveryrecyclebin.utils.AppPreferences
......
......@@ -6,10 +6,9 @@ import androidx.core.view.isVisible
import com.base.filerecoveryrecyclebin.R
import com.base.filerecoveryrecyclebin.ads.AdDisplayUtils
import com.base.filerecoveryrecyclebin.ads.AdmobCommonUtils.isMultiClick
import com.base.filerecoveryrecyclebin.ads.AdmobEvent
import com.base.filerecoveryrecyclebin.ads.AdmobEvent.clickAd
import com.base.filerecoveryrecyclebin.ads.AdmobEvent.pullAd
import com.base.filerecoveryrecyclebin.ads.AdmobEvent.showAd
import com.base.filerecoveryrecyclebin.ads.admob.AdmobEvent.clickAd
import com.base.filerecoveryrecyclebin.ads.admob.AdmobEvent.pullAd
import com.base.filerecoveryrecyclebin.ads.admob.AdmobEvent.showAd
import com.base.filerecoveryrecyclebin.help.BaseApplication
import com.base.filerecoveryrecyclebin.help.ConfigHelper
import com.base.filerecoveryrecyclebin.utils.EventUtils
......
......@@ -3,10 +3,9 @@ package com.base.filerecoveryrecyclebin.ads.admob
import android.app.Activity
import com.base.filerecoveryrecyclebin.ads.AdDisplayUtils
import com.base.filerecoveryrecyclebin.ads.AdmobCommonUtils.isMultiClick
import com.base.filerecoveryrecyclebin.ads.AdmobEvent
import com.base.filerecoveryrecyclebin.ads.AdmobEvent.clickAd
import com.base.filerecoveryrecyclebin.ads.AdmobEvent.pullAd
import com.base.filerecoveryrecyclebin.ads.AdmobEvent.showAd
import com.base.filerecoveryrecyclebin.ads.admob.AdmobEvent.clickAd
import com.base.filerecoveryrecyclebin.ads.admob.AdmobEvent.pullAd
import com.base.filerecoveryrecyclebin.ads.admob.AdmobEvent.showAd
import com.base.filerecoveryrecyclebin.help.BaseApplication
import com.base.filerecoveryrecyclebin.help.ConfigHelper
import com.base.filerecoveryrecyclebin.utils.EventUtils
......
package com.base.filerecoveryrecyclebin.ads.max
import android.app.Activity
import com.applovin.mediation.MaxAd
import com.base.filerecoveryrecyclebin.utils.EventUtils
import com.google.android.gms.ads.ResponseInfo
import org.json.JSONObject
object AdMaxEvent {
fun clickAd(nativeAd: MaxAd, adUnit: String) {
// val response = responseInfo?.adapterResponses?.getOrNull(0)
val obj = JSONObject()
// obj.put("source", response?.adSourceName)
obj.put("source", nativeAd.dspName)
obj.put("ad_unit", adUnit)
// val credentials = mapOf(
// "placementid" to response?.credentials?.get("placementid"),
// "appid" to response?.credentials?.get("appid"),
// "pubid" to response?.credentials?.get("pubid")
// )
// obj.put("credentials", credentials.toString())
// obj.put("session_id", responseInfo?.responseId)
// obj.put("networkname", responseInfo?.mediationAdapterClassName)
obj.put("networkname", nativeAd.networkName)
if (adUnit != "nativeAd") {
EventUtils.event("ad_click", ext = obj)
} else {
EventUtils.event("bigimage_ad_click", ext = obj)
}
}
fun showAd(nativeAd: MaxAd, adUnit: String, activity: Activity? = null) {
// val response = responseInfo?.adapterResponses?.getOrNull(0)
val obj = JSONObject()
// obj.put("source", response?.adSourceName)
obj.put("ad_unit", adUnit)
obj.put("networkname", nativeAd.networkName)
// val credentials = mapOf(
// "placementid" to response?.credentials?.get("placementid"),
// "appid" to response?.credentials?.get("appid"),
// "pubid" to response?.credentials?.get("pubid")
// )
// obj.put("credentials", credentials.toString())
// obj.put("session_id", responseInfo?.responseId)
obj.put("from", activity?.javaClass?.simpleName)
if (adUnit != "nativeAd") {
EventUtils.event("ad_show", ext = obj)
} else {
EventUtils.event("bigimage_ad_show", ext = obj)
}
}
}
\ No newline at end of file
......@@ -4,12 +4,15 @@ import android.content.Context
import com.applovin.sdk.AppLovinMediationProvider
import com.applovin.sdk.AppLovinSdk
import com.applovin.sdk.AppLovinSdkInitializationConfiguration
import com.base.filerecoveryrecyclebin.utils.LogEx
import com.google.android.gms.ads.identifier.AdvertisingIdClient
import java.util.Collections
import java.util.concurrent.Executors
object AdMaxInit {
private val TAG = "AdMaxInit"
fun Context.initAdMax() {
// If you want to test your own AppLovin SDK key, change the value here and update the package name in the build.gradle
val YOUR_SDK_KEY = "05TMDQ5tZabpXQ45_UTbmEGNUtVAzSTzT6KmWQc5_CuWdzccS4DCITZoL3yIWUG3bbq60QC_d4WF28tUC4gVTF"
......@@ -29,7 +32,7 @@ object AdMaxInit {
// Initialize the AppLovin SDK
val sdk = AppLovinSdk.getInstance(this)
sdk.initialize(initConfigBuilder.build()) {
LogEx.logDebug(TAG, "max init")
}
executor.shutdown()
......
package com.base.filerecoveryrecyclebin.ads.max
import android.app.Activity
import android.content.Context
import android.view.ViewGroup
import androidx.core.view.isVisible
import com.adjust.sdk.Adjust
import com.adjust.sdk.AdjustAdRevenue
import com.adjust.sdk.AdjustConfig
import com.applovin.mediation.MaxAd
import com.applovin.mediation.MaxError
import com.applovin.mediation.nativeAds.MaxNativeAdListener
import com.applovin.mediation.nativeAds.MaxNativeAdLoader
import com.applovin.mediation.nativeAds.MaxNativeAdView
import com.applovin.mediation.nativeAds.MaxNativeAdViewBinder
import com.base.filerecoveryrecyclebin.R
import com.base.filerecoveryrecyclebin.ads.AdDisplayUtils
import com.base.filerecoveryrecyclebin.ads.AdmobCommonUtils
import com.base.filerecoveryrecyclebin.help.BaseApplication
import com.base.filerecoveryrecyclebin.help.ConfigHelper
import com.base.filerecoveryrecyclebin.utils.EventUtils
import com.base.filerecoveryrecyclebin.utils.LogEx
import org.json.JSONObject
class AdMaxNativeUtils {
// private fun createNativeAdView(): MaxNativeAdView {
// val binder: MaxNativeAdViewBinder = MaxNativeAdViewBinder.Builder(R.layout.layout_max_native_custom)
// .setTitleTextViewId(R.id.tv_max_title)
// .setBodyTextViewId(R.id.tv_max_body)
// .setAdvertiserTextViewId(R.id.advertiser_text_view)
// .setIconImageViewId(R.id.icon_image_view)
// .setMediaContentViewGroupId(R.id.media_view_container)
// .setOptionsContentViewGroupId(R.id.options_view)
// .setStarRatingContentViewGroupId(R.id.star_rating_view)
// .setCallToActionButtonId(R.id.cta_button)
// .build()
// return MaxNativeAdView(binder, this)
// }
object AdMaxNativeUtils {
private val TAG = "AdMaxNativeUtils"
private var nativeAdLoader: MaxNativeAdLoader = MaxNativeAdLoader(ConfigHelper.nativeAdMaxId, BaseApplication.context)
private var nativeAd: MaxAd? = null
private var nativeLoadTime = Long.MAX_VALUE
private var haveSetAdListener: Boolean = false
private var loadingListener: (() -> Unit)? = null
private fun setNativeAdListener() {
if (!haveSetAdListener) {
//加载展示监听
nativeAdLoader.setNativeAdListener(object : MaxNativeAdListener() {
override fun onNativeAdLoaded(nativeAdView: MaxNativeAdView?, ad: MaxAd) {
// Cleanup any pre-existing native ad to prevent memory leaks.
if (nativeAd != null) {
nativeAdLoader.destroy(nativeAd)
}
// Save ad to be rendered later.
nativeAd = ad
nativeLoadTime = System.currentTimeMillis()
loadingListener?.invoke()
}
override fun onNativeAdLoadFailed(p0: String, p1: MaxError) {
super.onNativeAdLoadFailed(p0, p1)
val obj2 = JSONObject()
obj2.put("reason", "no_ad")
obj2.put("ad_unit", "nativeAd")
EventUtils.event("ad_show_error", ext = obj2)
}
override fun onNativeAdClicked(p0: MaxAd) {
super.onNativeAdClicked(p0)
nativeAd?.let { AdMaxEvent.clickAd(it, "nativeAd") }
AdmobCommonUtils.isMultiClick(nativeAd)
}
override fun onNativeAdExpired(p0: MaxAd) {
super.onNativeAdExpired(p0)
}
})
//广告价格监听
nativeAdLoader.setRevenueListener { ad ->
val adjustAdRevenue = AdjustAdRevenue(AdjustConfig.AD_REVENUE_APPLOVIN_MAX)
adjustAdRevenue.setRevenue(ad.revenue, "USD")
adjustAdRevenue.setAdRevenueNetwork(ad.networkName)
adjustAdRevenue.setAdRevenueUnit(ad.adUnitId)
adjustAdRevenue.setAdRevenuePlacement(ad.placement)
Adjust.trackAdRevenue(adjustAdRevenue)
}
haveSetAdListener = true
}
}
private fun createNativeAdView(context: Context): MaxNativeAdView {
val binder: MaxNativeAdViewBinder = MaxNativeAdViewBinder.Builder(R.layout.layout_max_native_custom)
.setTitleTextViewId(R.id.title_text_view)
.setBodyTextViewId(R.id.body_text_view)
.setAdvertiserTextViewId(R.id.advertiser_text_view)
.setIconImageViewId(R.id.icon_image_view)
.setMediaContentViewGroupId(R.id.media_view_container)
.setOptionsContentViewGroupId(R.id.options_view)
.setStarRatingContentViewGroupId(R.id.star_rating_view)
.setCallToActionButtonId(R.id.cta_button)
.build()
return MaxNativeAdView(binder, context)
}
fun showNativeAd(activity: Activity, parent: ViewGroup) {
setNativeAdListener()
val obj = JSONObject()
obj.put("ad_unit", "NativeAd")
EventUtils.event("ad_prepare_show", ext = obj)
if (!AdDisplayUtils.getInstance().shouldShowAd()) {
return
}
loadingListener = {
if (System.currentTimeMillis() - nativeLoadTime <= 1000 * 60 * 60) {
//是否已经加载渲染
if (nativeAd?.nativeAd?.isExpired == true) {
nativeAdLoader.destroy(nativeAd)
nativeAdLoader.loadAd()
} else {
//展示广告
val adView = createNativeAdView(activity)
parent.isVisible = true
nativeAdLoader.render(adView, nativeAd)
parent.addView(adView)
nativeAd?.let { AdMaxEvent.showAd(it, "nativeAd", activity) }
}
}
loadingListener = null
nativeAdLoader.loadAd()
LogEx.logDebug(TAG, "loadingListener finish")
}
if (nativeAd == null) {
nativeAdLoader.loadAd()
val obj2 = JSONObject()
obj2.put("reason", "no_ad")
obj2.put("ad_unit", "nativeAd")
EventUtils.event("ad_show_error", ext = obj2)
} else {
loadingListener?.invoke()
}
}
}
\ No newline at end of file
......@@ -14,12 +14,14 @@ import com.base.filerecoveryrecyclebin.activity.recovery.FileScanResultActivity
import com.base.filerecoveryrecyclebin.activity.repeat.RepeatAnimationActivity
import com.base.filerecoveryrecyclebin.activity.screenshot.ScreenShotAnimationActivity
import com.base.filerecoveryrecyclebin.ads.admob.AdmobNativeUtils
import com.base.filerecoveryrecyclebin.ads.max.AdMaxNativeUtils
import com.base.filerecoveryrecyclebin.bean.ConstObject.SCAN_DOCUMENTS
import com.base.filerecoveryrecyclebin.bean.ConstObject.SCAN_PHOTOS
import com.base.filerecoveryrecyclebin.bean.ConstObject.SCAN_VIDEOS
import com.base.filerecoveryrecyclebin.bean.ConstObject.privacyPinPassword
import com.base.filerecoveryrecyclebin.databinding.FragmentHomeBinding
import com.base.filerecoveryrecyclebin.help.BaseFragment
import com.base.filerecoveryrecyclebin.help.ConfigHelper
class HomeFragment : BaseFragment<FragmentHomeBinding>() {
......@@ -30,7 +32,12 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>() {
override fun setView() {
animatorSet = createHeartbeatAnimation(binding.flScan)
AdmobNativeUtils.showNativeAd(requireActivity(), binding.flAd)
if (ConfigHelper.admobTrueMaxFlase) {
AdmobNativeUtils.showNativeAd(requireActivity(), binding.flAd)
} else {
AdMaxNativeUtils.showNativeAd(requireActivity(), binding.flAd)
}
}
override fun setListener() {
......
......@@ -21,6 +21,7 @@ abstract class BaseActivity<T : ViewBinding> : AppCompatActivity() {
launcher = ActivityLauncher(this)
setContentView(binding.root)
ActivityManagerUtils.getInstance().addActivity(this)
initView()
initListener()
}
......
......@@ -11,13 +11,15 @@ object ConfigHelper {
const val eventUrl = "https://rp.rocioxyn.xyz"
const val apiUrl = "https://api.rocioxyn.xyz"
const val admobTrueMaxFlase = false
// admob广告id
const val interAdmobId = "ca-app-pub-3940256099942544/1033173712"
const val nativeAdmobId = "ca-app-pub-3940256099942544/2247696110"
const val openAdmobId = "/6499/example/app-open"
const val interAdMaxId = "ca-app-pub-3940256099942544/1033173712"
const val nativeAdMaxId = "ca-app-pub-3940256099942544/2247696110"
const val nativeAdMaxId = "YOUR_AD_UNIT_ID"
const val openAdMaxId = "/6499/example/app-open"
//一定展示大图广告
......
<com.google.android.gms.ads.nativead.NativeAdView xmlns:android="http://schemas.android.com/apk/res/android"
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
<LinearLayout
android:maxHeight="300dp"
android:padding="8dp">
<ImageView
android:id="@+id/icon_image_view"
android:layout_width="50dp"
android:layout_height="50dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription"
tools:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:background="@android:color/holo_green_dark"
android:padding="2dp"
android:text="Ad"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:textColor="@android:color/white"
app:layout_constraintBottom_toBottomOf="@+id/title_text_view"
app:layout_constraintStart_toEndOf="@+id/icon_image_view"
app:layout_constraintTop_toTopOf="@+id/title_text_view"
tools:ignore="HardcodedText" />
<FrameLayout
android:id="@+id/options_view"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginBottom="8dp"
android:orientation="horizontal"
app:layout_constraintBottom_toTopOf="@+id/advertiser_text_view"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@+id/title_text_view"
app:layout_constraintTop_toTopOf="@+id/icon_image_view" />
<TextView
android:id="@+id/title_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
app:layout_constraintStart_toEndOf="@+id/text_view"
app:layout_constraintTop_toTopOf="parent"
tools:text="Title" />
<TextView
android:id="@+id/advertiser_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
app:layout_constraintBottom_toBottomOf="@+id/icon_image_view"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/icon_image_view"
app:layout_constraintTop_toBottomOf="@+id/title_text_view"
app:layout_constraintVertical_bias="1.0"
tools:text="Advertiser"
tools:textSize="12sp" />
<FrameLayout
android:id="@+id/star_rating_view"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginTop="4dp"
app:layout_constraintBottom_toTopOf="@id/advertiser_text_view"
app:layout_constraintStart_toStartOf="@id/text_view"
app:layout_constraintTop_toBottomOf="@id/text_view" />
<TextView
android:id="@+id/body_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/bg_ad_border"
android:baselineAligned="false">
<com.google.android.gms.ads.nativead.MediaView
android:id="@+id/ad_media"
android:layout_width="91dp"
android:layout_height="91dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="5dp" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginHorizontal="8dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/tv_max_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:textColor="@color/black"
android:textSize="14sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="#FF923E"
android:padding="2dp"
android:text="Ad"
android:textColor="@color/white"
android:textSize="12sp"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/tv_max_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="10dp"
android:ellipsize="end"
android:maxLines="2"
android:textColor="@color/black"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingVertical="5dp">
<ImageView
android:id="@+id/ad_app_icon"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center_vertical"
tools:ignore="ContentDescription" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/ad_call_to_action"
android:layout_width="match_parent"
android:layout_height="26dp"
android:layout_gravity="center_vertical"
android:layout_marginHorizontal="12dp"
android:background="@drawable/bg_ad_button"
android:gravity="center"
android:textColor="@color/white"
android:textSize="15sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</com.google.android.gms.ads.nativead.NativeAdView>
\ No newline at end of file
android:layout_marginTop="8dp"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/icon_image_view"
tools:text="Body" />
<FrameLayout
android:id="@+id/media_view_container"
android:layout_width="0dp"
android:layout_height="100dp"
android:layout_marginTop="4dp"
android:maxHeight="50dp"
app:layout_constraintDimensionRatio="W,16:9"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/body_text_view" />
<Button
android:id="@+id/cta_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:backgroundTint="@color/applovin_sdk_brand_color"
android:textColor="@android:color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/media_view_container"
tools:layout_editor_absoluteX="8dp"
tools:text="Install" />
</androidx.constraintlayout.widget.ConstraintLayout>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment