old mode 100755
new mode 100644
| | |
| | | using Microsoft.AppCenter; |
| | | using Microsoft.AppCenter.Analytics; |
| | | using Microsoft.AppCenter.Crashes; |
| | | using Com.Tencent.MM.Sdk.Openapi; |
| | | using ZXing.Mobile;
|
| | | using System.IO;
|
| | | using GateWay.Droid.JPush; |
| | | |
| | | namespace com.hdl.home |
| | | { |
| | | /// <summary>
/// 设定为默认启动的Application
/// </summary>
[Android.App.Application]
public class Application : Android.App.Application
{
public Application(IntPtr handle, Android.Runtime.JniHandleOwnership ownerShip) : base(handle, ownerShip) { }
public override void OnCreate()
{
//安卓配网初始
//var result = Com.Mediatek.Elian.ElianNative.LoadLib();
//if (!result)
//{
// System.Console.WriteLine("Error,can't load elianjni lib");
//} |
| | | [Activity(Name = "com.hdl.home.wxapi.WXEntryActivity", Exported = true, Theme = "@android:style/Theme.Translucent", LaunchMode = Android.Content.PM.LaunchMode.SingleTask)] |
| | | class WXEntryActivity : Android.App.Activity, IWXAPIEventHandler |
| | | { |
| | | public void OnReq(BaseReq p0) |
| | | {
|
| | |
|
| | | } |
| | | protected override void OnNewIntent(Intent intent) |
| | | { |
| | | base.OnNewIntent(intent); |
| | | Intent = intent; |
| | | com.hdl.home.Application.api?.HandleIntent(intent, this); |
| | | //Finish(); |
| | | } |
| | | public static Action<string> RespAction; |
| | | public void OnResp(BaseResp p0) |
| | | { |
| | | |
| | | initAll();
base.OnCreate();
} |
| | | if (p0 is SendAuth.Resp) |
| | | { |
| | | var resp = p0 as SendAuth.Resp; |
| | | |
| | | switch (resp.ErrCode) |
| | | { |
| | | case SendAuth.Resp.InnerErrCode.ErrOk: |
| | | var result = new System.Net.WebClient { }.DownloadString($"https://api.weixin.qq.com/sns/oauth2/access_token?appid=wx2ec8f53f6fa36e82&secret=a08585cd6ff2ce64570b9e7e6525dd8e&code={resp.Token}&grant_type=authorization_code"); |
| | | RespAction?.Invoke(result); |
| | | break; |
| | | default: |
| | | RespAction?.Invoke(null); |
| | | break;
|
| | |
|
| | | //case SendAuth.Resp.InnerErrCode.ErrUserCancel:
|
| | | // break;
|
| | | //case SendAuth.Resp.InnerErrCode.ErrAuthDenied:
|
| | | // break;
|
| | |
|
| | | } |
| | | }
|
| | |
|
| | | this.Finish(); |
| | | } |
| | | //IWXAPI api; |
| | | protected override void OnCreate(Bundle savedInstanceState) |
| | | { |
| | | base.OnCreate(savedInstanceState);
|
| | | // 通过WXAPIFactory工厂,获取IWXAPI的实例
|
| | | //api = WXAPIFactory.CreateWXAPI(this, "wx2ec8f53f6fa36e82", false);
|
| | |
|
| | | // 将应用的appId注册到微信
|
| | | //api.RegisterApp("wx2ec8f53f6fa36e82");
|
| | |
|
| | | com.hdl.home.Application.api?.HandleIntent(Intent, this); |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// 设定为默认启动的Application |
| | | /// </summary> |
| | | [Android.App.Application]
|
| | | public class Application : Android.App.Application
|
| | | {
|
| | | public Application(IntPtr handle, Android.Runtime.JniHandleOwnership ownerShip) : base(handle, ownerShip) { }
|
| | |
|
| | | /// <summary>
|
| | | /// 检测内存泄露的东西
|
| | | /// </summary> |
| | | //private Square.LeakCanary.RefWatcher _refWatcher;
|
| | |
|
| | | public override void OnCreate()
|
| | | { |
| | | //如果不是App的主进程,则不需要处理 |
| | | if (this.IsCurrentAppProcess == false)
|
| | | {
|
| | | base.OnCreate();
|
| | | return;
|
| | | } |
| | | try
|
| | | {
|
| | | //这个东西好像可能会出异常
|
| | | this.initAll();
|
| | | }
|
| | | catch (Exception ex)
|
| | | {
|
| | | //调试:记录系统异常
|
| | | Shared.Phone.UserCenter.HdlLogLogic.Current.WriteOtherText(Shared.Phone.UserCenter.DirNameResourse.SystemLogFile, ex.Message + "\r\n" + ex.StackTrace, true, false);
|
| | | }
|
| | | base.OnCreate();
|
| | | // 通过WXAPIFactory工厂,获取IWXAPI的实例
|
| | | //api = WXAPIFactory.CreateWXAPI(this, "wx2ec8f53f6fa36e82", true);
|
| | |
|
| | | //检测内存泄露的东西
|
| | | //if (Square.LeakCanary.LeakCanaryXamarin.IsInAnalyzerProcess(this) == false)
|
| | | //{
|
| | | // _refWatcher = Square.LeakCanary.LeakCanaryXamarin.Install(this);
|
| | | // _refWatcher.Watch(this);
|
| | | //} |
| | | |
| | | // 将应用的appId注册到微信 |
| | | api?.RegisterApp("wx2ec8f53f6fa36e82"); |
| | | }
|
| | |
|
| | | /// <summary>
|
| | | /// 判断当前进程是不是App自己的主进程
|
| | | /// </summary> |
| | | private bool IsCurrentAppProcess
|
| | | {
|
| | | get
|
| | | {
|
| | | var activityManager = (ActivityManager)GetSystemService(ActivityService); |
| | | var listProcess = activityManager.RunningAppProcesses; |
| | | foreach (var process in listProcess)
|
| | | {
|
| | | if (process.ProcessName == "com.evoyo.home" && process.Pid == Android.OS.Process.MyPid())
|
| | | {
|
| | | return true;
|
| | | }
|
| | | } |
| | | return false; |
| | | } |
| | | }
|
| | |
|
| | | internal static IWXAPI api; |
| | | |
| | | /// <summary>
/// 所有初始化全部在这个方法实现
/// </summary>
void initAll()
{
BaseActivity.IsEnnableGPS = false; |
| | | public static void WXLogin()
|
| | | { |
| | | var req = new SendAuth.Req { Scope = "snsapi_userinfo", State = "ZigbeeApp" }; |
| | | api?.SendReq(req); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 所有初始化全部在这个方法实现 |
| | | /// </summary> |
| | | void initAll()
|
| | | {
|
| | | //取消屏幕常亮
|
| | | BaseActivity.KeepScreenON = false;
|
| | | //隐藏底部软按键
|
| | | BaseActivity.IsHideVirualButtons = true; |
| | | |
| | | //设置极光调试模式,为false时只打印警告信息 |
| | | // System.Console.WriteLine($"AAA : {System.DateTime.Now.ToString()}"); |
| | | #if Release
JPushInterface.SetDebugMode(false); |
| | | //保存手机名称到本地文件 |
| | | //System.Console.WriteLine($"BBB : {System .DateTime .Now .ToString ()}"); |
| | | |
| | | JPushInterface.Init(this); |
| | | //System.Console.WriteLine($"CCC : {System.DateTime.Now.ToString()}"); |
| | | #endif |
| | | BaseActivity.BackKeyAction = () => { |
| | | JPushInterface.SetDebugMode(true); |
| | | JPushInterface.Init(this);
|
| | | string registration_id = JPushInterface.GetRegistrationID(this); |
| | | |
| | | BaseActivity.BackKeyAction = () =>
|
| | | { |
| | | try |
| | | { |
| | | if (Shared.Common.CommonPage.BackKeyCanClick == false) |
| | | { |
| | | //不允许按返回键 |
| | | return; |
| | | } |
| | | if (Shared.Common.CommonPage.Loading != null) |
| | | { |
| | | Console.WriteLine(Shared.Common.CommonPage.Loading.CurStatus); |
| | |
| | | Console.WriteLine("Remove PageLayout Children!!!!"); |
| | | HomePage.Instance.GetChildren(HomePage.Instance.ChildrenCount - 1).RemoveFromParent(); |
| | | Console.WriteLine("Remove PageLayout Children End!!!!"); |
| | | }
|
| | | else if (Shared.Common.CommonPage.Instance.ChildrenCount > 2)
|
| | | {
|
| | | //这里只对应登陆界面的
|
| | | Shared.Common.CommonPage.Instance.GetChildren(Shared.Common.CommonPage.Instance.ChildrenCount - 1).RemoveFromParent();
|
| | | } |
| | | else |
| | | { |
| | | BaseActivity.VerifyDateTime = DateTime.MaxValue; |
| | | Console.WriteLine("BaseActivity VerifyDateTime Max!!!!"); |
| | | } |
| | | }; |
| | |
BaseActivity.OnCreateActoin += (activity, application) => { |
| | | AppCenter.Start("4802834a-e7e9-4dd8-93f1-c2f88f0bd464", typeof(Analytics), typeof(Crashes));
#if Release
//保存获取的极光服务器上的注册ID到本地文件
var registrationId = JPushInterface.GetRegistrationID(activity); |
| | | };
|
| | | BaseActivity.OnCreateActoin += (activity, application) =>
|
| | | { |
| | | Shared.Application.FontSize = 12; |
| | | AppCenter.Start("4802834a-e7e9-4dd8-93f1-c2f88f0bd464", typeof(Analytics), typeof(Crashes));
|
| | | #if Release |
| | | //保存获取的极光服务器上的注册ID到本地文件 |
| | | var registrationId = JPushInterface.GetRegistrationID(activity); |
| | | System.Console.WriteLine("registrationId-极光id=" + registrationId); |
| | | if (!string.IsNullOrEmpty(registrationId))
{
Shared.Common.Config.Instance.RegistrationID = registrationId;
Shared.Common.Config.Instance.Save();
}
#endif
};
BaseActivity.RefreshUIAction += (activity) => {
Shared.Language.CurrentLanguage = "Chinese";
Shared.Common.CommonPage.Instance.Show();
};
BaseActivity.OnResumeAction += (activity) => {
};
BaseActivity.NetworkStateChanged += (v) =>
{
//网络状态变化处理事件 |
| | | Shared.Common.CommonPage.nowNetworkMode = v;
};
BaseActivity.OnDestroyAction += (activity) => {
//socket停止连接
//ZigBee.Device.ZbGateway.FindGateWaySocket.Stop();
};
}
public static bool IsShowTip = true;
JpushNotificationReceiver myReceiver = new JpushNotificationReceiver { };
/// <summary>
/// 项目启动时网络查询
/// </summary>
void checkSomeInfo()
{
var status = isNetworkAvailable(this);
string internetStatus = "Available";
if (!status)
{
internetStatus = "UnaVailable";
}
else
{
var isWifi = isWifiConnected(this);
if (isWifi)
{
internetStatus = "WiFiConnect";
}
else
{
internetStatus = "MobileConnect";
}
}
int connectState = 0;
if (internetStatus == "UnaVailable")
{
connectState = 0;
}
else if (internetStatus == "WiFiConnect")
{
connectState = 2;
}
else
{
connectState = 1;
}
//ZigBee.Device.ZbGateway.CheckConnection(connectState);
}
/// <summary>
/// 网络是否可用
/// </summary>
/// <returns><c>true</c>, if network available was ised, <c>false</c> otherwise.</returns>
/// <param name="context">Context.</param>
bool isNetworkAvailable(Context context)
{
var cm = (ConnectivityManager)context.GetSystemService(ConnectivityService);
if (cm == null || cm.ActiveNetworkInfo == null)
{
//当前网络不可用
return false;
}
else
{
return cm.ActiveNetworkInfo.IsAvailable;
}
}
/// <summary>
/// 网络是否连接
/// </summary>
/// <returns><c>true</c>, if wifi connected was ised, <c>false</c> otherwise.</returns>
/// <param name="context">Context.</param>
bool isWifiConnected(Context context)
{
if (context != null)
{
var cm = (ConnectivityManager)context.GetSystemService(ConnectivityService);
var mWiFiNetworkInfo = cm.GetNetworkInfo(ConnectivityType.Wifi);
if (Android.Net.NetworkInfo.State.Connected == mWiFiNetworkInfo.GetState())
{
//当前网络是Wi-Fi连接
return true;
}
var moWiFiNetworkInfo = cm.GetNetworkInfo(ConnectivityType.Mobile);
if (Android.Net.NetworkInfo.State.Connected == moWiFiNetworkInfo.GetState())
{
//当前网络是Mobile连接
return false;
}
}
return false;
} |
| | | } |
| | | |
| | | public class JpushNotificationReceiver : BroadcastReceiver |
| | | { |
| | | private static string TAG = "JpushNotificationReceiver"; |
| | | private NotificationManager nm; |
| | | static string ACTION = "android.intent.action.BOOT_COMPLETED"; |
| | | public override void OnReceive(Context context, Intent intent) |
| | | { |
| | | if (nm == null) |
| | | { |
| | | nm = (NotificationManager)context.GetSystemService(Context.NotificationService); |
| | | } |
| | | //base.OnReceive (context, intent); |
| | | try |
| | | { |
| | | Bundle bundle = intent.Extras; |
| | | if (intent.Action == ACTION) |
| | | { |
| | | //开机自动服务自动启动,PushService是要启动的服务 |
| | | Intent service = new Intent(context, typeof(PushService)); |
| | | context.StartService(service); |
| | | }
|
| | |
|
| | | //接收Registration Id
|
| | | if (JPushInterface.ActionRegistrationId == intent.Action)
|
| | | if (!string.IsNullOrEmpty(registrationId)) |
| | | { |
| | | Shared.Common.Config.Instance.RegistrationID = registrationId; |
| | | Shared.Common.Config.Instance.Save(); |
| | | } |
| | | //调试:记录极光ID |
| | | Shared.Phone.UserCenter.HdlLogLogic.Current.WriteOtherText(Shared.Phone.UserCenter.DirNameResourse.JiguangFile, "receive1:" + registrationId, true, true); |
| | | #endif |
| | | };
|
| | | BaseActivity.RefreshUIAction += (activity) =>
|
| | | {
|
| | | Shared.Language.CurrentLanguage = "Chinese";
|
| | | Shared.Common.CommonPage.Instance.Show();
|
| | | };
|
| | | BaseActivity.NetworkStateChanged += (v) =>
|
| | | {
|
| | | };
|
| | | BaseActivity.OnDestroyAction += (activity) =>
|
| | | {
|
| | | //socket停止连接
|
| | | //ZigBee.Device.ZbGateway.FindGateWaySocket.Stop();
|
| | | };
|
| | | HDLUtils.SetAuthoritiesName("com.evoyo.home.fileProvider");
|
| | | }
|
| | | public static bool IsShowTip = true;
|
| | | JpushNotificationReceiver myReceiver = new JpushNotificationReceiver { };
|
| | | /// <summary> |
| | | /// 项目启动时网络查询 |
| | | /// </summary> |
| | | void checkSomeInfo()
|
| | | {
|
| | | var status = isNetworkAvailable(this);
|
| | | string internetStatus = "Available";
|
| | | if (!status)
|
| | | {
|
| | | internetStatus = "UnaVailable";
|
| | | }
|
| | | else
|
| | | {
|
| | | var isWifi = isWifiConnected(this);
|
| | | if (isWifi)
|
| | | {
|
| | | string regId = bundle.GetString(JPushInterface.ExtraRegistrationId);
|
| | | if (!string.IsNullOrEmpty(regId))
|
| | | {
|
| | | Shared.Common.Config.Instance.RegistrationID = regId;
|
| | | Shared.Common.Config.Instance.Save();
|
| | | }
|
| | | } |
| | | //用户点击打开了通知 |
| | | else if (JPushInterface.ActionNotificationOpened == intent.Action) |
| | | { |
| | | OpenNotification(context, bundle); |
| | | } |
| | | //接受到推送下来的通知 |
| | | else if (JPushInterface.ActionNotificationReceived == intent.Action) |
| | | { |
| | | //int notifactionId = bundle.GetInt(JPushInterface.ExtraNotificationId); |
| | | ReceivingNotification(context, bundle); |
| | | //Shared.Common.CommonPage.Instance.SingOut(); |
| | | } |
| | | //接收到推送下来的自定义消息 |
| | | else if (JPushInterface.ActionMessageReceived == intent.Action) |
| | | { |
| | | bundle.GetString(JPushInterface.ExtraMessage); |
| | | } |
| | | else |
| | | { |
| | | } |
| | | } |
| | | catch (System.Exception e) |
| | | { |
| | | internetStatus = "WiFiConnect";
|
| | | }
|
| | | else
|
| | | {
|
| | | internetStatus = "MobileConnect";
|
| | | }
|
| | | }
|
| | | int connectState = 0;
|
| | | if (internetStatus == "UnaVailable")
|
| | | {
|
| | | connectState = 0;
|
| | | }
|
| | | else if (internetStatus == "WiFiConnect")
|
| | | {
|
| | | connectState = 2;
|
| | | }
|
| | | else
|
| | | {
|
| | | connectState = 1;
|
| | | }
|
| | | //ZigBee.Device.ZbGateway.CheckConnection(connectState);
|
| | | }
|
| | | /// <summary> |
| | | /// 网络是否可用 |
| | | /// </summary> |
| | | /// <returns><c>true</c>, if network available was ised, <c>false</c> otherwise.</returns> |
| | | /// <param name="context">Context.</param> |
| | | bool isNetworkAvailable(Context context)
|
| | | {
|
| | | var cm = (ConnectivityManager)context.GetSystemService(ConnectivityService);
|
| | | if (cm == null || cm.ActiveNetworkInfo == null)
|
| | | {
|
| | | //当前网络不可用
|
| | | return false;
|
| | | }
|
| | | else
|
| | | {
|
| | | return cm.ActiveNetworkInfo.IsAvailable;
|
| | | }
|
| | | }
|
| | | /// <summary> |
| | | /// 网络是否连接 |
| | | /// </summary |
| | | /// <returns><c>true</c>, if wifi connected was ised, <c>false</c> otherwise.</returns> |
| | | /// <param name="context">Context.</param> |
| | | bool isWifiConnected(Context context)
|
| | | {
|
| | | if (context != null)
|
| | | {
|
| | | var cm = (ConnectivityManager)context.GetSystemService(ConnectivityService);
|
| | | var mWiFiNetworkInfo = cm.GetNetworkInfo(ConnectivityType.Wifi);
|
| | | if (Android.Net.NetworkInfo.State.Connected == mWiFiNetworkInfo.GetState())
|
| | | {
|
| | | //当前网络是Wi-Fi连接
|
| | | return true;
|
| | | }
|
| | | var moWiFiNetworkInfo = cm.GetNetworkInfo(ConnectivityType.Mobile);
|
| | | if (Android.Net.NetworkInfo.State.Connected == moWiFiNetworkInfo.GetState())
|
| | | {
|
| | | //当前网络是Mobile连接
|
| | | return false;
|
| | | }
|
| | | }
|
| | | return false;
|
| | | } |
| | | }
|
| | | } |
| | | |
| | | System.Console.WriteLine("极光推送出错:" + e.Message); |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// 接收消息通知 |
| | | /// </summary> |
| | | /// <param name="context">Context.</param> |
| | | /// <param name="bundle">Bundle.</param> |
| | | private void ReceivingNotification(Context context, Bundle bundle) |
| | | { |
| | | String title = bundle.GetString(JPushInterface.ExtraNotificationTitle); |
| | | System.Console.WriteLine(TAG, " title : " + title); |
| | | String message = bundle.GetString(JPushInterface.ExtraAlert); |
| | | System.Console.WriteLine(TAG, "message : " + message); |
| | | String extras = bundle.GetString(JPushInterface.ExtraExtra); |
| | | System.Console.WriteLine(TAG, "extras : " + extras);
|
| | | namespace Shared |
| | | { |
| | | public static class QRCode |
| | | { |
| | | static ZXing.Mobile.MobileBarcodeScanner scanner;
|
| | | public static void ScanQRcode(Action<string> action, string cancel = "取消", string flashText = "闪光灯", string titleText = "二维码扫描")
|
| | | {
|
| | | ((BaseActivity)Shared.Application.Activity).SetCamera(async (obj) =>
|
| | | {
|
| | | if (obj)
|
| | | {
|
| | | if (scanner == null)
|
| | | {
|
| | | MobileBarcodeScanner.Initialize(Shared.Application.Activity.Application);
|
| | | var mZXingCustomScanView = new GateWay.Droid.ZXingCustomScanView(Shared.Application.Activity.Application);
|
| | | mZXingCustomScanView.cancelTextView.Text = cancel;
|
| | | mZXingCustomScanView.flashTextView.Text = flashText;
|
| | | mZXingCustomScanView.titleTextView.Text = titleText;
|
| | | var bOn = false;
|
| | | scanner = new ZXing.Mobile.MobileBarcodeScanner()
|
| | | {
|
| | | UseCustomOverlay = true,
|
| | | CustomOverlay = mZXingCustomScanView
|
| | | };
|
| | |
|
| | | //处理极光消息推送的逻辑函数
|
| | | Shared.Phone.UserCenter.HdlJiguangMsgPushLogic.Current.AdjustJiguangMsgPush(title, message, extras); |
| | | mZXingCustomScanView.OnCancel += () =>
|
| | | {
|
| | |
|
| | | scanner?.Cancel();
|
| | | };
|
| | |
|
| | | mZXingCustomScanView.OnTorch += () =>
|
| | | {
|
| | | bOn = !bOn;
|
| | | scanner?.Torch(bOn);
|
| | | };
|
| | | }
|
| | |
|
| | | var result = await scanner.Scan();
|
| | |
|
| | | if (result != null)
|
| | | action?.Invoke(result.Text);
|
| | | else
|
| | | action?.Invoke(null);
|
| | |
|
| | | }
|
| | | else
|
| | | {
|
| | | action?.Invoke(null);
|
| | | }
|
| | | });
|
| | | } |
| | | /// <summary> |
| | | /// 打开消息显示界面 |
| | | /// </summary> |
| | | /// <param name="context">Context.</param> |
| | | /// <param name="bundle">Bundle.</param> |
| | | private void OpenNotification(Context context, Bundle bundle) |
| | | |
| | | public static byte[] BytesFromText(string text, int width = 300, int height = 300) |
| | | { |
| | | String extras = bundle.GetString(JPushInterface.ExtraExtra); |
| | | String myValue = ""; |
| | | try |
| | | var barcodeWriter = new ZXing.Mobile.BarcodeWriter |
| | | { |
| | | JSONObject extrasJson = new JSONObject(extras); |
| | | myValue = extrasJson.OptString("myKey"); |
| | | } |
| | | catch (Exception e) |
| | | Format = ZXing.BarcodeFormat.QR_CODE, |
| | | Options = new ZXing.Common.EncodingOptions |
| | | { |
| | | Width = width, |
| | | Height = height, |
| | | Margin = 0 |
| | | } |
| | | }; |
| | | |
| | | barcodeWriter.Renderer = new ZXing.Mobile.BitmapRenderer();
|
| | | var bitmap = barcodeWriter.Write(text);
|
| | | using (var stream = new MemoryStream()) |
| | | { |
| | | System.Console.WriteLine(TAG, "Unexpected: extras is not a valid json", e); |
| | | return; |
| | | bitmap.Compress(Android.Graphics.Bitmap.CompressFormat.Png, 100, stream); // this is the diff between iOS and Android |
| | | stream.Position = 0; |
| | | return stream.ToArray(); |
| | | } |
| | | Intent i = new Intent(context, typeof(BaseActivity));//Intent intent=new Intent( 起始组件对象 , 目标 Service.class); |
| | | i.PutExtras(bundle); |
| | | i.SetFlags(ActivityFlags.NewTask); |
| | | context.StartActivity(i); |
| | | //if (TYPE_THIS.equals(myValue)) |
| | | //{ |
| | | //Intent mIntent = new Intent(context, ThisActivity.class); |
| | | //mIntent.putExtras(bundle); |
| | | //mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| | | //context.startActivity(mIntent); |
| | | //} |
| | | //else if (TYPE_ANOTHER.equals(myValue)) |
| | | //{ |
| | | //Intent mIntent = new Intent(context, AnotherActivity.class); |
| | | //mIntent.putExtras(bundle); |
| | | //mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| | | //context.startActivity(mIntent); |
| | | //} |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | } |