| StephaneLenclud@123 |      1 | //
 | 
| StephaneLenclud@123 |      2 | // Copyright (C) 2014-2015 Stéphane Lenclud.
 | 
| StephaneLenclud@123 |      3 | //
 | 
| StephaneLenclud@123 |      4 | // This file is part of SharpDisplayManager.
 | 
| StephaneLenclud@123 |      5 | //
 | 
| StephaneLenclud@123 |      6 | // SharpDisplayManager is free software: you can redistribute it and/or modify
 | 
| StephaneLenclud@123 |      7 | // it under the terms of the GNU General Public License as published by
 | 
| StephaneLenclud@123 |      8 | // the Free Software Foundation, either version 3 of the License, or
 | 
| StephaneLenclud@123 |      9 | // (at your option) any later version.
 | 
| StephaneLenclud@123 |     10 | //
 | 
| StephaneLenclud@123 |     11 | // SharpDisplayManager is distributed in the hope that it will be useful,
 | 
| StephaneLenclud@123 |     12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
| StephaneLenclud@123 |     13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
| StephaneLenclud@123 |     14 | // GNU General Public License for more details.
 | 
| StephaneLenclud@123 |     15 | //
 | 
| StephaneLenclud@123 |     16 | // You should have received a copy of the GNU General Public License
 | 
| StephaneLenclud@123 |     17 | // along with SharpDisplayManager.  If not, see <http://www.gnu.org/licenses/>.
 | 
| StephaneLenclud@123 |     18 | //
 | 
| StephaneLenclud@123 |     19 | 
 | 
| StephaneLenclud@123 |     20 | using System;
 | 
| sl@3 |     21 | using System.Collections.Generic;
 | 
| sl@3 |     22 | using System.Linq;
 | 
| sl@3 |     23 | using System.Text;
 | 
| sl@3 |     24 | using System.Threading.Tasks;
 | 
| sl@3 |     25 | //
 | 
| sl@3 |     26 | using System.Runtime.InteropServices;
 | 
| sl@46 |     27 | //using System.Runtime.Serialization;
 | 
| sl@3 |     28 | 
 | 
| StephaneLenclud@135 |     29 | using MiniDisplayInterop;
 | 
| StephaneLenclud@135 |     30 | 
 | 
| sl@3 |     31 | namespace SharpDisplayManager
 | 
| sl@3 |     32 | {
 | 
| sl@46 |     33 | 
 | 
| StephaneLenclud@104 |     34 | 
 | 
| sl@44 |     35 |     /// <summary>
 | 
| sl@44 |     36 |     /// Provide access to our display hardware through MiniDisplay API.
 | 
| sl@44 |     37 |     /// </summary>
 | 
| sl@46 |     38 |     public class Display
 | 
| sl@3 |     39 |     {
 | 
| StephaneLenclud@104 |     40 | 		public delegate void OnOpenedHandler(Display aDisplay);
 | 
| StephaneLenclud@104 |     41 | 		public event OnOpenedHandler OnOpened;
 | 
| StephaneLenclud@104 |     42 | 
 | 
| StephaneLenclud@104 |     43 | 		public delegate void OnClosedHandler(Display aDisplay);
 | 
| StephaneLenclud@104 |     44 | 		public event OnClosedHandler OnClosed;
 | 
| StephaneLenclud@104 |     45 | 
 | 
| StephaneLenclud@104 |     46 | 		//Our display device handle
 | 
| StephaneLenclud@104 |     47 | 		IntPtr iDevice;
 | 
| StephaneLenclud@104 |     48 | 
 | 
| StephaneLenclud@104 |     49 | 		//static functions
 | 
| StephaneLenclud@104 |     50 | 		public static int TypeCount()
 | 
| StephaneLenclud@104 |     51 | 		{
 | 
| StephaneLenclud@135 |     52 | 			return MiniDisplay.TypeCount();
 | 
| StephaneLenclud@104 |     53 | 		}
 | 
| StephaneLenclud@104 |     54 | 
 | 
| StephaneLenclud@135 |     55 | 		public static string TypeName(MiniDisplay.Type aType)
 | 
| StephaneLenclud@104 |     56 | 		{
 | 
| StephaneLenclud@135 |     57 | 			IntPtr ptr = MiniDisplay.TypeName(aType);
 | 
| StephaneLenclud@104 |     58 | 			string str = Marshal.PtrToStringUni(ptr);
 | 
| StephaneLenclud@104 |     59 | 			return str;
 | 
| StephaneLenclud@104 |     60 | 		}
 | 
| sl@3 |     61 | 
 | 
| sl@3 |     62 |         //Constructor
 | 
| sl@3 |     63 |         public Display()
 | 
| sl@3 |     64 |         {
 | 
| sl@3 |     65 |             iDevice = IntPtr.Zero;
 | 
| sl@3 |     66 |         }
 | 
| sl@3 |     67 | 
 | 
| sl@3 |     68 |         //
 | 
| StephaneLenclud@135 |     69 |         public bool Open(MiniDisplay.Type aType)
 | 
| sl@3 |     70 |         {
 | 
| StephaneLenclud@104 |     71 | 			if (IsOpen())
 | 
| StephaneLenclud@104 |     72 | 			{
 | 
| StephaneLenclud@104 |     73 | 				//Already open return an error
 | 
| StephaneLenclud@104 |     74 | 				return false;
 | 
| StephaneLenclud@104 |     75 | 			}
 | 
| StephaneLenclud@104 |     76 | 
 | 
| StephaneLenclud@135 |     77 |             iDevice = MiniDisplay.Open(aType);
 | 
| StephaneLenclud@104 |     78 | 
 | 
| StephaneLenclud@104 |     79 |             bool success = iDevice != IntPtr.Zero;
 | 
| StephaneLenclud@104 |     80 | 			if (success)
 | 
| StephaneLenclud@104 |     81 | 			{
 | 
| StephaneLenclud@104 |     82 | 				//Broadcast opened event
 | 
| StephaneLenclud@104 |     83 | 				OnOpened(this);
 | 
| StephaneLenclud@104 |     84 | 			}
 | 
| StephaneLenclud@104 |     85 | 
 | 
| StephaneLenclud@104 |     86 | 			return success;
 | 
| sl@3 |     87 |         }
 | 
| sl@3 |     88 | 
 | 
| sl@3 |     89 |         public void Close()
 | 
| sl@3 |     90 |         {
 | 
| StephaneLenclud@104 |     91 | 			if (!IsOpen())
 | 
| StephaneLenclud@104 |     92 | 			{
 | 
| StephaneLenclud@104 |     93 | 				//Pointless
 | 
| StephaneLenclud@104 |     94 | 				return;
 | 
| StephaneLenclud@104 |     95 | 			}
 | 
| StephaneLenclud@104 |     96 | 
 | 
| StephaneLenclud@105 |     97 | 			//
 | 
| StephaneLenclud@135 |     98 |             MiniDisplay.Close(iDevice);
 | 
| sl@3 |     99 |             iDevice = IntPtr.Zero;
 | 
| StephaneLenclud@104 |    100 | 			//Broadcast closed event
 | 
| StephaneLenclud@104 |    101 | 			OnClosed(this);
 | 
| sl@3 |    102 |         }
 | 
| sl@3 |    103 | 
 | 
| sl@3 |    104 |         public bool IsOpen()
 | 
| sl@3 |    105 |         {
 | 
| sl@3 |    106 |             return iDevice != IntPtr.Zero;
 | 
| sl@3 |    107 |         }
 | 
| sl@3 |    108 | 
 | 
| sl@3 |    109 |         public void Clear()
 | 
| sl@3 |    110 |         {
 | 
| StephaneLenclud@135 |    111 |             MiniDisplay.Clear(iDevice);
 | 
| sl@3 |    112 |         }
 | 
| sl@3 |    113 | 
 | 
| sl@3 |    114 |         public void Fill()
 | 
| sl@3 |    115 |         {
 | 
| StephaneLenclud@135 |    116 |             MiniDisplay.Fill(iDevice);
 | 
| sl@3 |    117 |         }
 | 
| sl@3 |    118 | 
 | 
| sl@3 |    119 |         public void SwapBuffers()
 | 
| sl@3 |    120 |         {
 | 
| StephaneLenclud@135 |    121 |             MiniDisplay.SwapBuffers(iDevice);
 | 
| sl@3 |    122 |         }
 | 
| sl@3 |    123 | 
 | 
| sl@3 |    124 |         public int MaxBrightness()
 | 
| sl@3 |    125 |         {
 | 
| StephaneLenclud@135 |    126 |             return MiniDisplay.MaxBrightness(iDevice);
 | 
| sl@3 |    127 |         }
 | 
| sl@3 |    128 | 
 | 
| sl@3 |    129 |         public int MinBrightness()
 | 
| sl@3 |    130 |         {
 | 
| StephaneLenclud@135 |    131 |             return MiniDisplay.MinBrightness(iDevice);
 | 
| sl@3 |    132 |         }
 | 
| sl@3 |    133 | 
 | 
| sl@3 |    134 |         public void SetBrightness(int aBrightness)
 | 
| sl@3 |    135 |         {
 | 
| sl@3 |    136 |             if (!IsOpen()) return;
 | 
| sl@3 |    137 | 
 | 
| StephaneLenclud@135 |    138 |             MiniDisplay.SetBrightness(iDevice, aBrightness);
 | 
| sl@3 |    139 |         }
 | 
| sl@3 |    140 | 
 | 
| sl@4 |    141 |         public int WidthInPixels()
 | 
| sl@4 |    142 |         {
 | 
| StephaneLenclud@135 |    143 |             return MiniDisplay.WidthInPixels(iDevice);
 | 
| sl@4 |    144 |         }
 | 
| sl@4 |    145 | 
 | 
| sl@4 |    146 |         public int HeightInPixels()
 | 
| sl@4 |    147 |         {
 | 
| StephaneLenclud@135 |    148 |             return MiniDisplay.HeightInPixels(iDevice);
 | 
| sl@4 |    149 |         }
 | 
| sl@4 |    150 | 
 | 
| sl@57 |    151 |         public void SetPixel(int aX, int aY, uint aValue)
 | 
| sl@4 |    152 |         {
 | 
| StephaneLenclud@135 |    153 |             MiniDisplay.SetPixel(iDevice,aX,aY,aValue);
 | 
| sl@4 |    154 |         }
 | 
| sl@4 |    155 | 
 | 
| sl@12 |    156 |         public void RequestPowerSupplyStatus()
 | 
| sl@12 |    157 |         {
 | 
| StephaneLenclud@135 |    158 |             MiniDisplay.SendRequest(iDevice, MiniDisplay.Request.PowerSupplyStatus);
 | 
| sl@12 |    159 |         }
 | 
| sl@12 |    160 | 
 | 
| sl@12 |    161 |         public void RequestDeviceId()
 | 
| sl@12 |    162 |         {
 | 
| StephaneLenclud@135 |    163 |             MiniDisplay.SendRequest(iDevice, MiniDisplay.Request.DeviceId);
 | 
| sl@12 |    164 |         }
 | 
| sl@12 |    165 | 
 | 
| sl@12 |    166 |         public void RequestFirmwareRevision()
 | 
| sl@12 |    167 |         {
 | 
| StephaneLenclud@135 |    168 |             MiniDisplay.SendRequest(iDevice, MiniDisplay.Request.FirmwareRevision);
 | 
| sl@12 |    169 |         }
 | 
| sl@12 |    170 | 
 | 
| sl@52 |    171 |         public void PowerOn()
 | 
| sl@52 |    172 |         {
 | 
| StephaneLenclud@135 |    173 |             MiniDisplay.PowerOn(iDevice);
 | 
| sl@52 |    174 |         }
 | 
| sl@52 |    175 | 
 | 
| sl@52 |    176 |         public void PowerOff()
 | 
| sl@52 |    177 |         {
 | 
| StephaneLenclud@135 |    178 |             MiniDisplay.PowerOff(iDevice);
 | 
| sl@52 |    179 |         }
 | 
| sl@52 |    180 | 
 | 
| sl@52 |    181 |         public bool SupportPowerOnOff()
 | 
| sl@52 |    182 |         {
 | 
| StephaneLenclud@135 |    183 |             return MiniDisplay.SupportPowerOnOff(iDevice);
 | 
| sl@52 |    184 |         }
 | 
| sl@52 |    185 | 
 | 
| sl@53 |    186 |         public void ShowClock()
 | 
| sl@53 |    187 |         {
 | 
| StephaneLenclud@135 |    188 |             MiniDisplay.ShowClock(iDevice);
 | 
| sl@53 |    189 |         }
 | 
| sl@53 |    190 | 
 | 
| sl@53 |    191 |         public void HideClock()
 | 
| sl@53 |    192 |         {
 | 
| StephaneLenclud@135 |    193 |             MiniDisplay.HideClock(iDevice);
 | 
| sl@53 |    194 |         }
 | 
| sl@53 |    195 | 
 | 
| sl@53 |    196 |         public bool SupportClock()
 | 
| sl@53 |    197 |         {
 | 
| StephaneLenclud@135 |    198 |             return MiniDisplay.SupportClock(iDevice);
 | 
| sl@53 |    199 |         }
 | 
| sl@53 |    200 | 
 | 
| sl@12 |    201 |         public bool PowerSupplyStatus()
 | 
| sl@12 |    202 |         {
 | 
| StephaneLenclud@135 |    203 |             bool res = MiniDisplay.PowerSupplyStatus(iDevice);
 | 
| sl@12 |    204 |             return res;
 | 
| sl@12 |    205 |         }
 | 
| sl@12 |    206 | 
 | 
| StephaneLenclud@135 |    207 |         public MiniDisplay.Request AttemptRequestCompletion()
 | 
| sl@12 |    208 |         {
 | 
| StephaneLenclud@135 |    209 |             return MiniDisplay.AttemptRequestCompletion(iDevice);
 | 
| sl@12 |    210 |         }
 | 
| sl@12 |    211 | 
 | 
| StephaneLenclud@135 |    212 |         public MiniDisplay.Request CurrentRequest()
 | 
| sl@12 |    213 |         {
 | 
| StephaneLenclud@135 |    214 |             return MiniDisplay.CurrentRequest(iDevice);
 | 
| sl@12 |    215 |         }
 | 
| sl@12 |    216 | 
 | 
| sl@12 |    217 |         public bool IsRequestPending()
 | 
| sl@12 |    218 |         {
 | 
| StephaneLenclud@135 |    219 |             return CurrentRequest() != MiniDisplay.Request.None;
 | 
| sl@12 |    220 |         }
 | 
| sl@12 |    221 | 
 | 
| StephaneLenclud@108 |    222 | 		//
 | 
| StephaneLenclud@135 |    223 | 		public int IconCount(MiniDisplay.IconType aIcon)
 | 
| StephaneLenclud@108 |    224 | 		{
 | 
| StephaneLenclud@135 |    225 | 			return MiniDisplay.IconCount(iDevice,aIcon);
 | 
| StephaneLenclud@108 |    226 | 		}
 | 
| StephaneLenclud@108 |    227 | 
 | 
| StephaneLenclud@135 |    228 | 		public int IconStatusCount(MiniDisplay.IconType aIcon)
 | 
| StephaneLenclud@108 |    229 | 		{
 | 
| StephaneLenclud@135 |    230 | 			return MiniDisplay.IconStatusCount(iDevice, aIcon);
 | 
| StephaneLenclud@108 |    231 | 		}
 | 
| StephaneLenclud@108 |    232 | 
 | 
| StephaneLenclud@135 |    233 | 		public void SetIconStatus(MiniDisplay.IconType aIcon, int aIndex, int aStatus)
 | 
| StephaneLenclud@108 |    234 | 		{
 | 
| StephaneLenclud@135 |    235 | 			MiniDisplay.SetIconStatus(iDevice, aIcon, aIndex, aStatus);
 | 
| StephaneLenclud@108 |    236 | 		}
 | 
| StephaneLenclud@108 |    237 | 
 | 
| StephaneLenclud@135 |    238 | 		public void SetIconOn(MiniDisplay.IconType aIcon, int aIndex)
 | 
| StephaneLenclud@118 |    239 | 		{
 | 
| StephaneLenclud@135 |    240 | 			MiniDisplay.SetIconStatus(iDevice, aIcon, aIndex, IconStatusCount(aIcon) - 1);
 | 
| StephaneLenclud@118 |    241 | 		}
 | 
| StephaneLenclud@118 |    242 | 
 | 
| StephaneLenclud@135 |    243 | 		public void SetIconOff(MiniDisplay.IconType aIcon, int aIndex)
 | 
| StephaneLenclud@118 |    244 | 		{
 | 
| StephaneLenclud@135 |    245 | 			MiniDisplay.SetIconStatus(iDevice, aIcon, aIndex, 0);
 | 
| StephaneLenclud@118 |    246 | 		}
 | 
| StephaneLenclud@118 |    247 | 
 | 
| StephaneLenclud@118 |    248 | 
 | 
| StephaneLenclud@109 |    249 | 		public void SetAllIconsStatus(int aStatus)
 | 
| StephaneLenclud@108 |    250 | 		{
 | 
| StephaneLenclud@135 |    251 | 			foreach (MiniDisplay.IconType icon in Enum.GetValues(typeof(MiniDisplay.IconType)))
 | 
| StephaneLenclud@109 |    252 | 			{
 | 
| StephaneLenclud@109 |    253 | 				int count=IconCount(icon);
 | 
| StephaneLenclud@109 |    254 | 				for (int i = 0; i < count; i++)
 | 
| StephaneLenclud@109 |    255 | 				{
 | 
| StephaneLenclud@109 |    256 | 					SetIconStatus(icon,i,aStatus);
 | 
| StephaneLenclud@109 |    257 | 				}
 | 
| StephaneLenclud@109 |    258 | 			}
 | 
| StephaneLenclud@108 |    259 | 		}
 | 
| StephaneLenclud@108 |    260 | 
 | 
| StephaneLenclud@115 |    261 | 		/// <summary>
 | 
| StephaneLenclud@116 |    262 | 		/// Set all elements of an icon to the given status.
 | 
| StephaneLenclud@115 |    263 | 		/// </summary>
 | 
| StephaneLenclud@115 |    264 | 		/// <param name="aIcon"></param>
 | 
| StephaneLenclud@115 |    265 | 		/// <param name="aStatus"></param>
 | 
| StephaneLenclud@135 |    266 | 		public void SetIconStatus(MiniDisplay.IconType aIcon, int aStatus)
 | 
| StephaneLenclud@115 |    267 | 		{
 | 
| StephaneLenclud@115 |    268 | 			int iconCount = IconCount(aIcon);
 | 
| StephaneLenclud@115 |    269 | 			for (int i = 0; i < iconCount; i++)
 | 
| StephaneLenclud@115 |    270 | 			{
 | 
| StephaneLenclud@115 |    271 | 				SetIconStatus(aIcon, i, aStatus);
 | 
| StephaneLenclud@115 |    272 | 			}
 | 
| StephaneLenclud@115 |    273 | 		}
 | 
| StephaneLenclud@115 |    274 | 
 | 
| StephaneLenclud@115 |    275 | 		/// <summary>
 | 
| StephaneLenclud@116 |    276 | 		/// Set all elements of an icon to be either on or off.
 | 
| StephaneLenclud@116 |    277 | 		/// </summary>
 | 
| StephaneLenclud@116 |    278 | 		/// <param name="aIcon"></param>
 | 
| StephaneLenclud@116 |    279 | 		/// <param name="aOn"></param>		
 | 
| StephaneLenclud@135 |    280 | 		public void SetIconOnOff(MiniDisplay.IconType aIcon, bool aOn)
 | 
| StephaneLenclud@116 |    281 | 		{
 | 
| StephaneLenclud@116 |    282 | 			if (aOn)
 | 
| StephaneLenclud@116 |    283 | 			{
 | 
| StephaneLenclud@116 |    284 | 				SetIconOn(aIcon);
 | 
| StephaneLenclud@116 |    285 | 			}
 | 
| StephaneLenclud@116 |    286 | 			else
 | 
| StephaneLenclud@116 |    287 | 			{
 | 
| StephaneLenclud@116 |    288 | 				SetIconOff(aIcon);
 | 
| StephaneLenclud@116 |    289 | 			}
 | 
| StephaneLenclud@116 |    290 | 		}
 | 
| StephaneLenclud@116 |    291 | 
 | 
| StephaneLenclud@116 |    292 | 		/// <summary>
 | 
| StephaneLenclud@116 |    293 | 		/// Set all elements of an icon to there maximum status.
 | 
| StephaneLenclud@115 |    294 | 		/// </summary>
 | 
| StephaneLenclud@115 |    295 | 		/// <param name="aIcon"></param>
 | 
| StephaneLenclud@135 |    296 | 		public void SetIconOn(MiniDisplay.IconType aIcon)
 | 
| StephaneLenclud@115 |    297 | 		{
 | 
| StephaneLenclud@115 |    298 | 			int iconCount = IconCount(aIcon);
 | 
| StephaneLenclud@115 |    299 | 			for (int i = 0; i < iconCount; i++)
 | 
| StephaneLenclud@115 |    300 | 			{
 | 
| StephaneLenclud@115 |    301 | 				SetIconStatus(aIcon, i, IconStatusCount(aIcon) - 1);
 | 
| StephaneLenclud@115 |    302 | 			}
 | 
| StephaneLenclud@115 |    303 | 		}
 | 
| StephaneLenclud@115 |    304 | 
 | 
| StephaneLenclud@115 |    305 | 		/// <summary>
 | 
| StephaneLenclud@116 |    306 | 		/// Turn off all elements of an icon.
 | 
| StephaneLenclud@115 |    307 | 		/// </summary>
 | 
| StephaneLenclud@115 |    308 | 		/// <param name="aIcon"></param>
 | 
| StephaneLenclud@135 |    309 | 		public void SetIconOff(MiniDisplay.IconType aIcon)
 | 
| StephaneLenclud@115 |    310 | 		{
 | 
| StephaneLenclud@115 |    311 | 			int iconCount = IconCount(aIcon);
 | 
| StephaneLenclud@115 |    312 | 			for (int i = 0; i < iconCount; i++)
 | 
| StephaneLenclud@115 |    313 | 			{
 | 
| StephaneLenclud@115 |    314 | 				SetIconStatus(aIcon, i, 0);
 | 
| StephaneLenclud@115 |    315 | 			}
 | 
| StephaneLenclud@115 |    316 | 		}
 | 
| StephaneLenclud@115 |    317 | 
 | 
| StephaneLenclud@108 |    318 | 
 | 
| sl@12 |    319 | 
 | 
| sl@10 |    320 |         public string Vendor()
 | 
| sl@10 |    321 |         {
 | 
| StephaneLenclud@135 |    322 |             IntPtr ptr = MiniDisplay.Vendor(iDevice);
 | 
| sl@10 |    323 |             string str = Marshal.PtrToStringUni(ptr);
 | 
| sl@10 |    324 |             return str;
 | 
| sl@10 |    325 |         }
 | 
| sl@4 |    326 | 
 | 
| sl@10 |    327 |         public string Product()
 | 
| sl@10 |    328 |         {
 | 
| StephaneLenclud@135 |    329 |             IntPtr ptr = MiniDisplay.Product(iDevice);
 | 
| sl@10 |    330 |             string str = Marshal.PtrToStringUni(ptr);
 | 
| sl@10 |    331 |             return str;
 | 
| sl@10 |    332 |         }
 | 
| sl@10 |    333 | 
 | 
| sl@10 |    334 |         public string SerialNumber()
 | 
| sl@10 |    335 |         {
 | 
| StephaneLenclud@135 |    336 |             IntPtr ptr = MiniDisplay.SerialNumber(iDevice);
 | 
| sl@10 |    337 |             string str = Marshal.PtrToStringUni(ptr);
 | 
| sl@10 |    338 |             return str;
 | 
| sl@10 |    339 |         }
 | 
| sl@4 |    340 | 
 | 
| sl@12 |    341 |         public string DeviceId()
 | 
| sl@12 |    342 |         {
 | 
| StephaneLenclud@135 |    343 |             IntPtr ptr = MiniDisplay.DeviceId(iDevice);
 | 
| sl@12 |    344 |             string str = Marshal.PtrToStringAnsi(ptr);
 | 
| sl@12 |    345 |             return str;
 | 
| sl@12 |    346 |         }
 | 
| sl@12 |    347 | 
 | 
| sl@12 |    348 |         public string FirmwareRevision()
 | 
| sl@12 |    349 |         {
 | 
| StephaneLenclud@135 |    350 |             IntPtr ptr = MiniDisplay.FirmwareRevision(iDevice);
 | 
| sl@12 |    351 |             string str = Marshal.PtrToStringAnsi(ptr);
 | 
| sl@12 |    352 |             return str;
 | 
| sl@12 |    353 |         }
 | 
| sl@12 |    354 | 
 | 
| sl@53 |    355 | 
 | 
| sl@3 |    356 |     }
 | 
| sl@3 |    357 | }
 |