sl@0
|
1 |
// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
|
sl@0
|
2 |
// All rights reserved.
|
sl@0
|
3 |
// This component and the accompanying materials are made available
|
sl@0
|
4 |
// under the terms of "Eclipse Public License v1.0"
|
sl@0
|
5 |
// which accompanies this distribution, and is available
|
sl@0
|
6 |
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
sl@0
|
7 |
//
|
sl@0
|
8 |
// Initial Contributors:
|
sl@0
|
9 |
// Nokia Corporation - initial contribution.
|
sl@0
|
10 |
//
|
sl@0
|
11 |
// Contributors:
|
sl@0
|
12 |
//
|
sl@0
|
13 |
// Description:
|
sl@0
|
14 |
//
|
sl@0
|
15 |
|
sl@0
|
16 |
#include <f32file.h>
|
sl@0
|
17 |
#include <fbs.h>
|
sl@0
|
18 |
#include <bitmap.h>
|
sl@0
|
19 |
#include <bautils.h>
|
sl@0
|
20 |
#include "../sfbs/UTILS.H"
|
sl@0
|
21 |
#include "TSecureFBS.h"
|
sl@0
|
22 |
|
sl@0
|
23 |
|
sl@0
|
24 |
|
sl@0
|
25 |
LOCAL_C RFs fs;
|
sl@0
|
26 |
|
sl@0
|
27 |
//----------------------TEST DATA-------------------------------------
|
sl@0
|
28 |
//RC_ROM12 is a ROM type mbm
|
sl@0
|
29 |
//RC_RAM16 is a File Store type mbm
|
sl@0
|
30 |
//TFBS inside TFBS_RSC is a File Store type mbm
|
sl@0
|
31 |
//Bitmap for testing purposes
|
sl@0
|
32 |
_LIT(KBmp1_Z,"z:\\system\\data\\RC_ROM12.mbm");
|
sl@0
|
33 |
_LIT(KBmp2_Z,"z:\\system\\data\\RC_RAM16.mbm");
|
sl@0
|
34 |
|
sl@0
|
35 |
//Private path in C:
|
sl@0
|
36 |
_LIT(KBmp2_CP,"c:\\private\\10273364\\RC_RAM16.mbm");
|
sl@0
|
37 |
//Private path in Z:
|
sl@0
|
38 |
_LIT(KBmp1_ZP,"z:\\private\\10273364\\RC_ROM12.mbm");
|
sl@0
|
39 |
_LIT(KBmp2_ZP,"z:\\private\\10273364\\RC_RAM16.mbm");
|
sl@0
|
40 |
_LIT(KRscHeader_ZP,"z:\\private\\10273364\\RscHeader3.bin");
|
sl@0
|
41 |
_LIT(KDummyRsc_ZP,"z:\\private\\10273364\\DummyRscFile3.rsc");
|
sl@0
|
42 |
_LIT(KTbsRsc_ZP,"z:\\private\\10273364\\TFBS_RSC.rsc");
|
sl@0
|
43 |
_LIT(KInvalid_Bitmap,"z:\\private\\10273364\\invalid.mbm");
|
sl@0
|
44 |
|
sl@0
|
45 |
//Other private path 00999999 used for data caging test
|
sl@0
|
46 |
_LIT(KBmp1_ZOP,"z:\\private\\00999999\\RC_ROM12.mbm");
|
sl@0
|
47 |
_LIT(KBmp2_ZOP,"z:\\private\\00999999\\RC_RAM16.mbm");
|
sl@0
|
48 |
|
sl@0
|
49 |
_LIT(KPlatsecBegin,"*PlatSec* ERROR - BEGIN NEGATIVE PLATSEC TESTING");
|
sl@0
|
50 |
_LIT(KPlatsecEnd,"*PlatSec* ERROR - END NEGATIVE PLATSEC TESTING");
|
sl@0
|
51 |
//---------------------------------------------------------------------
|
sl@0
|
52 |
|
sl@0
|
53 |
CTFbsSecure::CTFbsSecure(CTestStep* aStep) :
|
sl@0
|
54 |
CTGraphicsBase(aStep)
|
sl@0
|
55 |
{
|
sl@0
|
56 |
|
sl@0
|
57 |
}
|
sl@0
|
58 |
|
sl@0
|
59 |
//--------------------UTILITY Function---------------------------------
|
sl@0
|
60 |
//This function is here to measure the offset in the rsc file
|
sl@0
|
61 |
TInt CTFbsSecure::FileSizeL(const TDesC& aFileName)
|
sl@0
|
62 |
{
|
sl@0
|
63 |
RFile file;
|
sl@0
|
64 |
User::LeaveIfError(file.Open(fs, aFileName, EFileRead));
|
sl@0
|
65 |
CleanupClosePushL(file);
|
sl@0
|
66 |
TInt size = 0;
|
sl@0
|
67 |
User::LeaveIfError(file.Size(size));
|
sl@0
|
68 |
CleanupStack::PopAndDestroy(&file);
|
sl@0
|
69 |
return size;
|
sl@0
|
70 |
}
|
sl@0
|
71 |
|
sl@0
|
72 |
//--------------------TEST CASE Function-------------------------------
|
sl@0
|
73 |
/**
|
sl@0
|
74 |
|
sl@0
|
75 |
-Using two type of bitmaps Rom and File Store Bitmap
|
sl@0
|
76 |
-Testing will focus on File Store type bitmap only
|
sl@0
|
77 |
-Loading a bitmap in private data cage, expect KErrNone
|
sl@0
|
78 |
-Loading a bitmap in other private data cage, expect KErrPermissionDenied(-46)
|
sl@0
|
79 |
-Loading a bitmap from a public path, expect KErrNone
|
sl@0
|
80 |
-Loading a bitmap from an rsc file inside the private data path
|
sl@0
|
81 |
*/
|
sl@0
|
82 |
/**
|
sl@0
|
83 |
@SYMTestCaseID
|
sl@0
|
84 |
GRAPHICS-FBSERV-0585
|
sl@0
|
85 |
|
sl@0
|
86 |
@SYMTestCaseDesc
|
sl@0
|
87 |
TestCase1 for testing data caging properties.
|
sl@0
|
88 |
|
sl@0
|
89 |
@SYMTestActions
|
sl@0
|
90 |
Using two type of bitmaps Rom and File Store Bitmap.
|
sl@0
|
91 |
Testing will focus on File Store type bitmap only.
|
sl@0
|
92 |
Loading a bitmap in private data cage, expect KErrNone.
|
sl@0
|
93 |
Loading a bitmap in other private data cage, expect KErrPermissionDenied(-46).
|
sl@0
|
94 |
Loading a bitmap from a public path, expect KErrNone.
|
sl@0
|
95 |
Loading a bitmap from an rsc file inside the private data path.
|
sl@0
|
96 |
|
sl@0
|
97 |
@SYMTestExpectedResults
|
sl@0
|
98 |
Test should pass
|
sl@0
|
99 |
*/
|
sl@0
|
100 |
void CTFbsSecure::TestCase1()
|
sl@0
|
101 |
{
|
sl@0
|
102 |
INFO_PRINTF1(_L("Test Case 1"));
|
sl@0
|
103 |
TInt skipRomBitmapTests = EFalse;
|
sl@0
|
104 |
TUint32* romAddress = NULL;
|
sl@0
|
105 |
if(!CFbsBitmap::IsFileInRom(KBmp1_ZP, romAddress)) //any ROM bitmap
|
sl@0
|
106 |
{
|
sl@0
|
107 |
INFO_PRINTF2(_L("Skipping ROM bitmap tests since file \"%S\" is reported to not be a ROM bitmap."),
|
sl@0
|
108 |
&KBmp1_ZP);
|
sl@0
|
109 |
INFO_PRINTF1(_L("This should only occur on non-XIP ROMs, e.g. NAND ROMs, where ROM bitmaps aren't supported."));
|
sl@0
|
110 |
skipRomBitmapTests = ETrue;
|
sl@0
|
111 |
}
|
sl@0
|
112 |
|
sl@0
|
113 |
TInt ret;
|
sl@0
|
114 |
if(!skipRomBitmapTests)
|
sl@0
|
115 |
{
|
sl@0
|
116 |
//Loading a ROM bitmap from its own private data cage \private\00099999
|
sl@0
|
117 |
CFbsBitmap bmp1;
|
sl@0
|
118 |
ret=bmp1.Load(KBmp1_ZP,0);
|
sl@0
|
119 |
TEST(ret==KErrNone);
|
sl@0
|
120 |
TEST(bmp1.IsRomBitmap());
|
sl@0
|
121 |
|
sl@0
|
122 |
//Loading a ROM bitmap from other private data cage \private\00999999
|
sl@0
|
123 |
//This test works if PlatSecEnforcement is ON otherwise it will return KErrNone
|
sl@0
|
124 |
CFbsBitmap bmp2;
|
sl@0
|
125 |
ret=bmp2.Load(KBmp1_ZOP,0);
|
sl@0
|
126 |
if (PlatSec::ConfigSetting(PlatSec::EPlatSecEnforcement) && PlatSec::IsCapabilityEnforced(ECapabilityAllFiles))
|
sl@0
|
127 |
TEST(ret==KErrPermissionDenied);
|
sl@0
|
128 |
else
|
sl@0
|
129 |
TEST(ret==KErrNone);
|
sl@0
|
130 |
|
sl@0
|
131 |
//Loading a ROM bitmap from a public data cage \system\data
|
sl@0
|
132 |
CFbsBitmap bmp3;
|
sl@0
|
133 |
ret=bmp3.Load(KBmp1_Z,0);
|
sl@0
|
134 |
TEST(ret==KErrNone);
|
sl@0
|
135 |
}
|
sl@0
|
136 |
|
sl@0
|
137 |
//Loading a File Store bitmap from its own private data cage \private\00099999
|
sl@0
|
138 |
CFbsBitmap bmp4;
|
sl@0
|
139 |
ret=bmp4.Load(KBmp2_ZP,0);
|
sl@0
|
140 |
TEST(ret==KErrNone);
|
sl@0
|
141 |
TEST(!bmp4.IsRomBitmap());
|
sl@0
|
142 |
|
sl@0
|
143 |
//Loading a File Store bitmap from other own private data cage \private\00099999
|
sl@0
|
144 |
CFbsBitmap bmp5;
|
sl@0
|
145 |
ret=bmp5.Load(KBmp2_ZOP,0);
|
sl@0
|
146 |
if (PlatSec::ConfigSetting(PlatSec::EPlatSecEnforcement) && PlatSec::IsCapabilityEnforced(ECapabilityAllFiles))
|
sl@0
|
147 |
TEST(ret==KErrPermissionDenied);
|
sl@0
|
148 |
else
|
sl@0
|
149 |
TEST(ret==KErrNone);
|
sl@0
|
150 |
|
sl@0
|
151 |
//Loading a File Store bitmap from a public data cage \system\data
|
sl@0
|
152 |
CFbsBitmap bmp6;
|
sl@0
|
153 |
ret=bmp6.Load(KBmp2_Z,0);
|
sl@0
|
154 |
TEST(ret==KErrNone);
|
sl@0
|
155 |
|
sl@0
|
156 |
//Loading a bitmap file from an rsc file inside the private data path
|
sl@0
|
157 |
CFbsBitmap bmp7;
|
sl@0
|
158 |
TInt fileoffset=0;
|
sl@0
|
159 |
//Getting the file offset for the mbm file embedded inside the rsc
|
sl@0
|
160 |
TRAP(ret,fileoffset=FileSizeL(KRscHeader_ZP)+FileSizeL(KDummyRsc_ZP));
|
sl@0
|
161 |
TEST(ret==KErrNone);
|
sl@0
|
162 |
ret=bmp7.Load(KTbsRsc_ZP,0,EFalse,fileoffset);
|
sl@0
|
163 |
TEST(ret==KErrNone);
|
sl@0
|
164 |
|
sl@0
|
165 |
//Loading a File Store bitmap from own private data cage in C:
|
sl@0
|
166 |
CFbsBitmap bmp8;
|
sl@0
|
167 |
ret=bmp8.Load(KBmp2_CP,0);
|
sl@0
|
168 |
TEST(ret==KErrNone);
|
sl@0
|
169 |
}
|
sl@0
|
170 |
|
sl@0
|
171 |
/**
|
sl@0
|
172 |
@SYMTestCaseID
|
sl@0
|
173 |
GRAPHICS-FBSERV-0586
|
sl@0
|
174 |
|
sl@0
|
175 |
@SYMTestCaseDesc
|
sl@0
|
176 |
TestCase2 for testing of invalid arguments such as file name,id, file offset
|
sl@0
|
177 |
|
sl@0
|
178 |
@SYMTestActions
|
sl@0
|
179 |
Test focus on File Store bitmap
|
sl@0
|
180 |
Loading an invalid bitmap file name expect KErrNotFound
|
sl@0
|
181 |
Loading a bitmap with invalid id
|
sl@0
|
182 |
Loading a bitmap with invalid file offset
|
sl@0
|
183 |
|
sl@0
|
184 |
@SYMTestExpectedResults
|
sl@0
|
185 |
Test should pass
|
sl@0
|
186 |
*/
|
sl@0
|
187 |
void CTFbsSecure::TestCase2()
|
sl@0
|
188 |
{
|
sl@0
|
189 |
INFO_PRINTF1(_L("Test Case 2"));
|
sl@0
|
190 |
TInt ret;
|
sl@0
|
191 |
//Loading an invalid bitmap KInvalid_Bitmap
|
sl@0
|
192 |
CFbsBitmap bmp1;
|
sl@0
|
193 |
ret=bmp1.Load(KInvalid_Bitmap,0);
|
sl@0
|
194 |
TEST(ret==KErrNotFound);
|
sl@0
|
195 |
|
sl@0
|
196 |
//Loading a bitmap with invalid id,KBmp1_ZP only has one bitmap
|
sl@0
|
197 |
CFbsBitmap bmp2;
|
sl@0
|
198 |
ret=bmp2.Load(KBmp2_ZP,1);
|
sl@0
|
199 |
TEST(ret==KErrEof);
|
sl@0
|
200 |
|
sl@0
|
201 |
//Loading a bitmap with invalid File offset
|
sl@0
|
202 |
CFbsBitmap bmp3;
|
sl@0
|
203 |
ret=bmp3.Load(KTbsRsc_ZP,0,EFalse,0);
|
sl@0
|
204 |
TEST(ret==KErrNotSupported);
|
sl@0
|
205 |
}
|
sl@0
|
206 |
|
sl@0
|
207 |
/**
|
sl@0
|
208 |
|
sl@0
|
209 |
|
sl@0
|
210 |
*/
|
sl@0
|
211 |
/**
|
sl@0
|
212 |
@SYMTestCaseID
|
sl@0
|
213 |
GRAPHICS-FBSERV-0587
|
sl@0
|
214 |
|
sl@0
|
215 |
@SYMTestCaseDesc
|
sl@0
|
216 |
TestCase3 for testing of the sharing of bitmaps using iShareIfLoaded
|
sl@0
|
217 |
this indirectly test the removal of the FileInfo and yet preserver
|
sl@0
|
218 |
preserve the same functionality in 9.0 without any regression
|
sl@0
|
219 |
|
sl@0
|
220 |
@SYMTestActions
|
sl@0
|
221 |
bmp1 load with iShareIfLoaded=ETrue and bmp2 load same file with ETrue
|
sl@0
|
222 |
Expect the Handle() and DataAddress() to be the same as there will be
|
sl@0
|
223 |
only one raw memory data stored in the global heap for these 2 instances of
|
sl@0
|
224 |
the same bitmap
|
sl@0
|
225 |
|
sl@0
|
226 |
bmp3 load with iShareIfLoaded=EFalse and bmp4 load same file with ETrue
|
sl@0
|
227 |
Expect the Handle() and DataAddress() to be different as bmp1 does not want
|
sl@0
|
228 |
to share the bitmap,so bmp2 will have its own Handle() and a completely pointer
|
sl@0
|
229 |
to the bitmap raw data
|
sl@0
|
230 |
|
sl@0
|
231 |
@SYMTestExpectedResults
|
sl@0
|
232 |
Test should pass
|
sl@0
|
233 |
*/
|
sl@0
|
234 |
void CTFbsSecure::TestCase3()
|
sl@0
|
235 |
{
|
sl@0
|
236 |
INFO_PRINTF1(_L("Test Case 3"));
|
sl@0
|
237 |
TInt ret;
|
sl@0
|
238 |
|
sl@0
|
239 |
//Loading first bitmap with ShareIfLoaded
|
sl@0
|
240 |
CFbsBitmap* bmp1=new (ELeave) CFbsBitmap;
|
sl@0
|
241 |
ret=bmp1->Load(KBmp2_ZP,0,ETrue);
|
sl@0
|
242 |
TEST(ret==KErrNone);
|
sl@0
|
243 |
TEST(!bmp1->IsRomBitmap());
|
sl@0
|
244 |
|
sl@0
|
245 |
//Loading second bitmap with ShareIfLoaded
|
sl@0
|
246 |
CFbsBitmap* bmp2=new (ELeave) CFbsBitmap;
|
sl@0
|
247 |
ret-bmp2->Load(KBmp2_ZP,0,ETrue);
|
sl@0
|
248 |
TEST(ret==KErrNone);
|
sl@0
|
249 |
TEST(!bmp2->IsRomBitmap());
|
sl@0
|
250 |
|
sl@0
|
251 |
//Test the file sharing properties do exist here
|
sl@0
|
252 |
TEST(bmp1->Handle()==bmp2->Handle());
|
sl@0
|
253 |
TEST(bmp1->DataAddress()==bmp2->DataAddress());
|
sl@0
|
254 |
|
sl@0
|
255 |
TInt fileoffset=0;
|
sl@0
|
256 |
TRAP(ret,fileoffset=FileSizeL(KRscHeader_ZP)+FileSizeL(KDummyRsc_ZP));
|
sl@0
|
257 |
TEST(ret==KErrNone);
|
sl@0
|
258 |
//Loading third bitmap with NO ShareIfLoaded
|
sl@0
|
259 |
CFbsBitmap* bmp3=new (ELeave) CFbsBitmap;
|
sl@0
|
260 |
ret=bmp3->Load(KTbsRsc_ZP,1,EFalse,fileoffset);
|
sl@0
|
261 |
TEST(ret==KErrNone);
|
sl@0
|
262 |
TEST(!bmp3->IsRomBitmap());
|
sl@0
|
263 |
|
sl@0
|
264 |
//Loading fourth bitmap(similar to 3) with ShareIfLoaded
|
sl@0
|
265 |
CFbsBitmap* bmp4=new (ELeave) CFbsBitmap;
|
sl@0
|
266 |
ret=bmp4->Load(KTbsRsc_ZP,1,ETrue,fileoffset);
|
sl@0
|
267 |
TEST(ret==KErrNone);
|
sl@0
|
268 |
TEST(!bmp4->IsRomBitmap());
|
sl@0
|
269 |
|
sl@0
|
270 |
//Test the file sharing properties does not exist here
|
sl@0
|
271 |
TEST(bmp3->Handle()!=bmp4->Handle());
|
sl@0
|
272 |
TEST(bmp3->DataAddress()!=bmp4->DataAddress());
|
sl@0
|
273 |
|
sl@0
|
274 |
delete bmp1;
|
sl@0
|
275 |
delete bmp2;
|
sl@0
|
276 |
delete bmp3;
|
sl@0
|
277 |
delete bmp4;
|
sl@0
|
278 |
|
sl@0
|
279 |
}
|
sl@0
|
280 |
|
sl@0
|
281 |
/**
|
sl@0
|
282 |
@SYMTestCaseID GRAPHICS-SYSLIB-FBSERV-CT-0002
|
sl@0
|
283 |
@SYMTestCaseDesc Testing for the secure bitmap loading in FBSERV
|
sl@0
|
284 |
@SYMTestPriority High
|
sl@0
|
285 |
@SYMTestActions Testing the loading of a bitmap from its own data cage
|
sl@0
|
286 |
Testing for permission denied when loading from other private data
|
sl@0
|
287 |
Testing for invalid arguments
|
sl@0
|
288 |
Testing for bitmap sharing
|
sl@0
|
289 |
@SYMTestExpectedResults The test must not fail.
|
sl@0
|
290 |
@SYMPREQ 280 General Datacaging
|
sl@0
|
291 |
*/
|
sl@0
|
292 |
|
sl@0
|
293 |
void CTFbsSecure::RunTestCaseL(TInt aCurTestCase)
|
sl@0
|
294 |
{
|
sl@0
|
295 |
((CTFbsSecureStep*)iStep)->SetTestStepID(KUnknownSYMTestCaseIDName);
|
sl@0
|
296 |
switch(aCurTestCase)
|
sl@0
|
297 |
{
|
sl@0
|
298 |
case 1:
|
sl@0
|
299 |
((CTFbsSecureStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0585"));
|
sl@0
|
300 |
RDebug::Print(KPlatsecBegin);
|
sl@0
|
301 |
TestCase1();
|
sl@0
|
302 |
RDebug::Print(KPlatsecEnd);
|
sl@0
|
303 |
break;
|
sl@0
|
304 |
case 2:
|
sl@0
|
305 |
((CTFbsSecureStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0586"));
|
sl@0
|
306 |
TestCase2();
|
sl@0
|
307 |
case 3:
|
sl@0
|
308 |
((CTFbsSecureStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0587"));
|
sl@0
|
309 |
TestCase3();
|
sl@0
|
310 |
break;
|
sl@0
|
311 |
case 4:
|
sl@0
|
312 |
((CTFbsSecureStep*)iStep)->SetTestStepID(KNotATestSYMTestCaseIDName);
|
sl@0
|
313 |
((CTFbsSecureStep*)iStep)->CloseTMSGraphicsStep();
|
sl@0
|
314 |
TestComplete();
|
sl@0
|
315 |
break;
|
sl@0
|
316 |
}
|
sl@0
|
317 |
((CTFbsSecureStep*)iStep)->RecordTestResultL();
|
sl@0
|
318 |
}
|
sl@0
|
319 |
|
sl@0
|
320 |
//--------------
|
sl@0
|
321 |
__CONSTRUCT_STEP__(FbsSecure)
|
sl@0
|
322 |
|
sl@0
|
323 |
|
sl@0
|
324 |
void CTFbsSecureStep::TestSetupL()
|
sl@0
|
325 |
{
|
sl@0
|
326 |
User::LeaveIfError(fs.Connect());
|
sl@0
|
327 |
|
sl@0
|
328 |
//Creating secure private path for testing purpose
|
sl@0
|
329 |
//This should create the private\10099999 directory
|
sl@0
|
330 |
User::LeaveIfError(fs.CreatePrivatePath(EDriveC));
|
sl@0
|
331 |
|
sl@0
|
332 |
//copying files to the secure path
|
sl@0
|
333 |
BaflUtils::CopyFile(fs,KBmp2_Z,KBmp2_CP);
|
sl@0
|
334 |
}
|
sl@0
|
335 |
|
sl@0
|
336 |
void CTFbsSecureStep::TestClose()
|
sl@0
|
337 |
{
|
sl@0
|
338 |
//Deleting any bitmaps copied to C:
|
sl@0
|
339 |
DeleteDataFile(KBmp2_CP);
|
sl@0
|
340 |
fs.Close();
|
sl@0
|
341 |
}
|
sl@0
|
342 |
|
sl@0
|
343 |
//This function is here to delete the bitmaps in C after finished with it
|
sl@0
|
344 |
void CTFbsSecureStep::DeleteDataFile(const TDesC& aFullName)
|
sl@0
|
345 |
{
|
sl@0
|
346 |
TEntry entry;
|
sl@0
|
347 |
if(fs.Entry(aFullName, entry) == KErrNone)
|
sl@0
|
348 |
{
|
sl@0
|
349 |
RDebug::Print(_L("Deleting \"%S\" file.\n"), &aFullName);
|
sl@0
|
350 |
TInt err = fs.SetAtt(aFullName, 0, KEntryAttReadOnly);
|
sl@0
|
351 |
if(err != KErrNone)
|
sl@0
|
352 |
{
|
sl@0
|
353 |
RDebug::Print(_L("Error %d changing \"%S\" file attributes.\n"), err, &aFullName);
|
sl@0
|
354 |
}
|
sl@0
|
355 |
err = fs.Delete(aFullName);
|
sl@0
|
356 |
if(err != KErrNone)
|
sl@0
|
357 |
{
|
sl@0
|
358 |
RDebug::Print(_L("Error %d deleting \"%S\" file.\n"), err, &aFullName);
|
sl@0
|
359 |
}
|
sl@0
|
360 |
}
|
sl@0
|
361 |
}
|