Completed
Pull Request — master (#347)
by Maxence
01:49
created

MembersRequest::getLocalContactMembers()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
/**
3
 * Circles - Bring cloud-users closer together.
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Maxence Lange <[email protected]>
9
 * @copyright 2017
10
 * @license GNU AGPL version 3 or any later version
11
 *
12
 * This program is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License as
14
 * published by the Free Software Foundation, either version 3 of the
15
 * License, or (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
 *
25
 */
26
27
28
namespace OCA\Circles\Db;
29
30
31
use daita\MySmallPhpTools\Traits\TStringTools;
32
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
33
use OCA\Circles\Exceptions\MemberAlreadyExistsException;
34
use OCA\Circles\Exceptions\MemberDoesNotExistException;
35
use OCA\Circles\Model\Member;
36
use OCP\IGroup;
37
38
class MembersRequest extends MembersRequestBuilder {
39
40
41
	use TStringTools;
42
43
44
	/**
45
	 * Returns information about a member.
46
	 *
47
	 * WARNING: This function does not filters data regarding the current user/viewer.
48
	 *          In case of interaction with users, Please use MembersService->getMember() instead.
49
	 *
50
	 * @param string $circleUniqueId
51
	 * @param string $userId
52
	 * @param $type
53
	 *
54
	 * @return Member
55
	 * @throws MemberDoesNotExistException
56
	 */
57 View Code Duplication
	public function forceGetMember($circleUniqueId, $userId, $type) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
58
		$qb = $this->getMembersSelectSql();
59
60
		$this->limitToUserId($qb, $userId);
61
		$this->limitToUserType($qb, $type);
62
		$this->limitToCircleId($qb, $circleUniqueId);
63
64
		$cursor = $qb->execute();
65
		$data = $cursor->fetch();
66
		$cursor->closeCursor();
67
68
		if ($data === false) {
69
			throw new MemberDoesNotExistException($this->l10n->t('This member does not exist'));
70
		}
71
72
		$member = $this->parseMembersSelectSql($data);
73
74
		return $member;
75
	}
76
77
78
	/**
79
	 * Returns members list of a circle, based on their level.
80
	 *
81
	 * WARNING: This function does not filters data regarding the current user/viewer.
82
	 *          In case of interaction with users, Please use getMembers() instead.
83
	 *
84
	 * @param string $circleUniqueId
85
	 * @param int $level
86
	 * @param bool $incGroup
87
	 *
88
	 * @return Member[]
89
	 */
90
	public function forceGetMembers($circleUniqueId, $level = Member::LEVEL_MEMBER, $incGroup = false) {
91
92
		$qb = $this->getMembersSelectSql();
93
		$this->limitToMembersAndAlmost($qb);
94
		$this->limitToLevel($qb, $level);
95
96
		$this->limitToCircleId($qb, $circleUniqueId);
97
98
		$members = [];
99
		$cursor = $qb->execute();
100
		while ($data = $cursor->fetch()) {
101
			$members[] = $this->parseMembersSelectSql($data);
102
		}
103
		$cursor->closeCursor();
104
105
		if ($this->configService->isLinkedGroupsAllowed() && $incGroup === true) {
106
			$this->includeGroupMembers($members, $circleUniqueId, $level);
107
		}
108
109
		return $members;
110
	}
111
112
113
	/**
114
	 * Returns all members.
115
	 *
116
	 * WARNING: This function does not filters data regarding the current user/viewer.
117
	 *          In case of interaction with users, Please use getMembers() instead.
118
	 *
119
	 *
120
	 * @return Member[]
121
	 */
122
	public function forceGetAllMembers() {
123
124
		$qb = $this->getMembersSelectSql();
125
126
		$members = [];
127
		$cursor = $qb->execute();
128
		while ($data = $cursor->fetch()) {
129
			$members[] = $this->parseMembersSelectSql($data);
130
		}
131
		$cursor->closeCursor();
132
133
		return $members;
134
	}
135
136
137
	/**
138
	 * Returns members generated from Contacts that are not 'checked' (as not sent existing shares).
139
	 *
140
	 *
141
	 * @return Member[]
142
	 */
143
	public function forceGetAllRecentContactEdit() {
144
		$qb = $this->getMembersSelectSql();
145
		$this->limitToUserType($qb, Member::TYPE_CONTACT);
146
147
		$expr = $qb->expr();
148
		$orX = $expr->orX();
149
		$orX->add($expr->isNull('contact_checked'));
150
		$orX->add($expr->neq('contact_checked', $qb->createNamedParameter('1')));
151
		$qb->andWhere($orX);
152
153
		$members = [];
154
		$cursor = $qb->execute();
155
		while ($data = $cursor->fetch()) {
156
			$members[] = $this->parseMembersSelectSql($data);
157
		}
158
		$cursor->closeCursor();
159
160
		return $members;
161
	}
162
163
164
	/**
165
	 * @param Member $member
166
	 * @param bool $check
167
	 */
168
	public function checkMember(Member $member, bool $check) {
169
		$qb = $this->getMembersUpdateSql($member->getCircleId(), $member);
170
		$qb->set('contact_checked', $qb->createNamedParameter(($check) ? 1 : 0));
171
172
		$qb->execute();
173
	}
174
175
176
	/**
177
	 * @param string $circleUniqueId
178
	 * @param Member $viewer
179
	 *
180
	 * @return Member[]
181
	 * @throws \Exception
182
	 */
183
	public function getMembers($circleUniqueId, Member $viewer) {
184
		try {
185
			$viewer->hasToBeMember();
186
187
			$members = $this->forceGetMembers($circleUniqueId, Member::LEVEL_NONE);
188
			if (!$viewer->isLevel(Member::LEVEL_MODERATOR)) {
189
				array_map(
190
					function(Member $m) {
191
						$m->setNote('');
192
					}, $members
193
				);
194
			}
195
196
			return $members;
197
		} catch (\Exception $e) {
198
			return [];
199
		}
200
	}
201
202
203
	/**
204
	 * forceGetGroup();
205
	 *
206
	 * returns group information as a member within a Circle.
207
	 *
208
	 * WARNING: This function does not filters data regarding the current user/viewer.
209
	 *          In case of interaction with users, Please use getGroup() instead.
210
	 *
211
	 * @param string $circleUniqueId
212
	 * @param string $groupId
213
	 *
214
	 * @return Member
215
	 * @throws MemberDoesNotExistException
216
	 */
217 View Code Duplication
	public function forceGetGroup($circleUniqueId, $groupId) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
218
		$qb = $this->getGroupsSelectSql();
219
220
		$this->limitToGroupId($qb, $groupId);
221
		$this->limitToCircleId($qb, $circleUniqueId);
222
223
		$cursor = $qb->execute();
224
		$data = $cursor->fetch();
225
		if ($data === false) {
226
			throw new MemberDoesNotExistException($this->l10n->t('This member does not exist'));
227
		}
228
229
		$group = $this->parseGroupsSelectSql($data);
230
		$cursor->closeCursor();
231
232
		return $group;
233
	}
234
235
236
	/**
237
	 * includeGroupMembers();
238
	 *
239
	 * This function will get members of a circle throw NCGroups and fill the result an existing
240
	 * Members List. In case of duplicate, higher level will be kept.
241
	 *
242
	 * @param Member[] $members
243
	 * @param string $circleUniqueId
244
	 * @param int $level
245
	 */
246
	private function includeGroupMembers(array &$members, $circleUniqueId, $level) {
247
248
		$groupMembers = $this->forceGetGroupMembers($circleUniqueId, $level);
249
		$this->avoidDuplicateMembers($members, $groupMembers);
250
	}
251
252
253
	/**
254
	 * avoidDuplicateMembers();
255
	 *
256
	 * Use this function to add members to the list (1st argument), keeping the higher level in case
257
	 * of duplicate
258
	 *
259
	 * @param Member[] $members
260
	 * @param Member[] $groupMembers
261
	 */
262
	public function avoidDuplicateMembers(array &$members, array $groupMembers) {
263
		foreach ($groupMembers as $member) {
264
			$index = $this->indexOfMember($members, $member->getUserId());
265
			if ($index === -1) {
266
				array_push($members, $member);
267
			} else if ($members[$index]->getLevel() < $member->getLevel()) {
268
				$members[$index] = $member;
269
			}
270
		}
271
	}
272
273
274
	/**
275
	 * returns the index of a specific UserID in a Members List
276
	 *
277
	 * @param array $members
278
	 * @param $userId
279
	 *
280
	 * @return int
281
	 */
282
	private function indexOfMember(array $members, $userId) {
283
284
		foreach ($members as $k => $member) {
285
			if ($member->getUserId() === $userId) {
286
				return intval($k);
287
			}
288
		}
289
290
		return -1;
291
	}
292
293
294
	/**
295
	 * Check if a fresh member can be generated (by addMember/joinCircle)
296
	 *
297
	 * @param string $circleUniqueId
298
	 * @param string $name
299
	 * @param $type
300
	 *
301
	 * @return Member
302
	 * @throws MemberAlreadyExistsException
303
	 * @throws \Exception
304
	 */
305
	public function getFreshNewMember($circleUniqueId, $name, $type) {
306
307
		try {
308
309
			$member = $this->forceGetMember($circleUniqueId, $name, $type);
310
311
		} catch (MemberDoesNotExistException $e) {
312
			$member = new Member($name, $type, $circleUniqueId);
313
			$this->createMember($member);
314
		}
315
316
//		if ($member->alreadyExistOrJoining()) {
317
//			throw new MemberAlreadyExistsException(
318
//				$this->l10n->t('This user is already a member of the circle')
319
//			);
320
//		}
321
322
		return $member;
323
	}
324
325
326
	/**
327
	 * Returns members list of all Group Members of a Circle. The Level of the linked group will be
328
	 * assigned to each entry
329
	 *
330
	 * NOTE: Can contains duplicate.
331
	 *
332
	 * WARNING: This function does not filters data regarding the current user/viewer.
333
	 *          Do not use in case of direct interaction with users.
334
	 *
335
	 * @param string $circleUniqueId
336
	 * @param int $level
337
	 *
338
	 * @return Member[]
339
	 */
340
	public function forceGetGroupMembers($circleUniqueId, $level = Member::LEVEL_MEMBER) {
341
		$qb = $this->getGroupsSelectSql();
342
343
		$this->limitToLevel($qb, $level);
344
		$this->limitToCircleId($qb, $circleUniqueId);
345
		$this->limitToNCGroupUser($qb);
346
347
		$members = [];
348
		$cursor = $qb->execute();
349
		while ($data = $cursor->fetch()) {
350
			$members[] = $this->parseGroupsSelectSql($data);
351
		}
352
		$cursor->closeCursor();
353
354
		return $members;
355
	}
356
357
358
	/**
359
	 * returns all users from a Group as a list of Members.
360
	 *
361
	 * @param Member $group
362
	 *
363
	 * @return Member[]
364
	 */
365
	public function getGroupMemberMembers(Member $group) {
366
		/** @var IGroup $grp */
367
		$grp = $this->groupManager->get($group->getUserId());
368
		if ($grp === null) {
369
			return [];
370
		}
371
372
		$members = [];
373
		$users = $grp->getUsers();
374
		foreach ($users as $user) {
375
			$member = clone $group;
376
			//Member::fromJSON($this->l10n, json_encode($group));
377
			$member->setType(Member::TYPE_USER);
378
			$member->setUserId($user->getUID());
379
			$members[] = $member;
380
		}
381
382
		return $members;
383
	}
384
385
386
	/**
387
	 * return the higher level group linked to a circle, that include the userId.
388
	 *
389
	 * WARNING: This function does not filters data regarding the current user/viewer.
390
	 *          In case of direct interaction with users, Please don't use this.
391
	 *
392
	 * @param string $circleUniqueId
393
	 * @param string $userId
394
	 *
395
	 * @return Member
396
	 */
397
	public function forceGetHigherLevelGroupFromUser($circleUniqueId, $userId) {
398
		$qb = $this->getGroupsSelectSql();
399
400
		$this->limitToCircleId($qb, $circleUniqueId);
401
		$this->limitToNCGroupUser($qb, $userId);
402
403
		/** @var Member $group */
404
		$group = null;
405
406
		$cursor = $qb->execute();
407
		while ($data = $cursor->fetch()) {
408
			$entry = $this->parseGroupsSelectSql($data);
409
			if ($group === null || $entry->getLevel() > $group->getLevel()) {
410
				$group = $entry;
411
			}
412
		}
413
		$cursor->closeCursor();
414
415
		return $group;
416
	}
417
418
419
	/**
420
	 * Insert Member into database.
421
	 *
422
	 * @param Member $member
423
	 *
424
	 * @throws MemberAlreadyExistsException
425
	 */
426
	public function createMember(Member $member) {
427
428
		if ($member->getMemberId() === '') {
429
			$member->setMemberId($this->token());
430
		}
431
432
		try {
433
			$qb = $this->getMembersInsertSql();
434
			$qb->setValue('circle_id', $qb->createNamedParameter($member->getCircleId()))
435
			   ->setValue('user_id', $qb->createNamedParameter($member->getUserId()))
436
			   ->setValue('member_id', $qb->createNamedParameter($member->getMemberId()))
437
			   ->setValue('user_type', $qb->createNamedParameter($member->getType()))
438
			   ->setValue('level', $qb->createNamedParameter($member->getLevel()))
439
			   ->setValue('status', $qb->createNamedParameter($member->getStatus()))
440
			   ->setValue('contact_id', $qb->createNamedParameter($member->getContactId()))
441
			   ->setValue('note', $qb->createNamedParameter($member->getNote()));
442
443
			$qb->execute();
444
		} catch (UniqueConstraintViolationException $e) {
0 ignored issues
show
Bug introduced by
The class Doctrine\DBAL\Exception\...raintViolationException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
445
			throw new MemberAlreadyExistsException(
446
				$this->l10n->t('This user is already a member of the circle')
447
			);
448
		}
449
	}
450
451
452
	/**
453
	 * @param string $circleUniqueId
454
	 * @param Member $viewer
455
	 *
456
	 * @return Member[]
457
	 * @throws MemberDoesNotExistException
458
	 */
459
	public function getGroupsFromCircle($circleUniqueId, Member $viewer) {
460
461
		if ($viewer->getLevel() < Member::LEVEL_MEMBER) {
462
			return [];
463
		}
464
465
		$qb = $this->getGroupsSelectSql();
466
		$this->limitToCircleId($qb, $circleUniqueId);
467
		$this->limitToLevel($qb, Member::LEVEL_MEMBER);
468
469
		$cursor = $qb->execute();
470
		$groups = [];
471
		while ($data = $cursor->fetch()) {
472
			if ($viewer->getLevel() < Member::LEVEL_MODERATOR) {
473
				$data['note'] = '';
474
			}
475
			$groups[] = $this->parseGroupsSelectSql($data);
476
		}
477
		$cursor->closeCursor();
478
479
		return $groups;
480
	}
481
482
483
	/**
484
	 * Insert Member into database.
485
	 *
486
	 * @param Member $member
487
	 *
488
	 * @throws MemberAlreadyExistsException
489
	 */
490
	public function insertGroup(Member $member) {
491
		try {
492
			$qb = $this->getGroupsInsertSql();
493
			$qb->setValue('circle_id', $qb->createNamedParameter($member->getCircleId()))
494
			   ->setValue('group_id', $qb->createNamedParameter($member->getUserId()))
495
			   ->setValue('level', $qb->createNamedParameter($member->getLevel()))
496
			   ->setValue('note', $qb->createNamedParameter($member->getNote()));
497
498
			$qb->execute();
499
		} catch (UniqueConstraintViolationException $e) {
500
			throw new MemberAlreadyExistsException(
501
				$this->l10n->t('This user is already a member of the circle')
502
			);
503
		}
504
	}
505
506
507
	/**
508
	 * update database entry for a specific Member.
509
	 *
510
	 * @param Member $member
511
	 */
512
	public function updateMember(Member $member) {
513
		$qb = $this->getMembersUpdateSql($member->getCircleId(), $member);
514
		$qb->set('level', $qb->createNamedParameter($member->getLevel()))
515
		   ->set('status', $qb->createNamedParameter($member->getStatus()));
516
517
		$qb->execute();
518
	}
519
520
	/**
521
	 * update database entry for a specific Member.
522
	 *
523
	 * @param Member $member
524
	 */
525
	public function updateContactMeta(Member $member) {
526
		$qb = $this->getMembersUpdateSql($member->getCircleId(), $member);
527
		$qb->set('contact_meta', $qb->createNamedParameter(json_encode($member->getContactMeta())));
528
529
		$qb->execute();
530
	}
531
532
533
	/**
534
	 * removeAllFromCircle();
535
	 *
536
	 * Remove All members from a Circle. Used when deleting a Circle.
537
	 *
538
	 * @param string $uniqueCircleId
539
	 */
540
	public function removeAllFromCircle($uniqueCircleId) {
541
		$qb = $this->getMembersDeleteSql();
542
		$expr = $qb->expr();
543
544
		$qb->where($expr->eq('circle_id', $qb->createNamedParameter($uniqueCircleId)));
545
		$qb->execute();
546
	}
547
548
549
	/**
550
	 * removeAllMembershipsFromUser();
551
	 *
552
	 * remove All membership from a User. Used when removing a User from the Cloud.
553
	 *
554
	 * @param string $userId
555
	 */
556
	public function removeAllMembershipsFromUser($userId) {
557
		if ($userId === '') {
558
			return;
559
		}
560
561
		$qb = $this->getMembersDeleteSql();
562
		$expr = $qb->expr();
563
564
		/** @noinspection PhpMethodParametersCountMismatchInspection */
565
		$qb->where(
566
			$expr->andX(
567
				$expr->eq('user_id', $qb->createNamedParameter($userId)),
568
				$expr->eq('user_type', $qb->createNamedParameter(Member::TYPE_USER))
569
			)
570
		);
571
572
		$qb->execute();
573
	}
574
575
576
	/**
577
	 * remove member, identified by its id, type and circleId
578
	 *
579
	 * @param Member $member
580
	 */
581
	public function removeMember(Member $member) {
582
		$qb = $this->getMembersDeleteSql();
583
		$this->limitToCircleId($qb, $member->getCircleId());
584
		$this->limitToUserId($qb, $member->getUserId());
585
		$this->limitToUserType($qb, $member->getType());
586
		if ($member->getContactId() !== '') {
587
			$this->limitToContactId($qb, $member->getContactId());
588
		}
589
590
		$qb->execute();
591
	}
592
593
	/**
594
	 * update database entry for a specific Group.
595
	 *
596
	 * @param Member $member
597
	 *
598
	 * @return bool
599
	 */
600
	public function updateGroup(Member $member) {
601
		$qb = $this->getGroupsUpdateSql($member->getCircleId(), $member->getUserId());
602
		$qb->set('level', $qb->createNamedParameter($member->getLevel()));
603
		$qb->execute();
604
605
		return true;
606
	}
607
608
609
	public function unlinkAllFromGroup($groupId) {
610
		$qb = $this->getGroupsDeleteSql($groupId);
611
		$qb->execute();
612
	}
613
614
615
	/**
616
	 * @param string $contactId
617
	 *
618
	 * @return Member[]
619
	 */
620
	public function getMembersByContactId(string $contactId = ''): array {
621
		$qb = $this->getMembersSelectSql();
622
		if ($contactId === '') {
623
			$expr = $qb->expr();
624
			$qb->andWhere($expr->neq('contact_id', $qb->createNamedParameter('')));
625
		} else {
626
			$this->limitToContactId($qb, $contactId);
627
		}
628
629
		$members = [];
630
		$cursor = $qb->execute();
631
		while ($data = $cursor->fetch()) {
632
			$member = $this->parseMembersSelectSql($data);
633
			$members[] = $member;
634
		}
635
		$cursor->closeCursor();
636
637
		return $members;
638
	}
639
640
641
	/**
642
	 * @param string $circleId
643
	 * @param string $contactId
644
	 * @param string $userId
0 ignored issues
show
Bug introduced by
There is no parameter named $userId. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
645
	 * @param int $type
0 ignored issues
show
Bug introduced by
There is no parameter named $type. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
646
	 *
647
	 * @return Member
648
	 * @throws MemberDoesNotExistException
649
	 */
650 View Code Duplication
	public function getContactMember(string $circleId, string $contactId): Member {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
651
		$qb = $this->getMembersSelectSql();
652
		$this->limitToContactId($qb, $contactId);
653
		$this->limitToCircleId($qb, $circleId);
654
655
		$cursor = $qb->execute();
656
		$data = $cursor->fetch();
657
		$cursor->closeCursor();
658
659
		if ($data === false) {
660
			throw new MemberDoesNotExistException($this->l10n->t('This member does not exist'));
661
		}
662
663
		return $this->parseMembersSelectSql($data);
664
	}
665
666
667
	/**
668
	 * @param string $contactId
669
	 *
670
	 * @return Member[]
671
	 */
672
	public function getLocalContactMembers(string $contactId): array {
673
		$qb = $this->getMembersSelectSql();
674
		$this->limitToContactId($qb, $contactId);
675
		$this->limitToUserType($qb, Member::TYPE_USER);
676
677
		$members = [];
678
		$cursor = $qb->execute();
679
		while ($data = $cursor->fetch()) {
680
			$members[] = $this->parseMembersSelectSql($data);
681
		}
682
		$cursor->closeCursor();
683
684
		return $members;
685
	}
686
687
688
	/**
689
	 * @param string $contactId
690
	 * @param int $type
691
	 */
692
	public function removeMembersByContactId(string $contactId, int $type = 0) {
693
		$this->miscService->log($contactId);
694
		if ($contactId === '') {
695
			return;
696
		}
697
698
		$qb = $this->getMembersDeleteSql();
699
		$this->limitToContactId($qb, $contactId);
700
		if ($type > 0) {
701
			$this->limitToUserType($qb, $type);
702
		}
703
704
		$qb->execute();
705
	}
706
707
}
708
709