| | |
| | | { |
| | | public class UserSchedule : FrameLayout |
| | | { |
| | | /// <summary> |
| | | /// 上下滑动父控件 |
| | | /// </summary> |
| | | VerticalScrolViewLayout bodyView; |
| | | List<Timer> timers; |
| | | |
| | | public UserSchedule() |
| | | /// <summary> |
| | | /// 定时器列表 |
| | | /// </summary> |
| | | List<Timer> timerList; |
| | | /// <summary> |
| | | /// 对象构造函数 |
| | | /// </summary> |
| | | /// <param name="act">返回函数</param> |
| | | public UserSchedule () |
| | | { |
| | | BackgroundColor = SkinStyle.Current.MainColor; |
| | | timers = new List<Timer> (); |
| | | timerList = new List<Timer> (); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 对象主入口 |
| | | /// </summary> |
| | | public void ShowPage () |
| | | { |
| | | #region 标题 |
| | |
| | | topView.AddChidren (title); |
| | | |
| | | var back = new Button () { |
| | | Height = Application.GetRealHeight (100), |
| | | Height = Application.GetRealWidth (100), |
| | | Width = Application.GetRealWidth (85), |
| | | UnSelectedImagePath = "Item/Back.png", |
| | | SelectedImagePath = "Item/BackSelected.png", |
| | |
| | | |
| | | var ItemButton = new Button () { |
| | | Width = Application.GetRealWidth (55), |
| | | Height = Application.GetRealHeight (55), |
| | | Height = Application.GetRealWidth (55), |
| | | UnSelectedImagePath = "Item/+.png", |
| | | SelectedImagePath = "Item/+.png", |
| | | X = Application.GetRealWidth (640 - 80), |
| | |
| | | try { |
| | | System.Threading.Thread.Sleep (100); |
| | | Application.RunOnMainThread (() => { |
| | | var tt = new Timer () { TimeZone = Convert.ToInt32 (DateTime.Now.ToString ("%z")), RoomName = "ALL", Periodicity = ((int)DateTime.Now.DayOfWeek).ToString (), TimerType = TimerType.Week, TimerName = "Schedule " + timers.Count.ToString(), ExecutionTime = DateTime.Now.ToString ("HH:mm") }; |
| | | var timer = new Timer () { TimeZone = Convert.ToInt32 (DateTime.Now.ToString ("%z")),timerType = TimerType.Week, timerName = "Schedule " + timerList.Count.ToString(), executeUtcTime = DateTime.Now.ToString ("HH:mm") }; |
| | | Action<Timer> refLoad = (obj) => { |
| | | timers.Add (obj); |
| | | initSchedule (obj); |
| | | timerList.Add (obj); |
| | | InitSchedule (obj); |
| | | }; |
| | | var scheduleShowView = new AddSchedule (refLoad); |
| | | UserMiddle.SettingPageView.AddChidren (scheduleShowView); |
| | | scheduleShowView.ShowPage (tt,timers,false); |
| | | scheduleShowView.ShowPage (timer,timerList,false); |
| | | UserMiddle.SettingPageView.PageIndex = 2; |
| | | }); |
| | | }catch(Exception ex){ |
| | |
| | | BackgroundColor = SkinStyle.Current.ViewColor |
| | | }; |
| | | AddChidren (bodyView); |
| | | ///加载计数器列表界面 |
| | | InitScheduleView (); |
| | | } |
| | | |
| | | void InitScheduleView () |
| | | { |
| | | MainPage.Loading.Start ("Please wait..."); |
| | | System.Threading.Tasks.Task.Run (() => { |
| | | try { |
| | | var requestObj = new Timer () { RegionID = UserConfig.Instance.CurrentRegion.Id }; |
| | | var requestJson = Newtonsoft.Json.JsonConvert.SerializeObject (requestObj); |
| | | var revertObj = MainPage.RequestHttps (API.GetTimerList, requestJson); |
| | | if (revertObj.StateCode.ToUpper() == StateCode.SUCCESS) { |
| | | timers = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Timer>> (revertObj.ResponseData.ToString ()); |
| | | foreach (var schedule in timers) { |
| | | initSchedule (schedule); |
| | | } |
| | | } else { |
| | | //提示错误 |
| | | ShowGetTimerListErrorInfo (revertObj.StateCode); |
| | | } |
| | | } catch (Exception ex) { |
| | | Utlis.WriteLine (ex.Message); |
| | | } finally { |
| | | Application.RunOnMainThread (() => { |
| | | MainPage.Loading.Hide (); |
| | | }); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | //(1)Success 则调用此接口成功 |
| | | //(2)NoRecord 住宅未绑定网关! |
| | | //(3)NoExist 住宅不存在! |
| | | /// 显示的定时器列表界面 |
| | | /// </summary> |
| | | void ShowGetTimerListErrorInfo (string stateCodeStr) |
| | | { |
| | | string mes = ""; |
| | | if (stateCodeStr == "NoRecord") { |
| | | // 住宅未绑定网关! |
| | | mes = ErrorCode.HomeNoRecord; |
| | | } else if (stateCodeStr == "NoExist") { |
| | | //住宅不存在! |
| | | mes = ErrorCode.HomeNoExist; |
| | | } else if (stateCodeStr == ErrorCode.NetworkError) { |
| | | mes = ErrorCode.NetworkError; |
| | | } else { |
| | | mes = ErrorCode.OperationFailed + ErrorCode.Reason + stateCodeStr; |
| | | |
| | | } |
| | | if (!string.IsNullOrEmpty (mes)) { |
| | | Application.RunOnMainThread (() => { |
| | | new Alert ("", mes, Language.StringByID (R.MyInternationalizationString.Close)).Show (); |
| | | }); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | void reinitSchedule(Timer schedule) |
| | | { |
| | | for (int i = 0;i< bodyView.ChildrenCount;i++){ |
| | | var view = bodyView.GetChildren (i); |
| | | if(view.GetType() == typeof(RowLayout)){ |
| | | var rowView = view as RowLayout; |
| | | if (rowView.GetTagByKey("guid").ToString () == schedule.Id) { |
| | | for (int j = 0; j < rowView.ChildrenCount; j++) { |
| | | var viewChilren = rowView.GetChildren (j); |
| | | if (viewChilren.GetType () == typeof (Button)) { |
| | | var btn = viewChilren as Button; |
| | | if(btn.Tag!= null){ |
| | | switch (btn.Tag.ToString ()) { |
| | | case "btnScheduleName": |
| | | btn.Text = schedule.TimerName; |
| | | break; |
| | | case "btnScheduleRoomName": |
| | | btn.Text = schedule.RoomName; |
| | | break; |
| | | case "btnScheduleTime": |
| | | btn.Text = schedule.ExecutionTime; |
| | | break; |
| | | case "btnScheduleDay": |
| | | btn.Text = ""; |
| | | if (schedule.Periodicity.Contains ("0")) { |
| | | btn.Text += "Sun "; |
| | | } |
| | | if (schedule.Periodicity.Contains ("1")) { |
| | | btn.Text += "Mon "; |
| | | } |
| | | if (schedule.Periodicity.Contains ("2")) { |
| | | btn.Text += "Tues "; |
| | | } |
| | | if (schedule.Periodicity.Contains ("3")) { |
| | | btn.Text += "Wed "; |
| | | } |
| | | if (schedule.Periodicity.Contains ("4")) { |
| | | btn.Text += "Thur "; |
| | | } |
| | | if (schedule.Periodicity.Contains ("5")) { |
| | | btn.Text += "Fri "; |
| | | } |
| | | if (schedule.Periodicity.Contains ("6")) { |
| | | btn.Text += "Sat "; |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | void initSchedule(Timer schedule) |
| | | /// <param name="schedule"></param> |
| | | void InitSchedule (Timer schedule) |
| | | { |
| | | |
| | | Application.RunOnMainThread (() => { |
| | |
| | | Height = Application.GetRealHeight (180), |
| | | }; |
| | | bodyView.AddChidren (rowView); |
| | | rowView.AddTag ("guid", schedule.Id); |
| | | rowView.AddTag ("guid", schedule.id); |
| | | |
| | | var btnScheduleName = new Button () { |
| | | X = Application.GetRealWidth (30), |
| | |
| | | Width = Application.GetRealWidth (290), |
| | | TextAlignment = TextAlignment.CenterLeft, |
| | | TextColor = SkinStyle.Current.TextColor1, |
| | | Text = schedule.TimerName, |
| | | Text = schedule.timerName, |
| | | TextSize = 14, |
| | | Tag = "btnScheduleName", |
| | | }; |
| | | rowView.AddChidren (btnScheduleName); |
| | | btnScheduleName.AddTag ("guid", schedule.Id); |
| | | btnScheduleName.AddTag ("guid", schedule.id); |
| | | |
| | | var btnScheduleRoomName = new Button () { |
| | | X = btnScheduleName.Right, |
| | |
| | | Tag = "btnScheduleRoomName", |
| | | }; |
| | | rowView.AddChidren (btnScheduleRoomName); |
| | | btnScheduleRoomName.AddTag ("guid", schedule.Id); |
| | | btnScheduleRoomName.AddTag ("guid", schedule.id); |
| | | |
| | | var btnScheduleTime = new Button () { |
| | | X = Application.GetRealWidth (30), |
| | | Y = Application.GetRealHeight (60), |
| | | Height = Application.GetRealHeight (60), |
| | | Width = Application.GetRealWidth (150), |
| | | Text = schedule.ExecutionTime, |
| | | Text = schedule.executeUtcTime, |
| | | TextColor = SkinStyle.Current.TextColor1, |
| | | TextAlignment = TextAlignment.CenterLeft, |
| | | TextSize = 24, |
| | | Tag = "btnScheduleTime", |
| | | }; |
| | | rowView.AddChidren (btnScheduleTime); |
| | | btnScheduleTime.AddTag ("guid", schedule.Id); |
| | | btnScheduleTime.AddTag ("guid", schedule.id); |
| | | |
| | | var btnScheduleDay = new Button () { |
| | | X = Application.GetRealWidth (33), |
| | |
| | | Tag = "btnScheduleDay", |
| | | }; |
| | | rowView.AddChidren (btnScheduleDay); |
| | | btnScheduleDay.AddTag ("guid", schedule.Id); |
| | | btnScheduleDay.AddTag ("guid", schedule.id); |
| | | |
| | | if (schedule.Periodicity.Contains ("0")) { |
| | | if (schedule.whichDay.Contains (0)) { |
| | | btnScheduleDay.Text += "Sun "; |
| | | } |
| | | if (schedule.Periodicity.Contains ("1")) { |
| | | if (schedule.whichDay.Contains (1)) { |
| | | btnScheduleDay.Text += "Mon "; |
| | | } |
| | | if (schedule.Periodicity.Contains ("2")) { |
| | | if (schedule.whichDay.Contains (2)) { |
| | | btnScheduleDay.Text += "Tues "; |
| | | } |
| | | if (schedule.Periodicity.Contains ("3")) { |
| | | if (schedule.whichDay.Contains (3)) { |
| | | btnScheduleDay.Text += "Wed "; |
| | | } |
| | | if (schedule.Periodicity.Contains ("4")) { |
| | | if (schedule.whichDay.Contains (4)) { |
| | | btnScheduleDay.Text += "Thur "; |
| | | } |
| | | if (schedule.Periodicity.Contains ("5")) { |
| | | if (schedule.whichDay.Contains (5)) { |
| | | btnScheduleDay.Text += "Fri "; |
| | | } |
| | | if (schedule.Periodicity.Contains ("6")) { |
| | | if (schedule.whichDay.Contains (6)) { |
| | | btnScheduleDay.Text += "Sat "; |
| | | } |
| | | |
| | | var tempSiwtch = new Button () { |
| | | Width = Application.GetMinRealAverage (90), |
| | | Height = Application.GetMinRealAverage (53), |
| | | Width = Application.GetRealWidth (90), |
| | | Height = Application.GetRealWidth (53), |
| | | X = Application.GetRealWidth (640 - 90 - 20), |
| | | Y = Application.GetRealHeight (100), |
| | | UnSelectedImagePath = "Item/SwitchClose.png", |
| | | SelectedImagePath = "Item/SwitchOpen.png", |
| | | IsSelected = schedule.IsStart, |
| | | Tag = schedule.Id |
| | | IsSelected = schedule.isEnable, |
| | | Tag = schedule.id |
| | | }; |
| | | rowView.AddChidren (tempSiwtch); |
| | | |
| | | tempSiwtch.MouseUpEventHandler += (sdd, ffd) => { |
| | | tempSiwtch.IsSelected = !tempSiwtch.IsSelected; |
| | | MainPage.Loading.Start ("Loading"); |
| | | System.Threading.Tasks.Task.Run (() => { |
| | | try { |
| | | var switchObj = new Timer () { Id = (sdd as Button).Tag.ToString () }; |
| | | var switchRequestJson = Newtonsoft.Json.JsonConvert.SerializeObject (switchObj); |
| | | var switchRevertObj = MainPage.RequestHttps (API.IsEnableTimer, switchRequestJson); |
| | | if (switchRevertObj.StateCode.ToUpper() != StateCode.SUCCESS) { |
| | | |
| | | var switchRevertObj =SmartHome.Send.SwitchTimer (schedule); |
| | | if (switchRevertObj.Code== StateCode.SUCCESS) { |
| | | Application.RunOnMainThread (() => { |
| | | tempSiwtch.IsSelected = !tempSiwtch.IsSelected; |
| | | }); |
| | |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | Button btnDel = new Button () { |
| | | TextID = R.MyInternationalizationString.Del, |
| | | BackgroundColor = SkinStyle.Current.DelColor, |
| | | Tag = schedule.Id |
| | | Tag = schedule.id |
| | | }; |
| | | rowView.AddRightView (btnDel); |
| | | btnDel.MouseUpEventHandler += (sender, er) => { |
| | | if ((sender as Button).Tag == null) return; |
| | | //string uuid = (sender as Button).Tag.ToString (); |
| | | |
| | | DeleteTimerAction ((sender as Button).Tag.ToString (), rowView, true); |
| | | //var delObj = new Timer () { Guid = (sender as Button).Tag.ToString () }; |
| | | //var delRequestJson = Newtonsoft.Json.JsonConvert.SerializeObject (delObj); |
| | | //var delRevertObj = MainPage.RequestHttps ("DeleteTimer", delRequestJson); |
| | | //if (delRevertObj.StateCode.ToUpper() == StateCode.SUCCESS) { |
| | | // rowView.RemoveFromParent (); |
| | | // timers.Remove (timers.Find((obj) => obj.Guid == delObj.Guid)); |
| | | //} |
| | | |
| | | }; |
| | | |
| | | #region goSchedule |
| | | |
| | | EventHandler<MouseEventArgs> eventHandler = (sender, er) => { |
| | | Action<Timer> refLoad = (obj) => { |
| | | reinitSchedule (obj); |
| | | ReinitSchedule (obj); |
| | | }; |
| | | var scheduleShowView = new AddSchedule (refLoad); |
| | | UserMiddle.SettingPageView.AddChidren (scheduleShowView); |
| | | scheduleShowView.ShowPage (schedule, timers, true); |
| | | scheduleShowView.ShowPage (schedule, timerList, true); |
| | | UserMiddle.SettingPageView.PageIndex = 2; |
| | | }; |
| | | |
| | |
| | | #endregion |
| | | #region delSchedule |
| | | |
| | | btnScheduleName.MouseLongEventHandler += (sender, e) => { |
| | | var alert = new Alert ("",Language.StringByID (R.MyInternationalizationString.SureDelete), |
| | | EventHandler<MouseEventArgs> Del = (sender, er) => { |
| | | var alert = new Alert ("", Language.StringByID (R.MyInternationalizationString.SureDelete), |
| | | Language.StringByID (R.MyInternationalizationString.Cancel), |
| | | Language.StringByID (R.MyInternationalizationString.Confrim)); |
| | | alert.Show (); |
| | |
| | | DeleteTimerAction ((sender as Button).GetTagByKey ("guid").ToString (), rowView); |
| | | } |
| | | }; |
| | | }; |
| | | btnScheduleTime.MouseLongEventHandler += (sender, e) => { |
| | | var alert = new Alert ("", |
| | | Language.StringByID (R.MyInternationalizationString.SureDelete), |
| | | Language.StringByID (R.MyInternationalizationString.Cancel), |
| | | Language.StringByID (R.MyInternationalizationString.Confrim)); |
| | | alert.Show (); |
| | | alert.ResultEventHandler += (sender2, e2) => { |
| | | if (e2) { |
| | | if ((sender as Button).GetTagByKey ("guid") == null) return; |
| | | DeleteTimerAction ((sender as Button).GetTagByKey ("guid").ToString (), rowView); |
| | | } |
| | | }; |
| | | }; |
| | | btnScheduleDay.MouseLongEventHandler += (sender, e) => { |
| | | var alert = new Alert ("", |
| | | Language.StringByID (R.MyInternationalizationString.SureDelete), |
| | | Language.StringByID (R.MyInternationalizationString.Cancel), |
| | | Language.StringByID (R.MyInternationalizationString.Confrim)); |
| | | alert.Show (); |
| | | alert.ResultEventHandler += (sender2, e2) => { |
| | | if (e2) { |
| | | if ((sender as Button).GetTagByKey ("guid") == null) return; |
| | | DeleteTimerAction ((sender as Button).GetTagByKey ("guid").ToString (), rowView); |
| | | } |
| | | }; |
| | | }; |
| | | #endregion |
| | | }; |
| | | |
| | | btnScheduleName.MouseLongEventHandler += Del; |
| | | btnScheduleTime.MouseLongEventHandler += Del; |
| | | btnScheduleDay.MouseLongEventHandler += Del; |
| | | #endregion |
| | | |
| | | }); |
| | | |
| | | } |
| | | /// <summary> |
| | | /// 更新的定时器状态 |
| | | /// </summary> |
| | | /// <param name="schedule"></param> |
| | | void ReinitSchedule (Timer schedule) |
| | | { |
| | | for (int i = 0; i < bodyView.ChildrenCount; i++) { |
| | | var view = bodyView.GetChildren (i); |
| | | if (view.GetType () == typeof (RowLayout)) { |
| | | var rowView = view as RowLayout; |
| | | if (rowView.GetTagByKey ("guid").ToString () == schedule.id.ToString ()) { |
| | | for (int j = 0; j < rowView.ChildrenCount; j++) { |
| | | var viewChilren = rowView.GetChildren (j); |
| | | if (viewChilren.GetType () == typeof (Button)) { |
| | | var btn = viewChilren as Button; |
| | | if (btn.Tag != null) { |
| | | switch (btn.Tag.ToString ()) { |
| | | case "btnScheduleName": |
| | | btn.Text = schedule.timerName; |
| | | break; |
| | | case "btnScheduleRoomName": |
| | | btn.Text = schedule.RoomName; |
| | | break; |
| | | case "btnScheduleTime": |
| | | btn.Text = schedule.executeUtcTime; |
| | | break; |
| | | case "btnScheduleDay": |
| | | btn.Text = ""; |
| | | if (schedule.whichDay.Contains (0)) { |
| | | btn.Text += "Sun "; |
| | | } |
| | | if (schedule.whichDay.Contains (1)) { |
| | | btn.Text += "Mon "; |
| | | } |
| | | if (schedule.whichDay.Contains (2)) { |
| | | btn.Text += "Tues "; |
| | | } |
| | | if (schedule.whichDay.Contains (3)) { |
| | | btn.Text += "Wed "; |
| | | } |
| | | if (schedule.whichDay.Contains (4)) { |
| | | btn.Text += "Thur "; |
| | | } |
| | | if (schedule.whichDay.Contains (5)) { |
| | | btn.Text += "Fri "; |
| | | } |
| | | if (schedule.whichDay.Contains (6)) { |
| | | btn.Text += "Sat "; |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// 读取定时器列表 |
| | | /// </summary> |
| | | void InitScheduleView () |
| | | { |
| | | SmartHome.Method.GetDeviceList (); |
| | | MainPage.Loading.Start ("Please wait..."); |
| | | System.Threading.Tasks.Task.Run (() => { |
| | | try { |
| | | var revertObj = SmartHome.Send.GetTimerList (); |
| | | if (revertObj.Code == StateCode.SUCCESS) { |
| | | if (revertObj.Data == null) { |
| | | return; |
| | | } |
| | | if (string.IsNullOrEmpty (revertObj.Data.ToString ())) { |
| | | return; |
| | | } |
| | | var jsonDate = Newtonsoft.Json.Linq.JObject.Parse (revertObj.Data.ToString ()); |
| | | var array = jsonDate ["list"].ToString (); |
| | | var jArray = Newtonsoft.Json.Linq.JArray.Parse (array); |
| | | for (int a = 0; a < jArray.Count; a++) { |
| | | Timer timer = new Timer (); |
| | | var jay = jArray [a]; |
| | | timer.id = jay ["id"].ToString (); |
| | | timer.timerName =jay ["timerName"].ToString (); |
| | | timer.RoomName = jay ["room"].ToString (); |
| | | timer.userId = jay ["userId"].ToString (); |
| | | timer.isEnable = Boolean.Parse (jay ["isEnable"].ToString ()); |
| | | timer.executeUtcTime = SmartHome.Method.GetLocalUtcTime(jay ["executeUtcTime"].ToString ()); |
| | | timer.timerType = (TimerType)System.Enum.Parse (typeof (TimerType), jay ["timerType"].ToString ()); |
| | | var whichDayJson = jay ["whichDay"].ToString (); |
| | | var whichDayAry = Newtonsoft.Json.Linq.JArray.Parse (whichDayJson); |
| | | for (int b = 0; b < whichDayAry.Count; b++) { |
| | | var days = whichDayAry [b].ToString (); |
| | | timer.whichDay.Add (int.Parse (days)); |
| | | } |
| | | var controlDataStr = jay ["controlData"].ToString (); |
| | | var controlDataJosn = Newtonsoft.Json.JsonConvert.DeserializeObject<DeviceDate> (controlDataStr); |
| | | if (controlDataJosn != null) { |
| | | timer.controlData = controlDataJosn; |
| | | } |
| | | var timerJosn = timerList.Find ((c) => c.id == timer.id); |
| | | if (timerJosn == null && !string.IsNullOrEmpty (timer.id)) { |
| | | timerList.Add (timer); |
| | | } |
| | | } |
| | | |
| | | } else { |
| | | //提示错误 |
| | | IMessageCommon.Current.ShowErrorInfoAlter (revertObj.Code); |
| | | |
| | | //SmartHome.Method method = new SmartHome.Method (); |
| | | //method.ShowGetTimerListErrorInfo (revertObj.Data.ToString ()); |
| | | } |
| | | } catch (Exception ex) { |
| | | Utlis.WriteLine (ex.Message); |
| | | } finally { |
| | | Application.RunOnMainThread (() => { |
| | | MainPage.Loading.Hide (); |
| | | for (int i = 0; i < timerList.Count; i++) { |
| | | var schedule = timerList [i]; |
| | | InitSchedule (schedule); |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | | } |
| | | /// <summary> |
| | | /// 删除定时器 |
| | | /// </summary> |
| | |
| | | Application.RunOnMainThread (() => { |
| | | MainPage.Loading.Start ("Please wait..."); |
| | | }); |
| | | |
| | | var delObj = new Timer () { Id = GUID }; |
| | | var delRequestJson = Newtonsoft.Json.JsonConvert.SerializeObject (delObj); |
| | | var delRevertObj = MainPage.RequestHttps (API.DeleteTimer, delRequestJson); |
| | | |
| | | |
| | | if (delRevertObj.StateCode.ToUpper () == StateCode.SUCCESS) { |
| | | var delRevertObj =SmartHome.Send.DelTimer (GUID); |
| | | if (delRevertObj.Code == StateCode.SUCCESS) { |
| | | rowView.RemoveFromParent (); |
| | | if (bTimersRemove) { |
| | | timers.Remove (timers.Find ((obj) => obj.Id == delObj.Id)); |
| | | timerList.Remove (timerList.Find ((obj) => obj.id.ToString() == GUID)); |
| | | } |
| | | } else { |
| | | //删除失败 |
| | |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | } |
| | | } |