- Added realracing3-community.apk (71.57 MB) - Removed 32-bit support (armeabi-v7a) - Only includes arm64-v8a libraries - Decompiled source code included - Added README-community.md with analysis
475 lines
22 KiB
Java
475 lines
22 KiB
Java
package csdk.glucustomersupport.impl;
|
|
|
|
import android.app.Activity;
|
|
import android.app.Application;
|
|
import android.content.SharedPreferences;
|
|
import android.text.TextUtils;
|
|
import android.util.Pair;
|
|
import androidx.annotation.NonNull;
|
|
import androidx.core.app.NotificationCompat;
|
|
import com.fyber.inneractive.sdk.external.InneractiveMediationDefs;
|
|
import com.helpshift.Helpshift;
|
|
import com.helpshift.HelpshiftAuthenticationFailureReason;
|
|
import com.helpshift.HelpshiftEventsListener;
|
|
import com.helpshift.core.HSContext;
|
|
import com.mbridge.msdk.foundation.entity.CampaignEx;
|
|
import com.tapjoy.TJAdUnitConstants;
|
|
import csdk.gluads.PrivacyStatus;
|
|
import csdk.glucustomersupport.Consts;
|
|
import csdk.glucustomersupport.GluCustomerSupportSessionEndedEvent;
|
|
import csdk.glucustomersupport.GluCustomerSupportSessionStartedEvent;
|
|
import csdk.glucustomersupport.NotificationCountEvent;
|
|
import csdk.glucustomersupport.util.ConfigUtil;
|
|
import csdk.glucustomersupport.util.GluUtil;
|
|
import csdk.glucustomersupport.util.JsonUtil;
|
|
import csdk.glucustomersupport.util.StringStore;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.concurrent.Callable;
|
|
|
|
/* loaded from: classes4.dex */
|
|
public class GluHelpshift extends GluImplBase {
|
|
List<Object> countriesThatRequireFullPrivacy;
|
|
private GluHelpShiftActivityLifecycleCallbacks mActivityLifeCycleCallbacks;
|
|
private boolean mCcpaApplies;
|
|
HashMap<String, Object> mConfig;
|
|
private String mDefaultShowType;
|
|
private boolean mFetchNotificationCountFromServer;
|
|
private boolean mGdprApplies;
|
|
private String mPublishID;
|
|
private boolean mUnderAge;
|
|
private String pushTokenCopy;
|
|
private boolean sendAnalyticsEvents;
|
|
|
|
public void sendAnalyticsEvent(String str, Map<String, Object> map) {
|
|
if (this.sendAnalyticsEvents) {
|
|
if (map == null) {
|
|
map = new HashMap<>();
|
|
}
|
|
String str2 = "C_" + str;
|
|
String str3 = this.mPublishID;
|
|
if (str3 != null && str3.length() > 0 && !this.mPublishID.equals("NOT_AVAILABLE")) {
|
|
map.put("publishID", this.mPublishID);
|
|
}
|
|
map.put("tier", Integer.valueOf(this.tier));
|
|
this.mEventHandler.sendAnalyticsEvent(str2, map);
|
|
}
|
|
}
|
|
|
|
public GluHelpshift(Callable<Activity> callable, Map<String, Object> map, Map<String, Object> map2) {
|
|
super(callable, map, "HELPSHIFT");
|
|
this.mConfig = new HashMap<>();
|
|
this.mDefaultShowType = ConfigUtil.getString(map, "csdk.gluCustomerSupport.helpshift.defaultShowType", "chat");
|
|
ConfigUtil.getString(map, "csdk.gluCustomerSupport.helpshift.apiKey", null);
|
|
String string = ConfigUtil.getString(map, "csdk.gluCustomerSupport.helpshift.domainName", null);
|
|
String string2 = ConfigUtil.getString(map, "csdk.gluCustomerSupport.helpshift.appID", null);
|
|
Boolean valueOf = Boolean.valueOf(ConfigUtil.getBoolean(map, "csdk.gluCustomerSupport.helpshift.enableManualLifecycleTracking", false));
|
|
this.mFetchNotificationCountFromServer = ConfigUtil.getBoolean(map, "csdk.gluCustomerSupport.helpshift.fetchNotificationCountFromServer", true);
|
|
this.mGdprApplies = false;
|
|
this.mCcpaApplies = false;
|
|
this.mUnderAge = false;
|
|
this.sendAnalyticsEvents = !ConfigUtil.getBoolean(map, "csdk.gluCustomerSupport.disabled.sendAnalyticsEvents", false);
|
|
ArrayList arrayList = new ArrayList();
|
|
arrayList.add("RU");
|
|
this.countriesThatRequireFullPrivacy = ConfigUtil.getList(map, "csdk.gluCustomerSupport.helpshift.countriesThatRequireFullPrivacy", arrayList);
|
|
try {
|
|
Map<String, Object> installConfig = getInstallConfig(map2, valueOf.booleanValue());
|
|
Helpshift.install(this.mActivity.getApplication(), string2, string, installConfig);
|
|
String string3 = ConfigUtil.getString(map2, "language", null);
|
|
if (string3 != null && string3.length() == 2) {
|
|
Helpshift.setLanguage(string3);
|
|
}
|
|
internal_cacheConfig(string2, string, installConfig);
|
|
} catch (Exception e) {
|
|
log("Exception", e.toString());
|
|
}
|
|
Helpshift.setHelpshiftEventsListener(new HelpshiftEventsListener() { // from class: csdk.glucustomersupport.impl.GluHelpshift.1
|
|
@Override // com.helpshift.HelpshiftEventsListener
|
|
public void onUserAuthenticationFailure(HelpshiftAuthenticationFailureReason helpshiftAuthenticationFailureReason) {
|
|
}
|
|
|
|
@Override // com.helpshift.HelpshiftEventsListener
|
|
public void onEventOccurred(@NonNull String str, Map<String, Object> map3) {
|
|
str.hashCode();
|
|
switch (str) {
|
|
case "helpshiftSessionStarted":
|
|
GluHelpshift.this.log(InneractiveMediationDefs.GENDER_MALE, "HelpshiftX session started.");
|
|
GluHelpshift.this.sendAnalyticsEvent("SESSION_STARTED", null);
|
|
GluHelpshift.this.mListener.onHelpshiftSessionStarted(new GluCustomerSupportSessionStartedEvent(null));
|
|
break;
|
|
case "messageAdd":
|
|
GluHelpshift.this.log(map3.get("body"));
|
|
if (map3.get("type").equals("attachment")) {
|
|
GluHelpshift.this.log(InneractiveMediationDefs.GENDER_MALE, "user sent an attachment");
|
|
}
|
|
GluHelpshift.this.sendAnalyticsEvent("MESSAGE_ADD", null);
|
|
break;
|
|
case "receivedUnreadMessageCount":
|
|
GluHelpshift.this.log(InneractiveMediationDefs.GENDER_MALE, "HelpshiftX message count event.");
|
|
GluHelpshift.this.mListener.onQueryNotificationCount(new NotificationCountEvent(((Integer) map3.get("count")).intValue(), null));
|
|
break;
|
|
case "conversationEnd":
|
|
GluHelpshift.this.sendAnalyticsEvent("CONVERSATION_ENDED", null);
|
|
break;
|
|
case "helpshiftSessionEnded":
|
|
GluHelpshift.this.log(InneractiveMediationDefs.GENDER_MALE, "HelpshiftX session ended.");
|
|
GluHelpshift.this.sendAnalyticsEvent("SESSION_ENDED", null);
|
|
GluHelpshift.this.mListener.onHelpshiftSessionEnded(new GluCustomerSupportSessionEndedEvent(null));
|
|
break;
|
|
case "csatSubmit":
|
|
GluHelpshift.this.log(map3.get(CampaignEx.JSON_KEY_STAR));
|
|
GluHelpshift.this.log(map3.get("additionalFeedback"));
|
|
Map<String, Object> createMap = GluUtil.createMap();
|
|
createMap.put(CampaignEx.JSON_KEY_STAR, map3.get(CampaignEx.JSON_KEY_STAR));
|
|
GluHelpshift.this.sendAnalyticsEvent("CSAT_SUBMIT", createMap);
|
|
break;
|
|
case "conversationStart":
|
|
GluHelpshift.this.log(map3.get("message"));
|
|
GluHelpshift.this.sendAnalyticsEvent("CONVERSATION_START", null);
|
|
break;
|
|
case "widgetToggle":
|
|
GluHelpshift.this.log(map3.get(TJAdUnitConstants.String.VISIBLE));
|
|
break;
|
|
case "conversationRejected":
|
|
GluHelpshift.this.log(InneractiveMediationDefs.GENDER_MALE, "Conversation rejected.");
|
|
GluHelpshift.this.sendAnalyticsEvent("CONVERSATION_REJECTED", null);
|
|
break;
|
|
case "conversationReopened":
|
|
GluHelpshift.this.log(InneractiveMediationDefs.GENDER_MALE, "Conversation reopened.");
|
|
GluHelpshift.this.sendAnalyticsEvent("CONVERSATION_REOPENED", null);
|
|
break;
|
|
case "conversationResolved":
|
|
GluHelpshift.this.log(InneractiveMediationDefs.GENDER_MALE, "Conversation resolved.");
|
|
GluHelpshift.this.sendAnalyticsEvent("CONVERSATION_RESOLVED", null);
|
|
break;
|
|
case "conversationStatus":
|
|
GluHelpshift.this.log(map3.get("latestIssuePublishId"));
|
|
GluHelpshift.this.mPublishID = (String) map3.get("latestIssuePublishId");
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
if (valueOf.booleanValue()) {
|
|
Helpshift.onAppForeground();
|
|
this.mActivityLifeCycleCallbacks = new GluHelpShiftActivityLifecycleCallbacks(this.mActivity, new IAction2<String, Activity>() { // from class: csdk.glucustomersupport.impl.GluHelpshift.2
|
|
@Override // csdk.glucustomersupport.impl.IAction2
|
|
public void apply(String str, Activity activity) {
|
|
GluHelpshift.this.log("ACTIVITY", NotificationCompat.CATEGORY_EVENT, str, "activity", activity);
|
|
if ("onApplicationResumed".equals(str)) {
|
|
Helpshift.onAppForeground();
|
|
} else if ("onApplicationPaused".equals(str)) {
|
|
Helpshift.onAppBackground();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
private void internal_cacheConfig(String str, String str2, Map<String, Object> map) {
|
|
SharedPreferences.Editor edit = this.mActivity.getApplication().getSharedPreferences("hs_shared", 0).edit();
|
|
edit.putString("hs_appID", str);
|
|
edit.putString("hs_domainName", str2);
|
|
edit.putString("hs_config", JsonUtil.toJson(map));
|
|
edit.apply();
|
|
}
|
|
|
|
public static void internal_Install(Application application) {
|
|
if (application == null || HSContext.verifyInstall()) {
|
|
return;
|
|
}
|
|
SharedPreferences sharedPreferences = application.getSharedPreferences("hs_shared", 0);
|
|
String string = sharedPreferences.getString("hs_appID", "");
|
|
String string2 = sharedPreferences.getString("hs_domainName", "");
|
|
String string3 = sharedPreferences.getString("hs_config", "");
|
|
if (string.length() <= 0 || string2.length() <= 0 || string3.length() <= 0) {
|
|
return;
|
|
}
|
|
try {
|
|
Helpshift.install(application, string, string2, JsonUtil.toMap(string3));
|
|
} catch (Exception unused) {
|
|
}
|
|
}
|
|
|
|
@Override // csdk.glucustomersupport.IGluCustomerSupport
|
|
public void login(Map<String, Object> map) {
|
|
String gluImplBase = toString(map.get(Consts.LOGIN_INFO_USERID));
|
|
String gluImplBase2 = toString(map.get(Consts.LOGIN_INFO_NAME));
|
|
String gluImplBase3 = toString(map.get(Consts.LOGIN_INFO_EMAIL));
|
|
GluUtil.require(!TextUtils.isEmpty(gluImplBase), "userID can't be null or empty.");
|
|
String trim = gluImplBase.trim();
|
|
if (trim.length() > 750) {
|
|
trim = trim.substring(0, 750);
|
|
log(InneractiveMediationDefs.GENDER_MALE, "userID is too long, truncated to 750 chars");
|
|
}
|
|
this.mUserID = trim;
|
|
if (gluImplBase2 != null) {
|
|
gluImplBase2 = gluImplBase2.trim();
|
|
if (gluImplBase2.length() > 255) {
|
|
gluImplBase2 = gluImplBase2.substring(0, 255);
|
|
log(InneractiveMediationDefs.GENDER_MALE, "userName is too long, truncated to 255 chars");
|
|
}
|
|
}
|
|
if (gluImplBase3 != null) {
|
|
gluImplBase3 = gluImplBase3.trim();
|
|
}
|
|
this.mUserName = gluImplBase2;
|
|
this.mUserEmail = gluImplBase3;
|
|
HashMap hashMap = new HashMap();
|
|
String str = this.mUserID;
|
|
if (str != null && !TextUtils.isEmpty(str)) {
|
|
hashMap.put("userId", this.mUserID);
|
|
}
|
|
String str2 = this.mUserEmail;
|
|
if (str2 != null && !TextUtils.isEmpty(str2)) {
|
|
hashMap.put("userEmail", this.mUserEmail);
|
|
}
|
|
String str3 = this.mUserName;
|
|
if (str3 != null && !TextUtils.isEmpty(str3)) {
|
|
hashMap.put("userName", this.mUserName);
|
|
}
|
|
if (hashMap.size() > 0) {
|
|
Helpshift.login(hashMap);
|
|
} else {
|
|
log(InneractiveMediationDefs.GENDER_MALE, "HelpShift login called with no data, ignoring.");
|
|
}
|
|
}
|
|
|
|
@Override // csdk.glucustomersupport.IGluCustomerSupport
|
|
public void logout() {
|
|
Helpshift.logout();
|
|
}
|
|
|
|
@Override // csdk.glucustomersupport.impl.GluImplBase, csdk.glucustomersupport.IGluCustomerSupport
|
|
public void destroy() {
|
|
GluHelpShiftActivityLifecycleCallbacks gluHelpShiftActivityLifecycleCallbacks = this.mActivityLifeCycleCallbacks;
|
|
if (gluHelpShiftActivityLifecycleCallbacks != null) {
|
|
gluHelpShiftActivityLifecycleCallbacks.destroy();
|
|
}
|
|
}
|
|
|
|
@Override // csdk.glucustomersupport.IGluCustomerSupport
|
|
public void queryNotificationCount() {
|
|
log(InneractiveMediationDefs.GENDER_MALE, "queryNotificationCount");
|
|
Helpshift.requestUnreadMessageCount(this.mFetchNotificationCountFromServer);
|
|
}
|
|
|
|
@Override // csdk.glucustomersupport.IGluCustomerSupport
|
|
public void show(String str, Map<String, Object> map) {
|
|
str.hashCode();
|
|
switch (str) {
|
|
case "GCC_SHOW_TYPE_CHAT":
|
|
showConversation(map);
|
|
break;
|
|
case "GCC_SHOW_TYPE_DEFAULT":
|
|
if (this.mDefaultShowType.equals("chat")) {
|
|
show(Consts.SHOW_TYPE_CHAT, map);
|
|
break;
|
|
} else if (this.mDefaultShowType.equals("faq")) {
|
|
show(Consts.SHOW_TYPE_FAQ, map);
|
|
break;
|
|
} else {
|
|
log("Unsupported default type", this.mDefaultShowType);
|
|
break;
|
|
}
|
|
case "GCC_SHOW_TYPE_FAQ":
|
|
if (map != null && map.containsKey(Consts.SHOW_OPTION_FAQ_ID)) {
|
|
showSingleFAQ(toString(map.get(Consts.SHOW_OPTION_FAQ_ID)), map);
|
|
break;
|
|
} else if (map != null && map.containsKey(Consts.SHOW_OPTION_FAQ_SECTION)) {
|
|
showFAQSection(toString(map.get(Consts.SHOW_OPTION_FAQ_SECTION)), map);
|
|
break;
|
|
} else {
|
|
showFAQs(map);
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
log("Unsupported type", str);
|
|
break;
|
|
}
|
|
}
|
|
|
|
@Override // csdk.glucustomersupport.IGluCustomerSupport
|
|
public void setMetadata(Map<String, Object> map, List<Object> list, Map<String, Object> map2) {
|
|
log("setMetadata", map, "tags", list);
|
|
Pair<Map<String, Object>, Set<String>> metadata = getMetadata(map, list);
|
|
HashMap hashMap = new HashMap();
|
|
if (map2 != null) {
|
|
hashMap.putAll(map2);
|
|
}
|
|
String str = this.mUserID;
|
|
if (str != null && str.length() > 0 && !hashMap.containsKey("customer_id")) {
|
|
HashMap hashMap2 = new HashMap();
|
|
hashMap2.put("type", "singleline");
|
|
hashMap2.put("value", this.mUserID);
|
|
hashMap.put("customer_id", hashMap2);
|
|
}
|
|
Map map3 = (Map) metadata.first;
|
|
map3.put("gdpr_applies", this.mGdprApplies ? "true" : "false");
|
|
map3.put("ccpa_applies", this.mCcpaApplies ? "true" : "false");
|
|
HashMap<String, Object> hashMap3 = new HashMap<>();
|
|
this.mConfig = hashMap3;
|
|
hashMap3.put("customMetadata", map3);
|
|
this.mConfig.put("tags", ((Set) metadata.second).toArray());
|
|
if (hashMap.size() > 0) {
|
|
this.mConfig.put("customIssueFields", hashMap);
|
|
}
|
|
}
|
|
|
|
@Override // csdk.glucustomersupport.IGluCustomerSupport
|
|
public void setLanguageCode(String str) {
|
|
log(InneractiveMediationDefs.GENDER_MALE, "setLanguageCode", "code", str);
|
|
Helpshift.setLanguage(str);
|
|
}
|
|
|
|
@Override // csdk.glucustomersupport.IGluCustomerSupport
|
|
public void setPushToken(String str) {
|
|
this.pushTokenCopy = str;
|
|
log(InneractiveMediationDefs.GENDER_MALE, "setPushToken");
|
|
}
|
|
|
|
@Override // csdk.glucustomersupport.IGluCustomerSupport
|
|
public void setConsentFlags(Map<String, ?> map) {
|
|
this.mGdprApplies = ConfigUtil.getBoolean(map, PrivacyStatus.GDPR_APPLIES, false);
|
|
this.mCcpaApplies = ConfigUtil.getBoolean(map, PrivacyStatus.CCPA_APPLIES, false);
|
|
boolean z = ConfigUtil.getBoolean(map, PrivacyStatus.UNDER_AGE_USER, false);
|
|
this.mUnderAge = z;
|
|
if (z || this.pushTokenCopy == null) {
|
|
return;
|
|
}
|
|
log(InneractiveMediationDefs.GENDER_MALE, "setConsentFlags");
|
|
Helpshift.registerPushToken(this.pushTokenCopy);
|
|
}
|
|
|
|
private void showFAQs(Map<String, Object> map) {
|
|
log(InneractiveMediationDefs.GENDER_MALE, "showFAQs");
|
|
Helpshift.showFAQs(this.mActivity, convertOptions(map));
|
|
}
|
|
|
|
private void showSingleFAQ(String str, Map<String, Object> map) {
|
|
log(InneractiveMediationDefs.GENDER_MALE, "showSingleFAQ", "faq", str);
|
|
Helpshift.showSingleFAQ(this.mActivity, str, convertOptions(map));
|
|
}
|
|
|
|
private void showFAQSection(String str, Map<String, Object> map) {
|
|
log(InneractiveMediationDefs.GENDER_MALE, "showFAQSection", "section", str);
|
|
Helpshift.showFAQSection(this.mActivity, str, convertOptions(map));
|
|
}
|
|
|
|
private void showConversation(Map<String, Object> map) {
|
|
log(InneractiveMediationDefs.GENDER_MALE, "showConversation");
|
|
Helpshift.showConversation(this.mActivity, convertOptions(map));
|
|
}
|
|
|
|
private void logUserAction(String str) {
|
|
log("logUserAction", str);
|
|
Helpshift.leaveBreadCrumb(str);
|
|
}
|
|
|
|
private void clearUserActions() {
|
|
log(InneractiveMediationDefs.GENDER_MALE, "clearUserActions");
|
|
Helpshift.clearBreadCrumbs();
|
|
}
|
|
|
|
private Map<String, Object> getInstallConfig(Map<String, Object> map, boolean z) {
|
|
Object value;
|
|
Boolean bool;
|
|
Integer integer;
|
|
boolean z2;
|
|
HashMap hashMap = new HashMap();
|
|
if (map != null) {
|
|
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
|
value = entry.getValue();
|
|
bool = toBoolean(value);
|
|
integer = toInteger(value);
|
|
String key = entry.getKey();
|
|
key.hashCode();
|
|
z2 = true;
|
|
switch (key) {
|
|
case "notificationSound":
|
|
hashMap.put("notificationSoundId", Integer.valueOf(this.mActivity.getResources().getIdentifier(toString(value), "raw", this.mActivity.getPackageName())));
|
|
break;
|
|
case "largeNotificationIcon":
|
|
hashMap.put("notificationLargeIcon", Integer.valueOf(this.mActivity.getResources().getIdentifier(toString(value), "drawable", this.mActivity.getPackageName())));
|
|
break;
|
|
case "isForChina":
|
|
if (bool != null && !bool.booleanValue()) {
|
|
z2 = false;
|
|
}
|
|
hashMap.put("isForChina", Boolean.valueOf(z2));
|
|
break;
|
|
case "enableInAppNotification":
|
|
if (bool != null && !bool.booleanValue()) {
|
|
z2 = false;
|
|
}
|
|
hashMap.put("enableInAppNotification", Boolean.valueOf(z2));
|
|
break;
|
|
case "supportNotificationChannelId":
|
|
hashMap.put("notificationChannelId", value);
|
|
break;
|
|
case "screenOrientation":
|
|
hashMap.put("screenOrientation", Integer.valueOf(integer != null ? integer.intValue() : 0));
|
|
break;
|
|
case "enableLogging":
|
|
if (bool != null && !bool.booleanValue()) {
|
|
z2 = false;
|
|
}
|
|
hashMap.put("enableLogging", Boolean.valueOf(z2));
|
|
break;
|
|
case "notificationIcon":
|
|
hashMap.put("notificationIcon", Integer.valueOf(this.mActivity.getResources().getIdentifier(toString(value), "drawable", this.mActivity.getPackageName())));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (map != null && !map.containsKey("enableLogging")) {
|
|
hashMap.put("enableLogging", Boolean.valueOf(this.mIsDebug));
|
|
}
|
|
if (z) {
|
|
hashMap.put("manualLifecycleTracking", Boolean.TRUE);
|
|
}
|
|
return hashMap;
|
|
}
|
|
|
|
private Map<String, Object> convertOptions(Map<String, Object> map) {
|
|
HashMap hashMap = (HashMap) this.mConfig.clone();
|
|
boolean z = false;
|
|
if (map != null) {
|
|
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
|
Boolean bool = toBoolean(entry.getValue());
|
|
String key = entry.getKey();
|
|
key.hashCode();
|
|
if (key.equals("fullPrivacy") || key.equals("enableFullPrivacy")) {
|
|
hashMap.put("fullPrivacy", Boolean.valueOf(bool != null && bool.booleanValue()));
|
|
} else {
|
|
log("Option is not supported:", entry.getKey());
|
|
}
|
|
}
|
|
}
|
|
try {
|
|
String lowerCase = StringStore.get(StringStore.Key.LOCATION_ISO_CODE).toLowerCase();
|
|
if (lowerCase != null) {
|
|
int i = 0;
|
|
while (true) {
|
|
if (i >= this.countriesThatRequireFullPrivacy.size()) {
|
|
break;
|
|
}
|
|
if (((String) this.countriesThatRequireFullPrivacy.get(i)).compareToIgnoreCase(lowerCase) == 0) {
|
|
z = true;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
} catch (Exception unused) {
|
|
}
|
|
if (this.mUnderAge || z) {
|
|
hashMap.put("fullPrivacy", Boolean.TRUE);
|
|
}
|
|
return hashMap;
|
|
}
|
|
}
|