Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2000-2011 Regents of the University of California and the
4
 *              National Center for Ecological Analysis and Synthesis
5
 *
6
 *   '$Author: tao $'
7
 *     '$Date: 2014-12-31 15:49:58 -0800 (Wed, 31 Dec 2014) $'
8
 *
9
 * This program is free software; you can redistribute it and/or modify
10
 * it under the terms of the GNU General Public License as published by
11
 * the Free Software Foundation; either version 2 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
 */
23

    
24
package edu.ucsb.nceas.metacat.dataone.v1;
25

    
26
import java.io.InputStream;
27
import java.sql.SQLException;
28
import java.util.Date;
29

    
30
import javax.servlet.http.HttpServletRequest;
31

    
32
import org.apache.log4j.Logger;
33
import org.dataone.service.exceptions.IdentifierNotUnique;
34
import org.dataone.service.exceptions.InsufficientResources;
35
import org.dataone.service.exceptions.InvalidRequest;
36
import org.dataone.service.exceptions.InvalidSystemMetadata;
37
import org.dataone.service.exceptions.InvalidToken;
38
import org.dataone.service.exceptions.NotAuthorized;
39
import org.dataone.service.exceptions.NotFound;
40
import org.dataone.service.exceptions.NotImplemented;
41
import org.dataone.service.exceptions.ServiceFailure;
42
import org.dataone.service.exceptions.SynchronizationFailed;
43
import org.dataone.service.exceptions.UnsupportedType;
44
import org.dataone.service.mn.tier1.v1.MNCore;
45
import org.dataone.service.mn.tier1.v1.MNRead;
46
import org.dataone.service.mn.tier2.v1.MNAuthorization;
47
import org.dataone.service.mn.tier3.v1.MNStorage;
48
import org.dataone.service.mn.tier4.v1.MNReplication;
49
import org.dataone.service.mn.v1.MNQuery;
50
import org.dataone.service.types.v1.Checksum;
51
import org.dataone.service.types.v1.DescribeResponse;
52
import org.dataone.service.types.v1.Event;
53
import org.dataone.service.types.v1.Identifier;
54
import org.dataone.service.types.v1.Log;
55
import org.dataone.service.types.v1.Node;
56
import org.dataone.service.types.v1.NodeReference;
57
import org.dataone.service.types.v1.ObjectFormatIdentifier;
58
import org.dataone.service.types.v1.ObjectList;
59
import org.dataone.service.types.v1.Permission;
60
import org.dataone.service.types.v1.Session;
61
import org.dataone.service.types.v1.SystemMetadata;
62
import org.dataone.service.types.v1_1.QueryEngineDescription;
63
import org.dataone.service.types.v1_1.QueryEngineList;
64
import org.dataone.service.util.TypeMarshaller;
65

    
66
import edu.ucsb.nceas.metacat.IdentifierManager;
67

    
68
/**
69
 * Represents Metacat's implementation of the DataONE Member Node 
70
 * service API, v1. Methods typically pass through to the current 
71
 * version implementation performing type conversion as needed.
72
 * 
73
 */
74
public class MNodeService 
75
    implements MNAuthorization, MNCore, MNRead, MNReplication, MNStorage, MNQuery {
76

    
77
	/**
78
	 * current version implementation
79
	 */
80
	edu.ucsb.nceas.metacat.dataone.MNodeService impl = null;
81
	
82
	/* the logger instance */
83
    private Logger logMetacat = null;
84

    
85
    /**
86
     * Singleton accessor to get an instance of MNodeService.
87
     * 
88
     * @return instance - the instance of MNodeService
89
     */
90
    public static MNodeService getInstance(HttpServletRequest request) {
91
        return new MNodeService(request);
92
    }
93

    
94
    /**
95
     * Constructor, private for singleton access
96
     */
97
    private MNodeService(HttpServletRequest request) {
98
        logMetacat = Logger.getLogger(MNodeService.class);
99
        impl = edu.ucsb.nceas.metacat.dataone.MNodeService.getInstance(request);
100
    }
101
    
102
    public void setSession(Session session) {
103
    	impl.setSession(session);
104
    }
105
    
106
    public boolean isAdminAuthorized(Session session) throws ServiceFailure, InvalidToken, NotAuthorized, NotImplemented {
107
    	return impl.isAdminAuthorized(session);
108
    }
109

    
110
	@Override
111
	public QueryEngineDescription getQueryEngineDescription(String engine)
112
			throws InvalidToken, ServiceFailure, NotAuthorized, NotImplemented,
113
			NotFound {
114
		return impl.getQueryEngineDescription(null, engine);
115
	}
116

    
117
	@Override
118
	public QueryEngineList listQueryEngines() throws InvalidToken,
119
			ServiceFailure, NotAuthorized, NotImplemented {
120
		return impl.listQueryEngines(null);
121
	}
122

    
123
	@Override
124
	public InputStream query(String engine, String query) throws InvalidToken,
125
			ServiceFailure, NotAuthorized, InvalidRequest, NotImplemented,
126
			NotFound {
127
		return impl.query(null, engine, query);
128
	}
129

    
130
	@Override
131
	public Identifier archive(Identifier pid) throws InvalidToken,
132
			ServiceFailure, NotAuthorized, NotFound, NotImplemented {
133
	    String serviceFailure = "2912";
134
        String notFound = "2911";
135
        impl.checkV1SystemMetaPidExist(pid, serviceFailure, "The object specified by "+pid.getValue()+" couldn't be identified if it exists",  notFound, 
136
                "The object specified by "+pid.getValue()+" does not exist at this node.");
137
		return impl.archive(null, pid);
138
	}
139

    
140
	@Override
141
	@Deprecated
142
	public Identifier archive(Session session, Identifier pid)
143
			throws InvalidToken, ServiceFailure, NotAuthorized, NotFound,
144
			NotImplemented {
145
	    String serviceFailure = "2912";
146
        String notFound = "2911";
147
        impl.checkV1SystemMetaPidExist(pid, serviceFailure, "The object specified by "+pid.getValue()+" couldn't be identified if it exists",  notFound, 
148
                "The object specified by "+pid.getValue()+" does not exist at this node.");
149
		return impl.archive(session, pid);
150
	}
151

    
152
	@Override
153
	public Identifier create(Identifier pid, InputStream object,
154
			SystemMetadata sysmeta) throws IdentifierNotUnique,
155
			InsufficientResources, InvalidRequest, InvalidSystemMetadata,
156
			InvalidToken, NotAuthorized, NotImplemented, ServiceFailure,
157
			UnsupportedType {
158
		return this.create(null, pid, object, sysmeta);
159
	}
160

    
161
	@Override
162
	@Deprecated
163
	public Identifier create(Session session, Identifier pid, InputStream object,
164
			SystemMetadata sysmeta) throws IdentifierNotUnique,
165
			InsufficientResources, InvalidRequest, InvalidSystemMetadata,
166
			InvalidToken, NotAuthorized, NotImplemented, ServiceFailure,
167
			UnsupportedType {
168
		//convert sysmeta to newer version
169
		org.dataone.service.types.v2.SystemMetadata v2Sysmeta = null;
170
		try {
171
			v2Sysmeta = TypeMarshaller.convertTypeFromType(sysmeta, org.dataone.service.types.v2.SystemMetadata.class);
172
		} catch (Exception e) {
173
			// report as service failure
174
			ServiceFailure sf = new ServiceFailure("1190", e.getMessage());
175
			sf.initCause(e);
176
			throw sf;
177
		}
178
		
179
		return impl.create(session, pid, object, v2Sysmeta);
180
	}
181

    
182
	@Override
183
	public Identifier delete(Identifier pid) throws InvalidToken,
184
			ServiceFailure, NotAuthorized, NotFound, NotImplemented {
185
	    String serviceFailure = "2902";
186
        String notFound = "2901";
187
        impl.checkV1SystemMetaPidExist(pid, serviceFailure, "The object specified by "+pid.getValue()+" couldn't be identified if it exists",  notFound, 
188
                "The object specified by "+pid.getValue()+" does not exist at this node.");
189
		return impl.delete(null, pid);
190
	}
191

    
192
	@Override
193
	@Deprecated
194
	public Identifier delete(Session session, Identifier pid)
195
			throws InvalidToken, ServiceFailure, NotAuthorized, NotFound,
196
			NotImplemented {
197
	    String serviceFailure = "2902";
198
        String notFound = "2901";
199
        impl.checkV1SystemMetaPidExist(pid, serviceFailure, "The object specified by "+pid.getValue()+" couldn't be identified if it exists",  notFound, 
200
                "The object specified by "+pid.getValue()+" does not exist at this node.");
201
		return impl.delete(session, pid);
202
	}
203

    
204
	@Override
205
	public Identifier generateIdentifier(String scheme, String fragment)
206
			throws InvalidToken, ServiceFailure, NotAuthorized, NotImplemented,
207
			InvalidRequest {
208
		return impl.generateIdentifier(null, scheme, fragment);
209
	}
210

    
211
	@Override
212
	@Deprecated
213
	public Identifier generateIdentifier(Session session, String scheme, String fragment)
214
			throws InvalidToken, ServiceFailure, NotAuthorized, NotImplemented,
215
			InvalidRequest {
216
		return impl.generateIdentifier(session, scheme, fragment);
217
	}
218

    
219
	@Override
220
	public Identifier update(Identifier pid, InputStream object,
221
			Identifier newPid, SystemMetadata sysmeta) throws IdentifierNotUnique,
222
			InsufficientResources, InvalidRequest, InvalidSystemMetadata,
223
			InvalidToken, NotAuthorized, NotImplemented, ServiceFailure,
224
			UnsupportedType, NotFound {
225
		return this.update(null, pid, object, newPid, sysmeta);
226
	}
227

    
228
	@Override
229
	@Deprecated
230
	public Identifier update(Session session, Identifier pid, InputStream object,
231
			Identifier newPid, SystemMetadata sysmeta) throws IdentifierNotUnique,
232
			InsufficientResources, InvalidRequest, InvalidSystemMetadata,
233
			InvalidToken, NotAuthorized, NotImplemented, ServiceFailure,
234
			UnsupportedType, NotFound {
235
	    //check if the pid exists and not a sid
236
	    String serviceFailure = "1310";
237
        String notFound = "1280";
238
        impl.checkV1SystemMetaPidExist(pid, serviceFailure, "The object specified by "+pid.getValue()+" couldn't be identified if it exists",  notFound, 
239
                "The object specified by "+pid.getValue()+" does not exist at this node.");
240
		//convert sysmeta to newer version
241
		org.dataone.service.types.v2.SystemMetadata v2Sysmeta = null;
242
		try {
243
			v2Sysmeta = TypeMarshaller.convertTypeFromType(sysmeta, org.dataone.service.types.v2.SystemMetadata.class);
244
		} catch (Exception e) {
245
			// report as service failure
246
			ServiceFailure sf = new ServiceFailure("1030", e.getMessage());
247
			sf.initCause(e);
248
			throw sf;
249
		}
250
		return impl.update(session, pid, object, newPid, v2Sysmeta);
251
	}
252

    
253
	@Override
254
	public boolean replicate(SystemMetadata sysmeta, NodeReference sourceNode)
255
			throws NotImplemented, ServiceFailure, NotAuthorized,
256
			InvalidRequest, InvalidToken, InsufficientResources,
257
			UnsupportedType {
258
		return this.replicate(null, sysmeta, sourceNode);
259
	}
260

    
261
	@Override
262
	@Deprecated
263
	public boolean replicate(Session session, SystemMetadata sysmeta,
264
			NodeReference sourceNode) throws NotImplemented, ServiceFailure,
265
			NotAuthorized, InvalidRequest, InvalidToken, InsufficientResources,
266
			UnsupportedType {
267
		//convert sysmeta to newer version
268
		org.dataone.service.types.v2.SystemMetadata v2Sysmeta = null;
269
		try {
270
			v2Sysmeta = TypeMarshaller.convertTypeFromType(sysmeta, org.dataone.service.types.v2.SystemMetadata.class);
271
		} catch (Exception e) {
272
			// report as service failure
273
			ServiceFailure sf = new ServiceFailure("1030", e.getMessage());
274
			sf.initCause(e);
275
			throw sf;
276
		}
277
		return impl.replicate(session, v2Sysmeta, sourceNode);
278
	}
279

    
280
	@Override
281
	public DescribeResponse describe(Identifier pid) throws InvalidToken,
282
			NotAuthorized, NotImplemented, ServiceFailure, NotFound {
283
	    String serviceFailure = "1030";
284
        String notFound = "1020";
285
        impl.checkV1SystemMetaPidExist(pid, serviceFailure, "The system metadata for given PID "+pid.getValue()+" couldn't be identified if it exists",  notFound, 
286
                "No system metadata could be found for given PID: "+pid.getValue());
287
		return impl.describe(null, pid);
288
	}
289

    
290
	@Override
291
	@Deprecated
292
	public DescribeResponse describe(Session session, Identifier pid)
293
			throws InvalidToken, NotAuthorized, NotImplemented, ServiceFailure,
294
			NotFound {
295
	    String serviceFailure = "1030";
296
        String notFound = "1020";
297
        impl.checkV1SystemMetaPidExist(pid, serviceFailure, "The system metadata for given PID "+pid.getValue()+" couldn't be identified if it exists",  notFound, 
298
                "No system metadata could be found for given PID: "+pid.getValue());
299
		return impl.describe(session, pid);
300
	}
301

    
302
	@Override
303
	public InputStream get(Identifier pid) throws InvalidToken, NotAuthorized,
304
			NotImplemented, ServiceFailure, NotFound, InsufficientResources {
305
	    String serviceFailure = "1030";
306
        String notFound = "1020";
307
        impl.checkV1SystemMetaPidExist(pid, serviceFailure, "The object specified by "+pid.getValue()+" couldn't be identified if it exists",  notFound, 
308
                "The object specified by "+pid.getValue()+" does not exist at this node.");
309
		return impl.get(null, pid);
310
	}
311

    
312
	@Override
313
	@Deprecated
314
	public InputStream get(Session session, Identifier pid) throws InvalidToken,
315
			NotAuthorized, NotImplemented, ServiceFailure, NotFound,
316
			InsufficientResources {
317
	    String serviceFailure = "1030";
318
        String notFound = "1020";
319
        impl.checkV1SystemMetaPidExist(pid, serviceFailure, "The object specified by "+pid.getValue()+" couldn't be identified if it exists",  notFound, 
320
                "The object specified by "+pid.getValue()+" does not exist at this node.");
321
		return impl.get(session, pid);
322
	}
323

    
324
	@Override
325
	public Checksum getChecksum(Identifier pid, String algorithm)
326
			throws InvalidRequest, InvalidToken, NotAuthorized, NotImplemented,
327
			ServiceFailure, NotFound {
328
		return impl.getChecksum(null, pid, algorithm);
329
	}
330

    
331
	@Override
332
	@Deprecated
333
	public Checksum getChecksum(Session session, Identifier pid, String algorithm)
334
			throws InvalidRequest, InvalidToken, NotAuthorized, NotImplemented,
335
			ServiceFailure, NotFound {
336
		return impl.getChecksum(session, pid, algorithm);
337
	}
338

    
339
	@Override
340
	public InputStream getReplica(Identifier pid) throws InvalidToken,
341
			NotAuthorized, NotImplemented, ServiceFailure, NotFound,
342
			InsufficientResources {
343
		return impl.getReplica(null, pid);
344
	}
345

    
346
	@Override
347
	@Deprecated
348
	public InputStream getReplica(Session session, Identifier pid)
349
			throws InvalidToken, NotAuthorized, NotImplemented, ServiceFailure,
350
			NotFound, InsufficientResources {
351
		return impl.get(session, pid);
352
	}
353

    
354
	@Override
355
	public SystemMetadata getSystemMetadata(Identifier pid)
356
			throws InvalidToken, NotAuthorized, NotImplemented, ServiceFailure,
357
			NotFound {
358
		
359
		return this.getSystemMetadata(null, pid);
360
		
361
	}
362

    
363
	@Override
364
	@Deprecated
365
	public SystemMetadata getSystemMetadata(Session session, Identifier pid)
366
			throws InvalidToken, NotAuthorized, NotImplemented, ServiceFailure,
367
			NotFound {
368
	    String serviceFailure = "1090";
369
        String notFound = "1060";
370
        impl.checkV1SystemMetaPidExist(pid, serviceFailure, "The system metadata for given PID "+pid.getValue()+" couldn't be identified if it exists",  notFound, 
371
                "No system metadata could be found for given PID: "+pid.getValue());
372
		org.dataone.service.types.v2.SystemMetadata sysMeta = impl.getSystemMetadata(session, pid);
373
		SystemMetadata retSysMeta = null;
374
		try {
375
			retSysMeta = TypeMarshaller.convertTypeFromType(sysMeta, SystemMetadata.class);
376
		} catch (Exception e) {
377
			// report as service failure
378
			ServiceFailure sf = new ServiceFailure("4801", e.getMessage());
379
			sf.initCause(e);
380
			throw sf;
381
		}
382
		return retSysMeta;
383
	}
384

    
385
	@Override
386
	public ObjectList listObjects(Date startTime, Date endTime,
387
			ObjectFormatIdentifier objectFormatId, Boolean replicaStatus, Integer start,
388
			Integer count) throws InvalidRequest, InvalidToken, NotAuthorized,
389
			NotImplemented, ServiceFailure {
390
		return this.listObjects(null, startTime, endTime, objectFormatId, replicaStatus, start, count);
391
	}
392

    
393
	@Override
394
	@Deprecated
395
	public ObjectList listObjects(Session session, Date startTime, Date endTime,
396
			ObjectFormatIdentifier objectFormatId, Boolean replicaStatus, Integer start,
397
			Integer count) throws InvalidRequest, InvalidToken, NotAuthorized,
398
			NotImplemented, ServiceFailure {
399
		return impl.listObjects(session, startTime, endTime, objectFormatId, null, replicaStatus, start, count);
400
	}
401

    
402
	@Override
403
	public boolean synchronizationFailed(SynchronizationFailed syncFailed)
404
			throws InvalidToken, NotAuthorized, NotImplemented, ServiceFailure {
405
		return impl.synchronizationFailed(null, syncFailed);
406
	}
407

    
408
	@Override
409
	@Deprecated
410
	public boolean synchronizationFailed(Session session,
411
			SynchronizationFailed syncFailed) throws InvalidToken, NotAuthorized,
412
			NotImplemented, ServiceFailure {
413
		return impl.synchronizationFailed(session, syncFailed);
414
	}
415

    
416
	@Override
417
	public Node getCapabilities() throws NotImplemented, ServiceFailure {
418
		org.dataone.service.types.v2.Node node = impl.getCapabilities();
419
		Node retNode = null;
420
		try {
421
			retNode = TypeMarshaller.convertTypeFromType(node, Node.class);
422
		} catch (Exception e) {
423
			// report as service failure
424
			ServiceFailure sf = new ServiceFailure("4801", e.getMessage());
425
			sf.initCause(e);
426
			throw sf;
427
		}
428
		return retNode;
429
	}
430

    
431
	@Override
432
	public Log getLogRecords(Date fromDate, Date toDate, Event event,
433
			String pidFilter, Integer start, Integer count) throws InvalidRequest, InvalidToken,
434
			NotAuthorized, NotImplemented, ServiceFailure {
435
		return this.getLogRecords(null, fromDate, toDate, event, pidFilter, start, count);
436
	}
437

    
438
	@Override
439
	@Deprecated
440
	public Log getLogRecords(Session session, Date fromDate, Date toDate, Event event,
441
			String pidFilter, Integer start, Integer count) throws InvalidRequest, InvalidToken,
442
			NotAuthorized, NotImplemented, ServiceFailure {
443
		org.dataone.service.types.v2.Log log = impl.getLogRecords(session, fromDate, toDate, event.xmlValue(), pidFilter, start, count);
444
		Log retLog = null;
445
		try {
446
			retLog = TypeMarshaller.convertTypeFromType(log, Log.class);
447
		} catch (Exception e) {
448
			// report as service failure
449
			ServiceFailure sf = new ServiceFailure("1490", e.getMessage());
450
			sf.initCause(e);
451
			throw sf;
452
		}
453
		return retLog;
454
	}
455

    
456
	@Override
457
	public Date ping() throws NotImplemented, ServiceFailure,
458
			InsufficientResources {
459
		return impl.ping();
460
	}
461

    
462
	@Override
463
	public boolean isAuthorized(Identifier pid, Permission permission)
464
			throws ServiceFailure, InvalidRequest, InvalidToken, NotFound,
465
			NotAuthorized, NotImplemented {
466
	    String serviceFailure = "1760";
467
        String notFound = "1800";
468
        impl.checkV1SystemMetaPidExist(pid, serviceFailure, "The object specified by "+pid.getValue()+" couldn't be identified if it exists",  notFound, 
469
                "The object specified by "+pid.getValue()+" does not exist at this node.");
470
		return impl.isAuthorized(null, pid, permission);
471
	}
472

    
473
	@Override
474
	@Deprecated
475
	public boolean isAuthorized(Session session, Identifier pid, Permission permission)
476
			throws ServiceFailure, InvalidRequest, InvalidToken, NotFound,
477
			NotAuthorized, NotImplemented {
478
	    String serviceFailure = "1760";
479
        String notFound = "1800";
480
        impl.checkV1SystemMetaPidExist(pid, serviceFailure, "The object specified by "+pid.getValue()+" couldn't be identified if it exists",  notFound, 
481
                "The object specified by "+pid.getValue()+" does not exist at this node.");
482
		return impl.isAuthorized(session, pid, permission);
483
	}
484

    
485
	@Override
486
	public boolean systemMetadataChanged(Identifier pid, long serialVersion, Date dateSysMetaLastModified)
487
			throws InvalidToken, ServiceFailure, NotAuthorized, NotImplemented,
488
			InvalidRequest {
489
	    String serviceFailure = "1333";
490
        String notFound = "1800";
491
        try {
492
            impl.checkV1SystemMetaPidExist(pid, serviceFailure, "The system metadata of the object specified by "+pid.getValue()+" couldn't be identified if it exists",  notFound, 
493
                    "The system metadata of the object specified by "+pid.getValue()+" does not exist at this node.");
494
        } catch (NotFound e) {
495
            throw new ServiceFailure(serviceFailure, e.getMessage());
496
        }
497
		return impl.systemMetadataChanged(null, pid, serialVersion, dateSysMetaLastModified);
498

    
499
	}
500

    
501
	@Override
502
	@Deprecated
503
	public boolean systemMetadataChanged(Session session, Identifier pid,
504
			long serialVersion, Date dateSysMetaLastModified) throws InvalidToken, ServiceFailure,
505
			NotAuthorized, NotImplemented, InvalidRequest {
506
	    String serviceFailure = "1333";
507
        String notFound = "1800";
508
        try {
509
            impl.checkV1SystemMetaPidExist(pid, serviceFailure, "The system metadata of the object specified by "+pid.getValue()+" couldn't be identified if it exists",  notFound, 
510
                    "The system metadata of the object specified by "+pid.getValue()+" does not exist at this node.");
511
        } catch (NotFound e) {
512
            throw new ServiceFailure(serviceFailure, e.getMessage());
513
        }
514
		return impl.systemMetadataChanged(session, pid, serialVersion, dateSysMetaLastModified);
515
	}
516
    
517
	// methods not defined in v1, but implemented in metacat pre-v2 release
518
	
519
	public Identifier publish(Session session, Identifier originalIdentifier) 
520
			throws InvalidToken, ServiceFailure, NotAuthorized, NotImplemented, InvalidRequest, NotFound, IdentifierNotUnique, UnsupportedType, InsufficientResources, InvalidSystemMetadata {
521
		return impl.publish(session, originalIdentifier);
522
		
523
	}
524
	
525
	public InputStream view(Session session, String format, Identifier pid)
526
			throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest,
527
			NotImplemented, NotFound {
528
		
529
		return impl.view(session, format, pid);
530
	}
531
	
532
	public InputStream getPackage(Session session, ObjectFormatIdentifier formatId,
533
			Identifier pid) throws InvalidToken, ServiceFailure,
534
			NotAuthorized, InvalidRequest, NotImplemented, NotFound {
535
		return impl.getPackage(session, formatId, pid);
536
	}
537
	
538
    
539

    
540
   
541
}
(2-2/2)