1<?php
2
3declare(strict_types=1);
4
5
6/**
7 * Circles - Bring cloud-users closer together.
8 *
9 * This file is licensed under the Affero General Public License version 3 or
10 * later. See the COPYING file.
11 *
12 * @author Maxence Lange <maxence@artificial-owl.com>
13 * @copyright 2021
14 * @license GNU AGPL version 3 or any later version
15 *
16 * This program is free software: you can redistribute it and/or modify
17 * it under the terms of the GNU Affero General Public License as
18 * published by the Free Software Foundation, either version 3 of the
19 * License, or (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 * GNU Affero General Public License for more details.
25 *
26 * You should have received a copy of the GNU Affero General Public License
27 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
28 *
29 */
30
31
32namespace OCA\Circles\Model;
33
34use ArtificialOwl\MySmallPhpTools\Db\Nextcloud\nc22\INC22QueryRow;
35use ArtificialOwl\MySmallPhpTools\Exceptions\InvalidItemException;
36use ArtificialOwl\MySmallPhpTools\IDeserializable;
37use ArtificialOwl\MySmallPhpTools\Traits\Nextcloud\nc22\TNC22Deserialize;
38use ArtificialOwl\MySmallPhpTools\Traits\TArrayTools;
39use DateTime;
40use JsonSerializable;
41use OCA\Circles\AppInfo\Capabilities;
42use OCA\Circles\Exceptions\MemberNotFoundException;
43use OCA\Circles\Exceptions\MembershipNotFoundException;
44use OCA\Circles\Exceptions\ParseMemberLevelException;
45use OCA\Circles\Exceptions\RequestBuilderException;
46use OCA\Circles\Exceptions\UnknownInterfaceException;
47use OCA\Circles\Exceptions\UserTypeNotFoundException;
48use OCA\Circles\IFederatedUser;
49use OCA\Circles\IEntity;
50use OCA\Circles\Model\Federated\RemoteInstance;
51
52/**
53 * Class Member
54 *
55 * @package OCA\Circles\Model
56 */
57class Member extends ManagedModel implements
58	IEntity,
59	IFederatedUser,
60	IDeserializable,
61	INC22QueryRow,
62	JsonSerializable {
63	use TArrayTools;
64	use TNC22Deserialize;
65
66
67	public const LEVEL_NONE = 0;
68	public const LEVEL_MEMBER = 1;
69	public const LEVEL_MODERATOR = 4;
70	public const LEVEL_ADMIN = 8;
71	public const LEVEL_OWNER = 9;
72
73	public const TYPE_SINGLE = 0;
74	public const TYPE_USER = 1;
75	public const TYPE_GROUP = 2;
76	public const TYPE_MAIL = 4;
77	public const TYPE_CONTACT = 8;
78	public const TYPE_CIRCLE = 16;
79	public const TYPE_APP = 10000;
80
81	public const APP_CIRCLES = 10001;
82	public const APP_OCC = 10002;
83
84
85	public static $TYPE = [
86		0 => 'single',
87		1 => 'user',
88		2 => 'group',
89		4 => 'mail',
90		8 => 'contact',
91		16 => 'circle',
92		10000 => 'app'
93	];
94
95	/**
96	 * Note: When editing those values, update lib/Application/Capabilities.php
97	 *
98	 * @see Capabilities::generateConstantsMember()
99	 */
100	public const STATUS_INVITED = 'Invited';
101	public const STATUS_REQUEST = 'Requesting';
102	public const STATUS_MEMBER = 'Member';
103	public const STATUS_BLOCKED = 'Blocked';
104
105
106	/**
107	 * Note: When editing those values, update lib/Application/Capabilities.php
108	 *
109	 * @see Capabilities::generateConstantsMember()
110	 * @var array
111	 */
112	public static $DEF_LEVEL = [
113		1 => 'Member',
114		4 => 'Moderator',
115		8 => 'Admin',
116		9 => 'Owner'
117	];
118
119
120	public static $DEF_TYPE_MAX = 31;
121
122
123	/** @var string */
124	private $id = '';
125
126	/** @var string */
127	private $circleId = '';
128
129	/** @var string */
130	private $singleId = '';
131
132	/** @var string */
133	private $userId = '';
134
135	/** @var int */
136	private $userType = 0;
137
138	/** @var Circle */
139	private $basedOn;
140
141	/** @var Member */
142	private $inheritanceFrom;
143
144	/** @var FederatedUser */
145	private $inheritedBy;
146
147	/** @var string */
148	private $instance = '';
149
150	/** @var FederatedUser */
151	private $invitedBy;
152
153	/** @var RemoteInstance */
154	private $remoteInstance;
155
156	/** @var bool */
157	private $local = false;
158
159	/** @var int */
160	private $level = 0;
161
162	/** @var string */
163	private $status = 'Unknown';
164
165	/** @var array */
166	private $notes = [];
167
168	/** @var string */
169	private $displayName = '';
170
171	/** @var int */
172	private $displayUpdate = 0;
173
174	/** @var string */
175	private $contactId = '';
176
177	/** @var string */
178	private $contactMeta = '';
179
180	/** @var Circle */
181	private $circle;
182
183	/** @var int */
184	private $joined = 0;
185
186	/** @var Membership[] */
187	private $memberships = null;
188
189
190	/**
191	 * Member constructor.
192	 */
193	public function __construct() {
194	}
195
196
197	/**
198	 * @param string $id
199	 *
200	 * @return $this
201	 */
202	public function setId(string $id): self {
203		$this->id = $id;
204
205		return $this;
206	}
207
208	/**
209	 * @return string
210	 */
211	public function getId(): string {
212		return $this->id;
213	}
214
215
216	/**
217	 * @param string $circleId
218	 *
219	 * @return Member
220	 */
221	public function setCircleId(string $circleId): self {
222		$this->circleId = $circleId;
223
224		return $this;
225	}
226
227	/**
228	 * @return string
229	 */
230	public function getCircleId(): string {
231		return $this->circleId;
232	}
233
234
235	/**
236	 * This should replace user_id, user_type and instance; and will use the data from Circle with
237	 * Config=CFG_SINGLE
238	 *
239	 * @param string $singleId
240	 *
241	 * @return $this
242	 */
243	public function setSingleId(string $singleId): self {
244		$this->singleId = $singleId;
245
246		return $this;
247	}
248
249	/**
250	 * @return string
251	 */
252	public function getSingleId(): string {
253		return $this->singleId;
254	}
255
256
257	/**
258	 * @param string $userId
259	 *
260	 * @return Member
261	 */
262	public function setUserId(string $userId): self {
263		$this->userId = $userId;
264		if ($this->displayName === '') {
265			$this->displayName = $userId;
266		}
267
268		return $this;
269	}
270
271	/**
272	 * @return string
273	 */
274	public function getUserId(): string {
275		return $this->userId;
276	}
277
278
279	/**
280	 * @param int $userType
281	 *
282	 * @return Member
283	 */
284	public function setUserType(int $userType): self {
285		$this->userType = $userType;
286
287		return $this;
288	}
289
290	/**
291	 * @return int
292	 */
293	public function getUserType(): int {
294		return $this->userType;
295	}
296
297	/**
298	 * @return int
299	 * @deprecated 22.0.0
300	 */
301	public function getType(): int {
302		return $this->getUserType();
303	}
304
305
306	/**
307	 * @param string $instance
308	 *
309	 * @return Member
310	 */
311	public function setInstance(string $instance): self {
312		$this->instance = $instance;
313
314		return $this;
315	}
316
317	/**
318	 * @return string
319	 */
320	public function getInstance(): string {
321		return $this->instance;
322	}
323
324
325	/**
326	 * @return bool
327	 */
328	public function isLocal(): bool {
329		return $this->getManager()->isLocalInstance($this->getInstance());
330	}
331
332
333	/**
334	 * @param FederatedUser $invitedBy
335	 *
336	 * @return Member
337	 */
338	public function setInvitedBy(FederatedUser $invitedBy): Member {
339		$this->invitedBy = $invitedBy;
340
341		return $this;
342	}
343
344	/**
345	 * @return FederatedUser
346	 */
347	public function getInvitedBy(): FederatedUser {
348		return $this->invitedBy;
349	}
350
351	/**
352	 * @return bool
353	 */
354	public function hasInvitedBy(): bool {
355		return !is_null($this->invitedBy);
356	}
357
358
359	/**
360	 * @return bool
361	 */
362	public function hasRemoteInstance(): bool {
363		return !is_null($this->remoteInstance);
364	}
365
366	/**
367	 * @param RemoteInstance $remoteInstance
368	 *
369	 * @return Member
370	 */
371	public function setRemoteInstance(RemoteInstance $remoteInstance): self {
372		$this->remoteInstance = $remoteInstance;
373
374		return $this;
375	}
376
377	/**
378	 * @return RemoteInstance
379	 */
380	public function getRemoteInstance(): RemoteInstance {
381		return $this->remoteInstance;
382	}
383
384
385	/**
386	 * @return bool
387	 */
388	public function hasBasedOn(): bool {
389		return !is_null($this->basedOn);
390	}
391
392	/**
393	 * @param Circle $basedOn
394	 *
395	 * @return $this
396	 */
397	public function setBasedOn(Circle $basedOn): self {
398		$this->basedOn = $basedOn;
399
400		return $this;
401	}
402
403	/**
404	 * @return Circle
405	 */
406	public function getBasedOn(): Circle {
407		return $this->basedOn;
408	}
409
410
411	/**
412	 * @return bool
413	 */
414	public function hasInheritedBy(): bool {
415		return !is_null($this->inheritedBy);
416	}
417
418	/**
419	 * @param FederatedUser $inheritedBy
420	 *
421	 * @return $this
422	 */
423	public function setInheritedBy(FederatedUser $inheritedBy): self {
424		$this->inheritedBy = $inheritedBy;
425
426		return $this;
427	}
428
429	/**
430	 * @return FederatedUser
431	 */
432	public function getInheritedBy(): FederatedUser {
433		return $this->inheritedBy;
434	}
435
436
437	/**
438	 * @return bool
439	 */
440	public function hasInheritanceFrom(): bool {
441		return !is_null($this->inheritanceFrom);
442	}
443
444	/**
445	 * @param Member $inheritanceFrom
446	 *
447	 * @return $this
448	 */
449	public function setInheritanceFrom(Member $inheritanceFrom): self {
450		$this->inheritanceFrom = $inheritanceFrom;
451
452		return $this;
453	}
454
455	/**
456	 * @return Member|null
457	 */
458	public function getInheritanceFrom(): ?Member {
459		return $this->inheritanceFrom;
460	}
461
462
463	/**
464	 * @param int $level
465	 *
466	 * @return Member
467	 */
468	public function setLevel(int $level): self {
469		$this->level = $level;
470
471		return $this;
472	}
473
474	/**
475	 * @return int
476	 */
477	public function getLevel(): int {
478		return $this->level;
479	}
480
481
482	/**
483	 * @param string $status
484	 *
485	 * @return Member
486	 */
487	public function setStatus(string $status): self {
488		$this->status = $status;
489
490		return $this;
491	}
492
493	/**
494	 * @return string
495	 */
496	public function getStatus(): string {
497		return $this->status;
498	}
499
500
501	/**
502	 * @param array $notes
503	 *
504	 * @return Member
505	 */
506	public function setNotes(array $notes): self {
507		$this->notes = $notes;
508
509		return $this;
510	}
511
512	/**
513	 * @return array
514	 */
515	public function getNotes(): array {
516		return $this->notes;
517	}
518
519
520	/**
521	 * @param string $key
522	 *
523	 * @return string
524	 */
525	public function getNote(string $key): string {
526		return $this->get($key, $this->notes);
527	}
528
529	/**
530	 * @param string $key
531	 *
532	 * @return array
533	 */
534	public function getNoteArray(string $key): array {
535		return $this->getArray($key, $this->notes);
536	}
537
538	/**
539	 * @param string $key
540	 * @param string $note
541	 *
542	 * @return $this
543	 */
544	public function setNote(string $key, string $note): self {
545		$this->notes[$key] = $note;
546
547		return $this;
548	}
549
550	/**
551	 * @param string $key
552	 * @param array $note
553	 *
554	 * @return $this
555	 */
556	public function setNoteArray(string $key, array $note): self {
557		$this->notes[$key] = $note;
558
559		return $this;
560	}
561
562	/**
563	 * @param string $key
564	 * @param JsonSerializable $obj
565	 *
566	 * @return $this
567	 */
568	public function setNoteObj(string $key, JsonSerializable $obj): self {
569		$this->notes[$key] = $obj;
570
571		return $this;
572	}
573
574
575	/**
576	 * @param string $displayName
577	 *
578	 * @return Member
579	 */
580	public function setDisplayName(string $displayName): self {
581		if ($displayName !== '') {
582			$this->displayName = $displayName;
583		}
584
585		return $this;
586	}
587
588
589	/**
590	 * @param int $displayUpdate
591	 *
592	 * @return Member
593	 */
594	public function setDisplayUpdate(int $displayUpdate): self {
595		$this->displayUpdate = $displayUpdate;
596
597		return $this;
598	}
599
600	/**
601	 * @return int
602	 */
603	public function getDisplayUpdate(): int {
604		return $this->displayUpdate;
605	}
606
607
608	/**
609	 * @return string
610	 */
611	public function getDisplayName(): string {
612		return $this->displayName;
613	}
614
615
616	/**
617	 * @param string $contactId
618	 *
619	 * @return Member
620	 */
621	public function setContactId(string $contactId): self {
622		$this->contactId = $contactId;
623
624		return $this;
625	}
626
627	/**
628	 * @return string
629	 */
630	public function getContactId(): string {
631		return $this->contactId;
632	}
633
634
635	/**
636	 * @param string $contactMeta
637	 *
638	 * @return Member
639	 */
640	public function setContactMeta(string $contactMeta): self {
641		$this->contactMeta = $contactMeta;
642
643		return $this;
644	}
645
646	/**
647	 * @return string
648	 */
649	public function getContactMeta(): string {
650		return $this->contactMeta;
651	}
652
653
654	/**
655	 * @param Circle $circle
656	 *
657	 * @return self
658	 */
659	public function setCircle(Circle $circle): self {
660		$this->circle = $circle;
661
662		return $this;
663	}
664
665	/**
666	 * @return Circle
667	 */
668	public function getCircle(): Circle {
669		return $this->circle;
670	}
671
672	/**
673	 * @return bool
674	 */
675	public function hasCircle(): bool {
676		return (!is_null($this->circle));
677	}
678
679
680	/**
681	 * @param int $joined
682	 *
683	 * @return Member
684	 */
685	public function setJoined(int $joined): self {
686		$this->joined = $joined;
687
688		return $this;
689	}
690
691	/**
692	 * @return int
693	 */
694	public function getJoined(): int {
695		return $this->joined;
696	}
697
698
699	/**
700	 * @return bool
701	 */
702	public function hasMemberships(): bool {
703		return !is_null($this->memberships);
704	}
705
706	/**
707	 * @param array $memberships
708	 *
709	 * @return self
710	 */
711	public function setMemberships(array $memberships): IEntity {
712		$this->memberships = $memberships;
713
714		return $this;
715	}
716
717	/**
718	 * @return Membership[]
719	 */
720	public function getMemberships(): array {
721		if (is_null($this->memberships)) {
722			$this->getManager()->getMemberships($this);
723		}
724
725		return $this->memberships;
726	}
727
728
729	/**
730	 * @param string $singleId
731	 * @param bool $detailed
732	 *
733	 * @return Membership
734	 * @throws MembershipNotFoundException
735	 * @throws RequestBuilderException
736	 */
737	public function getLink(string $singleId, bool $detailed = false): Membership {
738		$this->getManager()->getLink($this, $singleId, $detailed);
739
740		throw new MembershipNotFoundException();
741	}
742
743	/**
744	 * @param string $circleId
745	 * @param bool $detailed
746	 *
747	 * @return Membership
748	 * @throws MembershipNotFoundException
749	 * @throws RequestBuilderException
750	 * @deprecated - use getLink();
751	 */
752	public function getMembership(string $circleId, bool $detailed = false): Membership {
753		return $this->getLink($circleId, $detailed);
754	}
755
756
757	/**
758	 * @param Member $member
759	 * @param bool $full
760	 *
761	 * @return bool
762	 */
763	public function compareWith(Member $member, bool $full = true): bool {
764		if ($this->getId() !== $member->getId()
765			|| $this->getCircleId() !== $member->getCircleId()
766			|| $this->getSingleId() !== $member->getSingleId()
767			|| $this->getUserId() !== $member->getUserId()
768			|| $this->getUserType() <> $member->getUserType()
769			|| $this->getInstance() !== $member->getInstance()) {
770			return false;
771		}
772
773		if ($full
774			&& ($this->getLevel() <> $member->getLevel()
775				|| $this->getStatus() !== $member->getStatus())) {
776			return false;
777		}
778
779		return true;
780	}
781
782
783	/**
784	 * @param array $data
785	 *
786	 * @return $this
787	 * @throws InvalidItemException
788	 */
789	public function import(array $data): IDeserializable {
790		if ($this->get('userId', $data) === '') {
791			throw new InvalidItemException();
792		}
793
794		$this->setId($this->get('id', $data));
795		$this->setCircleId($this->get('circleId', $data));
796		$this->setSingleId($this->get('singleId', $data));
797		$this->setUserId($this->get('userId', $data));
798		$this->setUserType($this->getInt('userType', $data));
799		$this->setInstance($this->get('instance', $data));
800		$this->setLevel($this->getInt('level', $data));
801		$this->setStatus($this->get('status', $data));
802		$this->setDisplayName($this->get('displayName', $data));
803		$this->setDisplayUpdate($this->getInt('displayUpdate', $data));
804		$this->setNotes($this->getArray('notes', $data));
805		$this->setContactId($this->get('contactId', $data));
806		$this->setContactMeta($this->get('contactMeta', $data));
807		$this->setJoined($this->getInt('joined', $data));
808
809		try {
810			/** @var Circle $circle */
811			$circle = $this->deserialize($this->getArray('circle', $data), Circle::class);
812			$this->setCircle($circle);
813		} catch (InvalidItemException $e) {
814		}
815
816		try {
817			/** @var Circle $circle */
818			$circle = $this->deserialize($this->getArray('basedOn', $data), Circle::class);
819			$this->setBasedOn($circle);
820		} catch (InvalidItemException $e) {
821		}
822
823		try {
824			/** @var FederatedUser $invitedBy */
825			$invitedBy = $this->deserialize($this->getArray('invitedBy', $data), FederatedUser::class);
826			$this->setInvitedBy($invitedBy);
827		} catch (InvalidItemException $e) {
828		}
829
830		try {
831			/** @var FederatedUSer $inheritedBy */
832			$inheritedBy = $this->deserialize($this->getArray('inheritedBy', $data), Membership::class);
833			$this->setInheritedBy($inheritedBy);
834		} catch (InvalidItemException $e) {
835		}
836
837		return $this;
838	}
839
840
841	/**
842	 * @param array $data
843	 * @param string $prefix
844	 *
845	 * @return INC22QueryRow
846	 * @throws MemberNotFoundException
847	 */
848	public function importFromDatabase(array $data, string $prefix = ''): INC22QueryRow {
849		if ($this->get($prefix . 'single_id', $data) === '') {
850			throw new MemberNotFoundException();
851		}
852
853		$this->setId($this->get($prefix . 'member_id', $data));
854		$this->setCircleId($this->get($prefix . 'circle_id', $data));
855		$this->setSingleId($this->get($prefix . 'single_id', $data));
856		$this->setUserId($this->get($prefix . 'user_id', $data));
857		$this->setUserType($this->getInt($prefix . 'user_type', $data));
858		$this->setInstance($this->get($prefix . 'instance', $data));
859		$this->setLevel($this->getInt($prefix . 'level', $data));
860		$this->setStatus($this->get($prefix . 'status', $data));
861		$this->setDisplayName($this->get($prefix . 'cached_name', $data));
862		$this->setNotes($this->getArray($prefix . 'note', $data));
863		$this->setContactId($this->get($prefix . 'contact_id', $data));
864		$this->setContactMeta($this->get($prefix . 'contact_meta', $data));
865
866		$cachedUpdate = $this->get($prefix . 'cached_update', $data);
867		if ($cachedUpdate !== '') {
868			$this->setDisplayUpdate(DateTime::createFromFormat('Y-m-d H:i:s', $cachedUpdate)->getTimestamp());
869		}
870
871		$joined = $this->get($prefix . 'joined', $data);
872		if ($joined !== '') {
873			$this->setJoined(DateTime::createFromFormat('Y-m-d H:i:s', $joined)->getTimestamp());
874		}
875
876		if ($this->getInstance() === '') {
877			$this->setInstance($this->getManager()->getLocalInstance());
878		}
879
880		$this->getManager()->manageImportFromDatabase($this, $data, $prefix);
881
882		// in case invitedBy is not obtainable from 'invited_by', we reach data from 'note'
883		if (!$this->hasInvitedBy()) {
884			$invitedByArray = $this->getNoteArray('invitedBy');
885			if (!empty($invitedByArray)) {
886				try {
887					$invitedBy = new FederatedUser();
888					$this->setInvitedBy($invitedBy->import($invitedByArray));
889				} catch (InvalidItemException $e) {
890				}
891			}
892		}
893
894		return $this;
895	}
896
897
898	/**
899	 * @return string[]
900	 * @throws UnknownInterfaceException
901	 */
902	public function jsonSerialize(): array {
903		$arr = [
904			'id' => $this->getId(),
905			'circleId' => $this->getCircleId(),
906			'singleId' => $this->getSingleId(),
907			'userId' => $this->getUserId(),
908			'userType' => $this->getUserType(),
909			'instance' => $this->getManager()->fixInstance($this->getInstance()),
910			'local' => $this->isLocal(),
911			'level' => $this->getLevel(),
912			'status' => $this->getStatus(),
913			'displayName' => $this->getDisplayName(),
914			'displayUpdate' => $this->getDisplayUpdate(),
915			'notes' => $this->getNotes(),
916			'contactId' => $this->getContactId(),
917			'contactMeta' => $this->getContactMeta(),
918			'joined' => $this->getJoined()
919		];
920
921		if ($this->hasInvitedBy()) {
922			$arr['invitedBy'] = $this->getInvitedBy();
923		}
924
925		if ($this->hasBasedOn()) {
926			$arr['basedOn'] = $this->getBasedOn();
927		}
928
929		if ($this->hasInheritedBy()) {
930			$arr['inheritedBy'] = $this->getInheritedBy();
931		}
932
933		if ($this->hasInheritanceFrom()) {
934			$arr['inheritanceFrom'] = $this->getInheritanceFrom();
935		}
936
937		if ($this->hasCircle()) {
938			$arr['circle'] = $this->getCircle();
939		}
940
941		if ($this->hasMemberships()) {
942			$arr['memberships'] = $this->getMemberships();
943		}
944
945		if ($this->hasRemoteInstance()) {
946			$arr['remoteInstance'] = $this->getRemoteInstance();
947		}
948
949		return $arr;
950	}
951
952
953	/**
954	 * @param int $level
955	 *
956	 * @return int
957	 * @throws ParseMemberLevelException
958	 */
959	public static function parseLevelInt(int $level): int {
960		if (!array_key_exists($level, self::$DEF_LEVEL)) {
961			$all = implode(', ', array_keys(self::$DEF_LEVEL));
962			throw new ParseMemberLevelException('Available levels: ' . $all, 121);
963		}
964
965		return $level;
966	}
967
968
969	/**
970	 * @param string $levelString
971	 *
972	 * @return int
973	 * @throws ParseMemberLevelException
974	 */
975	public static function parseLevelString(string $levelString): int {
976		$levelString = ucfirst(strtolower($levelString));
977		$level = array_search($levelString, Member::$DEF_LEVEL);
978
979		if (!$level) {
980			$all = implode(', ', array_values(self::$DEF_LEVEL));
981			throw new ParseMemberLevelException('Available levels: ' . $all, 121);
982		}
983
984		return (int)$level;
985	}
986
987	/**
988	 * @param string $typeString
989	 *
990	 * @return int
991	 * @throws UserTypeNotFoundException
992	 */
993	public static function parseTypeString(string $typeString): int {
994		$typeString = strtolower($typeString);
995		if (array_key_exists($typeString, Member::$TYPE)) {
996			return (int)$typeString;
997		}
998
999		$type = array_search($typeString, Member::$TYPE);
1000		if ($type === false) {
1001			$all = implode(', ', array_values(self::$TYPE));
1002			throw new UserTypeNotFoundException('Available types: ' . $all);
1003		}
1004
1005		return (int)$type;
1006	}
1007}
1008