1#[allow(unused_imports)]
9use alloc::collections::BTreeMap;
10
11#[allow(unused_imports)]
12use core::marker::PhantomData;
13use jacquard_common::CowStr;
14
15#[allow(unused_imports)]
16use jacquard_common::deps::codegen::unicode_segmentation::UnicodeSegmentation;
17use jacquard_common::types::collection::{Collection, RecordError};
18use jacquard_common::types::string::{AtUri, Cid, Datetime, Language};
19use jacquard_common::types::uri::{RecordUri, UriError};
20use jacquard_common::xrpc::XrpcResp;
21use jacquard_derive::{IntoStatic, lexicon, open_union};
22use jacquard_lexicon::lexicon::LexiconDoc;
23use jacquard_lexicon::schema::LexiconSchema;
24
25#[allow(unused_imports)]
26use jacquard_lexicon::validation::{ConstraintError, ValidationPath};
27use serde::{Serialize, Deserialize};
28use crate::app_bsky::embed::external::ExternalRecord;
29use crate::app_bsky::embed::images::Images;
30use crate::app_bsky::embed::record::Record;
31use crate::app_bsky::embed::record_with_media::RecordWithMedia;
32use crate::app_bsky::embed::video::Video;
33use crate::app_bsky::richtext::facet::Facet;
34use crate::com_atproto::label::SelfLabels;
35use crate::com_atproto::repo::strong_ref::StrongRef;
36use crate::net_anisota::feed::draft;
37#[lexicon]
40#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
41#[serde(rename_all = "camelCase", rename = "net.anisota.feed.draft", tag = "$type")]
42pub struct Draft<'a> {
43 pub created_at: Datetime,
45 #[serde(skip_serializing_if = "Option::is_none")]
46 #[serde(borrow)]
47 pub embed: Option<DraftEmbed<'a>>,
48 #[serde(skip_serializing_if = "Option::is_none")]
50 #[serde(borrow)]
51 pub facets: Option<Vec<Facet<'a>>>,
52 #[serde(skip_serializing_if = "Option::is_none")]
54 #[serde(borrow)]
55 pub labels: Option<SelfLabels<'a>>,
56 #[serde(skip_serializing_if = "Option::is_none")]
58 pub langs: Option<Vec<Language>>,
59 #[serde(skip_serializing_if = "Option::is_none")]
60 #[serde(borrow)]
61 pub reply: Option<draft::ReplyRef<'a>>,
62 #[serde(skip_serializing_if = "Option::is_none")]
64 #[serde(borrow)]
65 pub tags: Option<Vec<CowStr<'a>>>,
66 #[serde(borrow)]
68 pub text: CowStr<'a>,
69 #[serde(skip_serializing_if = "Option::is_none")]
71 pub updated_at: Option<Datetime>,
72}
73
74
75#[open_union]
76#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
77#[serde(tag = "$type", bound(deserialize = "'de: 'a"))]
78pub enum DraftEmbed<'a> {
79 #[serde(rename = "app.bsky.embed.images")]
80 Images(Box<Images<'a>>),
81 #[serde(rename = "app.bsky.embed.video")]
82 Video(Box<Video<'a>>),
83 #[serde(rename = "app.bsky.embed.external")]
84 External(Box<ExternalRecord<'a>>),
85 #[serde(rename = "app.bsky.embed.record")]
86 Record(Box<Record<'a>>),
87 #[serde(rename = "app.bsky.embed.recordWithMedia")]
88 RecordWithMedia(Box<RecordWithMedia<'a>>),
89}
90
91#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
94#[serde(rename_all = "camelCase")]
95pub struct DraftGetRecordOutput<'a> {
96 #[serde(skip_serializing_if = "Option::is_none")]
97 #[serde(borrow)]
98 pub cid: Option<Cid<'a>>,
99 #[serde(borrow)]
100 pub uri: AtUri<'a>,
101 #[serde(borrow)]
102 pub value: Draft<'a>,
103}
104
105
106#[lexicon]
107#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, IntoStatic)]
108#[serde(rename_all = "camelCase")]
109pub struct ReplyRef<'a> {
110 #[serde(borrow)]
111 pub parent: StrongRef<'a>,
112 #[serde(borrow)]
113 pub root: StrongRef<'a>,
114}
115
116impl<'a> Draft<'a> {
117 pub fn uri(
118 uri: impl Into<CowStr<'a>>,
119 ) -> Result<RecordUri<'a, DraftRecord>, UriError> {
120 RecordUri::try_from_uri(AtUri::new_cow(uri.into())?)
121 }
122}
123
124#[derive(Debug, Serialize, Deserialize)]
127pub struct DraftRecord;
128impl XrpcResp for DraftRecord {
129 const NSID: &'static str = "net.anisota.feed.draft";
130 const ENCODING: &'static str = "application/json";
131 type Output<'de> = DraftGetRecordOutput<'de>;
132 type Err<'de> = RecordError<'de>;
133}
134
135impl From<DraftGetRecordOutput<'_>> for Draft<'_> {
136 fn from(output: DraftGetRecordOutput<'_>) -> Self {
137 use jacquard_common::IntoStatic;
138 output.value.into_static()
139 }
140}
141
142impl Collection for Draft<'_> {
143 const NSID: &'static str = "net.anisota.feed.draft";
144 type Record = DraftRecord;
145}
146
147impl Collection for DraftRecord {
148 const NSID: &'static str = "net.anisota.feed.draft";
149 type Record = DraftRecord;
150}
151
152impl<'a> LexiconSchema for Draft<'a> {
153 fn nsid() -> &'static str {
154 "net.anisota.feed.draft"
155 }
156 fn def_name() -> &'static str {
157 "main"
158 }
159 fn lexicon_doc() -> LexiconDoc<'static> {
160 lexicon_doc_net_anisota_feed_draft()
161 }
162 fn validate(&self) -> Result<(), ConstraintError> {
163 if let Some(ref value) = self.langs {
164 #[allow(unused_comparisons)]
165 if value.len() > 3usize {
166 return Err(ConstraintError::MaxLength {
167 path: ValidationPath::from_field("langs"),
168 max: 3usize,
169 actual: value.len(),
170 });
171 }
172 }
173 if let Some(ref value) = self.tags {
174 #[allow(unused_comparisons)]
175 if value.len() > 8usize {
176 return Err(ConstraintError::MaxLength {
177 path: ValidationPath::from_field("tags"),
178 max: 8usize,
179 actual: value.len(),
180 });
181 }
182 }
183 {
184 let value = &self.text;
185 #[allow(unused_comparisons)]
186 if <str>::len(value.as_ref()) > 3000usize {
187 return Err(ConstraintError::MaxLength {
188 path: ValidationPath::from_field("text"),
189 max: 3000usize,
190 actual: <str>::len(value.as_ref()),
191 });
192 }
193 }
194 {
195 let value = &self.text;
196 {
197 let count = UnicodeSegmentation::graphemes(value.as_ref(), true).count();
198 if count > 300usize {
199 return Err(ConstraintError::MaxGraphemes {
200 path: ValidationPath::from_field("text"),
201 max: 300usize,
202 actual: count,
203 });
204 }
205 }
206 }
207 Ok(())
208 }
209}
210
211impl<'a> LexiconSchema for ReplyRef<'a> {
212 fn nsid() -> &'static str {
213 "net.anisota.feed.draft"
214 }
215 fn def_name() -> &'static str {
216 "replyRef"
217 }
218 fn lexicon_doc() -> LexiconDoc<'static> {
219 lexicon_doc_net_anisota_feed_draft()
220 }
221 fn validate(&self) -> Result<(), ConstraintError> {
222 Ok(())
223 }
224}
225
226pub mod draft_state {
227
228 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
229 #[allow(unused)]
230 use ::core::marker::PhantomData;
231 mod sealed {
232 pub trait Sealed {}
233 }
234 pub trait State: sealed::Sealed {
236 type Text;
237 type CreatedAt;
238 }
239 pub struct Empty(());
241 impl sealed::Sealed for Empty {}
242 impl State for Empty {
243 type Text = Unset;
244 type CreatedAt = Unset;
245 }
246 pub struct SetText<S: State = Empty>(PhantomData<fn() -> S>);
248 impl<S: State> sealed::Sealed for SetText<S> {}
249 impl<S: State> State for SetText<S> {
250 type Text = Set<members::text>;
251 type CreatedAt = S::CreatedAt;
252 }
253 pub struct SetCreatedAt<S: State = Empty>(PhantomData<fn() -> S>);
255 impl<S: State> sealed::Sealed for SetCreatedAt<S> {}
256 impl<S: State> State for SetCreatedAt<S> {
257 type Text = S::Text;
258 type CreatedAt = Set<members::created_at>;
259 }
260 #[allow(non_camel_case_types)]
262 pub mod members {
263 pub struct text(());
265 pub struct created_at(());
267 }
268}
269
270pub struct DraftBuilder<'a, S: draft_state::State> {
272 _state: PhantomData<fn() -> S>,
273 _fields: (
274 Option<Datetime>,
275 Option<DraftEmbed<'a>>,
276 Option<Vec<Facet<'a>>>,
277 Option<SelfLabels<'a>>,
278 Option<Vec<Language>>,
279 Option<draft::ReplyRef<'a>>,
280 Option<Vec<CowStr<'a>>>,
281 Option<CowStr<'a>>,
282 Option<Datetime>,
283 ),
284 _lifetime: PhantomData<&'a ()>,
285}
286
287impl<'a> Draft<'a> {
288 pub fn new() -> DraftBuilder<'a, draft_state::Empty> {
290 DraftBuilder::new()
291 }
292}
293
294impl<'a> DraftBuilder<'a, draft_state::Empty> {
295 pub fn new() -> Self {
297 DraftBuilder {
298 _state: PhantomData,
299 _fields: (None, None, None, None, None, None, None, None, None),
300 _lifetime: PhantomData,
301 }
302 }
303}
304
305impl<'a, S> DraftBuilder<'a, S>
306where
307 S: draft_state::State,
308 S::CreatedAt: draft_state::IsUnset,
309{
310 pub fn created_at(
312 mut self,
313 value: impl Into<Datetime>,
314 ) -> DraftBuilder<'a, draft_state::SetCreatedAt<S>> {
315 self._fields.0 = Option::Some(value.into());
316 DraftBuilder {
317 _state: PhantomData,
318 _fields: self._fields,
319 _lifetime: PhantomData,
320 }
321 }
322}
323
324impl<'a, S: draft_state::State> DraftBuilder<'a, S> {
325 pub fn embed(mut self, value: impl Into<Option<DraftEmbed<'a>>>) -> Self {
327 self._fields.1 = value.into();
328 self
329 }
330 pub fn maybe_embed(mut self, value: Option<DraftEmbed<'a>>) -> Self {
332 self._fields.1 = value;
333 self
334 }
335}
336
337impl<'a, S: draft_state::State> DraftBuilder<'a, S> {
338 pub fn facets(mut self, value: impl Into<Option<Vec<Facet<'a>>>>) -> Self {
340 self._fields.2 = value.into();
341 self
342 }
343 pub fn maybe_facets(mut self, value: Option<Vec<Facet<'a>>>) -> Self {
345 self._fields.2 = value;
346 self
347 }
348}
349
350impl<'a, S: draft_state::State> DraftBuilder<'a, S> {
351 pub fn labels(mut self, value: impl Into<Option<SelfLabels<'a>>>) -> Self {
353 self._fields.3 = value.into();
354 self
355 }
356 pub fn maybe_labels(mut self, value: Option<SelfLabels<'a>>) -> Self {
358 self._fields.3 = value;
359 self
360 }
361}
362
363impl<'a, S: draft_state::State> DraftBuilder<'a, S> {
364 pub fn langs(mut self, value: impl Into<Option<Vec<Language>>>) -> Self {
366 self._fields.4 = value.into();
367 self
368 }
369 pub fn maybe_langs(mut self, value: Option<Vec<Language>>) -> Self {
371 self._fields.4 = value;
372 self
373 }
374}
375
376impl<'a, S: draft_state::State> DraftBuilder<'a, S> {
377 pub fn reply(mut self, value: impl Into<Option<draft::ReplyRef<'a>>>) -> Self {
379 self._fields.5 = value.into();
380 self
381 }
382 pub fn maybe_reply(mut self, value: Option<draft::ReplyRef<'a>>) -> Self {
384 self._fields.5 = value;
385 self
386 }
387}
388
389impl<'a, S: draft_state::State> DraftBuilder<'a, S> {
390 pub fn tags(mut self, value: impl Into<Option<Vec<CowStr<'a>>>>) -> Self {
392 self._fields.6 = value.into();
393 self
394 }
395 pub fn maybe_tags(mut self, value: Option<Vec<CowStr<'a>>>) -> Self {
397 self._fields.6 = value;
398 self
399 }
400}
401
402impl<'a, S> DraftBuilder<'a, S>
403where
404 S: draft_state::State,
405 S::Text: draft_state::IsUnset,
406{
407 pub fn text(
409 mut self,
410 value: impl Into<CowStr<'a>>,
411 ) -> DraftBuilder<'a, draft_state::SetText<S>> {
412 self._fields.7 = Option::Some(value.into());
413 DraftBuilder {
414 _state: PhantomData,
415 _fields: self._fields,
416 _lifetime: PhantomData,
417 }
418 }
419}
420
421impl<'a, S: draft_state::State> DraftBuilder<'a, S> {
422 pub fn updated_at(mut self, value: impl Into<Option<Datetime>>) -> Self {
424 self._fields.8 = value.into();
425 self
426 }
427 pub fn maybe_updated_at(mut self, value: Option<Datetime>) -> Self {
429 self._fields.8 = value;
430 self
431 }
432}
433
434impl<'a, S> DraftBuilder<'a, S>
435where
436 S: draft_state::State,
437 S::Text: draft_state::IsSet,
438 S::CreatedAt: draft_state::IsSet,
439{
440 pub fn build(self) -> Draft<'a> {
442 Draft {
443 created_at: self._fields.0.unwrap(),
444 embed: self._fields.1,
445 facets: self._fields.2,
446 labels: self._fields.3,
447 langs: self._fields.4,
448 reply: self._fields.5,
449 tags: self._fields.6,
450 text: self._fields.7.unwrap(),
451 updated_at: self._fields.8,
452 extra_data: Default::default(),
453 }
454 }
455 pub fn build_with_data(
457 self,
458 extra_data: BTreeMap<
459 jacquard_common::deps::smol_str::SmolStr,
460 jacquard_common::types::value::Data<'a>,
461 >,
462 ) -> Draft<'a> {
463 Draft {
464 created_at: self._fields.0.unwrap(),
465 embed: self._fields.1,
466 facets: self._fields.2,
467 labels: self._fields.3,
468 langs: self._fields.4,
469 reply: self._fields.5,
470 tags: self._fields.6,
471 text: self._fields.7.unwrap(),
472 updated_at: self._fields.8,
473 extra_data: Some(extra_data),
474 }
475 }
476}
477
478fn lexicon_doc_net_anisota_feed_draft() -> LexiconDoc<'static> {
479 #[allow(unused_imports)]
480 use jacquard_common::{CowStr, deps::smol_str::SmolStr, types::blob::MimeType};
481 use jacquard_lexicon::lexicon::*;
482 use alloc::collections::BTreeMap;
483 LexiconDoc {
484 lexicon: Lexicon::Lexicon1,
485 id: CowStr::new_static("net.anisota.feed.draft"),
486 defs: {
487 let mut map = BTreeMap::new();
488 map.insert(
489 SmolStr::new_static("main"),
490 LexUserType::Record(LexRecord {
491 description: Some(
492 CowStr::new_static(
493 "Record containing a draft post that can be edited and later published as app.bsky.feed.post",
494 ),
495 ),
496 key: Some(CowStr::new_static("tid")),
497 record: LexRecordRecord::Object(LexObject {
498 required: Some(
499 vec![
500 SmolStr::new_static("text"),
501 SmolStr::new_static("createdAt")
502 ],
503 ),
504 properties: {
505 #[allow(unused_mut)]
506 let mut map = BTreeMap::new();
507 map.insert(
508 SmolStr::new_static("createdAt"),
509 LexObjectProperty::String(LexString {
510 description: Some(
511 CowStr::new_static(
512 "Client-declared timestamp when this draft was originally created.",
513 ),
514 ),
515 format: Some(LexStringFormat::Datetime),
516 ..Default::default()
517 }),
518 );
519 map.insert(
520 SmolStr::new_static("embed"),
521 LexObjectProperty::Union(LexRefUnion {
522 refs: vec![
523 CowStr::new_static("app.bsky.embed.images"),
524 CowStr::new_static("app.bsky.embed.video"),
525 CowStr::new_static("app.bsky.embed.external"),
526 CowStr::new_static("app.bsky.embed.record"),
527 CowStr::new_static("app.bsky.embed.recordWithMedia")
528 ],
529 ..Default::default()
530 }),
531 );
532 map.insert(
533 SmolStr::new_static("facets"),
534 LexObjectProperty::Array(LexArray {
535 description: Some(
536 CowStr::new_static(
537 "Annotations of text (mentions, URLs, hashtags, etc)",
538 ),
539 ),
540 items: LexArrayItem::Ref(LexRef {
541 r#ref: CowStr::new_static("app.bsky.richtext.facet"),
542 ..Default::default()
543 }),
544 ..Default::default()
545 }),
546 );
547 map.insert(
548 SmolStr::new_static("labels"),
549 LexObjectProperty::Union(LexRefUnion {
550 description: Some(
551 CowStr::new_static(
552 "Self-label values for this post. Effectively content warnings.",
553 ),
554 ),
555 refs: vec![
556 CowStr::new_static("com.atproto.label.defs#selfLabels")
557 ],
558 ..Default::default()
559 }),
560 );
561 map.insert(
562 SmolStr::new_static("langs"),
563 LexObjectProperty::Array(LexArray {
564 description: Some(
565 CowStr::new_static(
566 "Indicates human language of post primary text content.",
567 ),
568 ),
569 items: LexArrayItem::String(LexString {
570 format: Some(LexStringFormat::Language),
571 ..Default::default()
572 }),
573 max_length: Some(3usize),
574 ..Default::default()
575 }),
576 );
577 map.insert(
578 SmolStr::new_static("reply"),
579 LexObjectProperty::Ref(LexRef {
580 r#ref: CowStr::new_static("#replyRef"),
581 ..Default::default()
582 }),
583 );
584 map.insert(
585 SmolStr::new_static("tags"),
586 LexObjectProperty::Array(LexArray {
587 description: Some(
588 CowStr::new_static(
589 "Additional hashtags, in addition to any included in post text and facets.",
590 ),
591 ),
592 items: LexArrayItem::String(LexString {
593 max_length: Some(640usize),
594 max_graphemes: Some(64usize),
595 ..Default::default()
596 }),
597 max_length: Some(8usize),
598 ..Default::default()
599 }),
600 );
601 map.insert(
602 SmolStr::new_static("text"),
603 LexObjectProperty::String(LexString {
604 description: Some(
605 CowStr::new_static(
606 "The primary post content. May be an empty string, if there are embeds.",
607 ),
608 ),
609 max_length: Some(3000usize),
610 max_graphemes: Some(300usize),
611 ..Default::default()
612 }),
613 );
614 map.insert(
615 SmolStr::new_static("updatedAt"),
616 LexObjectProperty::String(LexString {
617 description: Some(
618 CowStr::new_static(
619 "Client-declared timestamp when this draft was last updated.",
620 ),
621 ),
622 format: Some(LexStringFormat::Datetime),
623 ..Default::default()
624 }),
625 );
626 map
627 },
628 ..Default::default()
629 }),
630 ..Default::default()
631 }),
632 );
633 map.insert(
634 SmolStr::new_static("replyRef"),
635 LexUserType::Object(LexObject {
636 required: Some(
637 vec![SmolStr::new_static("root"), SmolStr::new_static("parent")],
638 ),
639 properties: {
640 #[allow(unused_mut)]
641 let mut map = BTreeMap::new();
642 map.insert(
643 SmolStr::new_static("parent"),
644 LexObjectProperty::Ref(LexRef {
645 r#ref: CowStr::new_static("com.atproto.repo.strongRef"),
646 ..Default::default()
647 }),
648 );
649 map.insert(
650 SmolStr::new_static("root"),
651 LexObjectProperty::Ref(LexRef {
652 r#ref: CowStr::new_static("com.atproto.repo.strongRef"),
653 ..Default::default()
654 }),
655 );
656 map
657 },
658 ..Default::default()
659 }),
660 );
661 map
662 },
663 ..Default::default()
664 }
665}
666
667pub mod reply_ref_state {
668
669 pub use crate::builder_types::{Set, Unset, IsSet, IsUnset};
670 #[allow(unused)]
671 use ::core::marker::PhantomData;
672 mod sealed {
673 pub trait Sealed {}
674 }
675 pub trait State: sealed::Sealed {
677 type Parent;
678 type Root;
679 }
680 pub struct Empty(());
682 impl sealed::Sealed for Empty {}
683 impl State for Empty {
684 type Parent = Unset;
685 type Root = Unset;
686 }
687 pub struct SetParent<S: State = Empty>(PhantomData<fn() -> S>);
689 impl<S: State> sealed::Sealed for SetParent<S> {}
690 impl<S: State> State for SetParent<S> {
691 type Parent = Set<members::parent>;
692 type Root = S::Root;
693 }
694 pub struct SetRoot<S: State = Empty>(PhantomData<fn() -> S>);
696 impl<S: State> sealed::Sealed for SetRoot<S> {}
697 impl<S: State> State for SetRoot<S> {
698 type Parent = S::Parent;
699 type Root = Set<members::root>;
700 }
701 #[allow(non_camel_case_types)]
703 pub mod members {
704 pub struct parent(());
706 pub struct root(());
708 }
709}
710
711pub struct ReplyRefBuilder<'a, S: reply_ref_state::State> {
713 _state: PhantomData<fn() -> S>,
714 _fields: (Option<StrongRef<'a>>, Option<StrongRef<'a>>),
715 _lifetime: PhantomData<&'a ()>,
716}
717
718impl<'a> ReplyRef<'a> {
719 pub fn new() -> ReplyRefBuilder<'a, reply_ref_state::Empty> {
721 ReplyRefBuilder::new()
722 }
723}
724
725impl<'a> ReplyRefBuilder<'a, reply_ref_state::Empty> {
726 pub fn new() -> Self {
728 ReplyRefBuilder {
729 _state: PhantomData,
730 _fields: (None, None),
731 _lifetime: PhantomData,
732 }
733 }
734}
735
736impl<'a, S> ReplyRefBuilder<'a, S>
737where
738 S: reply_ref_state::State,
739 S::Parent: reply_ref_state::IsUnset,
740{
741 pub fn parent(
743 mut self,
744 value: impl Into<StrongRef<'a>>,
745 ) -> ReplyRefBuilder<'a, reply_ref_state::SetParent<S>> {
746 self._fields.0 = Option::Some(value.into());
747 ReplyRefBuilder {
748 _state: PhantomData,
749 _fields: self._fields,
750 _lifetime: PhantomData,
751 }
752 }
753}
754
755impl<'a, S> ReplyRefBuilder<'a, S>
756where
757 S: reply_ref_state::State,
758 S::Root: reply_ref_state::IsUnset,
759{
760 pub fn root(
762 mut self,
763 value: impl Into<StrongRef<'a>>,
764 ) -> ReplyRefBuilder<'a, reply_ref_state::SetRoot<S>> {
765 self._fields.1 = Option::Some(value.into());
766 ReplyRefBuilder {
767 _state: PhantomData,
768 _fields: self._fields,
769 _lifetime: PhantomData,
770 }
771 }
772}
773
774impl<'a, S> ReplyRefBuilder<'a, S>
775where
776 S: reply_ref_state::State,
777 S::Parent: reply_ref_state::IsSet,
778 S::Root: reply_ref_state::IsSet,
779{
780 pub fn build(self) -> ReplyRef<'a> {
782 ReplyRef {
783 parent: self._fields.0.unwrap(),
784 root: self._fields.1.unwrap(),
785 extra_data: Default::default(),
786 }
787 }
788 pub fn build_with_data(
790 self,
791 extra_data: BTreeMap<
792 jacquard_common::deps::smol_str::SmolStr,
793 jacquard_common::types::value::Data<'a>,
794 >,
795 ) -> ReplyRef<'a> {
796 ReplyRef {
797 parent: self._fields.0.unwrap(),
798 root: self._fields.1.unwrap(),
799 extra_data: Some(extra_data),
800 }
801 }
802}