mf_core/runtime/
builder.rs

1//! 统一运行时构建器
2//!
3//! 提供统一、流畅的运行时创建接口,支持:
4//! 1. 自动检测系统资源并选择最优运行时
5//! 2. 手动指定运行时类型
6//! 3. 使用配置文件创建运行时
7//! 4. 链式配置构建
8//!
9//! # 设计原则
10//!
11//! - **简单优先**:最常见的用例应该最简单
12//! - **渐进式配置**:从简单到复杂,逐步添加配置
13//! - **类型安全**:编译期捕获配置错误
14//! - **统一接口**:所有创建方式返回统一的运行时类型
15//!
16//! # 使用示例
17//!
18//! ## 1. 最简单的方式(推荐)
19//! ```rust
20//! use mf_core::ForgeRuntimeBuilder;
21//!
22//! // 自动检测系统资源,选择最优运行时和配置
23//! let runtime = ForgeRuntimeBuilder::new().build().await?;
24//! ```
25//!
26//! ## 2. 指定运行时类型
27//! ```rust
28//! use mf_core::{ForgeRuntimeBuilder, RuntimeType};
29//!
30//! // 明确使用 Actor 运行时
31//! let runtime = ForgeRuntimeBuilder::new()
32//!     .runtime_type(RuntimeType::Actor)
33//!     .build()
34//!     .await?;
35//! ```
36//!
37//! ## 3. 链式配置
38//! ```rust
39//! use mf_core::{ForgeRuntimeBuilder, RuntimeType, Extensions};
40//!
41//! let runtime = ForgeRuntimeBuilder::new()
42//!     .runtime_type(RuntimeType::Async)
43//!     .max_concurrent_tasks(20)
44//!     .queue_size(5000)
45//!     .enable_monitoring(true)
46//!     .history_limit(1000)
47//!     .extension(my_extension)
48//!     .build()
49//!     .await?;
50//! ```
51//!
52//! ## 4. 从配置文件
53//! ```rust
54//! use mf_core::ForgeRuntimeBuilder;
55//!
56//! let runtime = ForgeRuntimeBuilder::from_config_file("config.toml")
57//!     .await?
58//!     .build()
59//!     .await?;
60//! ```
61//!
62//! ## 5. 从 XML Schema
63//! ```rust
64//! use mf_core::ForgeRuntimeBuilder;
65//!
66//! let runtime = ForgeRuntimeBuilder::new()
67//!     .schema_path("schema/document.xml")
68//!     .build()
69//!     .await?;
70//! ```
71
72use crate::{
73    config::{ForgeConfig, RuntimeType, Environment},
74    debug::info,
75    runtime::{
76        adaptive::AdaptiveRuntimeSelector, actor_runtime::ForgeActorRuntime,
77        async_runtime::ForgeAsyncRuntime, runtime::ForgeRuntime,
78        runtime_trait::RuntimeTrait, system_detector::SystemResources,
79    },
80    types::{RuntimeOptions, Extensions, Content, EditorOptionsBuilder},
81    ForgeResult,
82};
83use std::sync::Arc;
84
85/// 统一运行时构建器
86///
87/// 提供流畅的链式 API 来配置和创建运行时。
88///
89/// # 设计特点
90///
91/// 1. **自动推断**:未指定的配置项会根据系统资源自动优化
92/// 2. **类型安全**:配置错误在编译期捕获
93/// 3. **灵活组合**:可以混合使用不同的配置方式
94/// 4. **统一返回**:始终返回 `AnyRuntime` 枚举,避免 trait object 开销
95///
96/// # 示例
97///
98/// ```rust
99/// // 最简单的用法
100/// let runtime = ForgeRuntimeBuilder::new().build().await?;
101///
102/// // 完全自定义
103/// let runtime = ForgeRuntimeBuilder::new()
104///     .runtime_type(RuntimeType::Actor)
105///     .environment(Environment::Production)
106///     .max_concurrent_tasks(20)
107///     .build()
108///     .await?;
109/// ```
110#[derive(Default)]
111pub struct ForgeRuntimeBuilder {
112    // 核心配置
113    runtime_type: Option<RuntimeType>,
114    environment: Option<Environment>,
115
116    // 运行时选项
117    content: Option<Content>,
118    extensions: Vec<Extensions>,
119    history_limit: Option<usize>,
120    event_handlers: Vec<
121        Arc<dyn crate::event::EventHandler<crate::event::Event> + Send + Sync>,
122    >,
123
124    // 性能配置
125    max_concurrent_tasks: Option<usize>,
126    queue_size: Option<usize>,
127    enable_monitoring: Option<bool>,
128    middleware_timeout_ms: Option<u64>,
129
130    // Schema 配置
131    schema_paths: Vec<String>,
132
133    // 完整配置(如果提供)
134    full_config: Option<ForgeConfig>,
135}
136
137impl ForgeRuntimeBuilder {
138    /// 创建新的构建器实例
139    ///
140    /// # 示例
141    /// ```rust
142    /// let builder = ForgeRuntimeBuilder::new();
143    /// ```
144    pub fn new() -> Self {
145        Self::default()
146    }
147
148    // ==================== 核心配置方法 ====================
149
150    /// 设置运行时类型
151    ///
152    /// 如果不设置,将根据系统资源自动选择。
153    ///
154    /// # 示例
155    /// ```rust
156    /// let builder = ForgeRuntimeBuilder::new()
157    ///     .runtime_type(RuntimeType::Actor);
158    /// ```
159    pub fn runtime_type(
160        mut self,
161        runtime_type: RuntimeType,
162    ) -> Self {
163        self.runtime_type = Some(runtime_type);
164        self
165    }
166
167    /// 设置运行环境
168    ///
169    /// 不同环境有不同的默认配置。
170    ///
171    /// # 示例
172    /// ```rust
173    /// let builder = ForgeRuntimeBuilder::new()
174    ///     .environment(Environment::Production);
175    /// ```
176    pub fn environment(
177        mut self,
178        environment: Environment,
179    ) -> Self {
180        self.environment = Some(environment);
181        self
182    }
183
184    // ==================== 内容和扩展配置 ====================
185
186    /// 设置初始内容
187    ///
188    /// # 示例
189    /// ```rust
190    /// let builder = ForgeRuntimeBuilder::new()
191    ///     .content(Content::Json(json_data));
192    /// ```
193    pub fn content(
194        mut self,
195        content: Content,
196    ) -> Self {
197        self.content = Some(content);
198        self
199    }
200
201    /// 添加扩展
202    ///
203    /// # 示例
204    /// ```rust
205    /// let builder = ForgeRuntimeBuilder::new()
206    ///     .extension(Extensions::N(my_node));
207    /// ```
208    pub fn extension(
209        mut self,
210        extension: Extensions,
211    ) -> Self {
212        self.extensions.push(extension);
213        self
214    }
215
216    /// 批量添加扩展
217    ///
218    /// # 示例
219    /// ```rust
220    /// let builder = ForgeRuntimeBuilder::new()
221    ///     .extensions(vec![ext1, ext2, ext3]);
222    /// ```
223    pub fn extensions(
224        mut self,
225        extensions: Vec<Extensions>,
226    ) -> Self {
227        self.extensions.extend(extensions);
228        self
229    }
230
231    /// 从 XML Schema 文件加载扩展
232    ///
233    /// # 示例
234    /// ```rust
235    /// let builder = ForgeRuntimeBuilder::new()
236    ///     .schema_path("schema/document.xml");
237    /// ```
238    pub fn schema_path(
239        mut self,
240        path: impl Into<String>,
241    ) -> Self {
242        self.schema_paths.push(path.into());
243        self
244    }
245
246    /// 从多个 XML Schema 文件加载扩展
247    ///
248    /// # 示例
249    /// ```rust
250    /// let builder = ForgeRuntimeBuilder::new()
251    ///     .schema_paths(vec!["schema/doc.xml", "schema/ui.xml"]);
252    /// ```
253    pub fn schema_paths(
254        mut self,
255        paths: Vec<String>,
256    ) -> Self {
257        self.schema_paths.extend(paths);
258        self
259    }
260
261    // ==================== 性能配置 ====================
262
263    /// 设置最大并发任务数
264    ///
265    /// 如果不设置,将根据 CPU 核心数自动计算。
266    ///
267    /// # 示例
268    /// ```rust
269    /// let builder = ForgeRuntimeBuilder::new()
270    ///     .max_concurrent_tasks(20);
271    /// ```
272    pub fn max_concurrent_tasks(
273        mut self,
274        count: usize,
275    ) -> Self {
276        self.max_concurrent_tasks = Some(count);
277        self
278    }
279
280    /// 设置任务队列大小
281    ///
282    /// 如果不设置,将根据可用内存自动计算。
283    ///
284    /// # 示例
285    /// ```rust
286    /// let builder = ForgeRuntimeBuilder::new()
287    ///     .queue_size(5000);
288    /// ```
289    pub fn queue_size(
290        mut self,
291        size: usize,
292    ) -> Self {
293        self.queue_size = Some(size);
294        self
295    }
296
297    /// 启用或禁用性能监控
298    ///
299    /// # 示例
300    /// ```rust
301    /// let builder = ForgeRuntimeBuilder::new()
302    ///     .enable_monitoring(true);
303    /// ```
304    pub fn enable_monitoring(
305        mut self,
306        enable: bool,
307    ) -> Self {
308        self.enable_monitoring = Some(enable);
309        self
310    }
311
312    /// 设置中间件超时时间(毫秒)
313    ///
314    /// # 示例
315    /// ```rust
316    /// let builder = ForgeRuntimeBuilder::new()
317    ///     .middleware_timeout_ms(1000);
318    /// ```
319    pub fn middleware_timeout_ms(
320        mut self,
321        timeout: u64,
322    ) -> Self {
323        self.middleware_timeout_ms = Some(timeout);
324        self
325    }
326
327    // ==================== 历史和事件配置 ====================
328
329    /// 设置历史记录限制
330    ///
331    /// # 示例
332    /// ```rust
333    /// let builder = ForgeRuntimeBuilder::new()
334    ///     .history_limit(1000);
335    /// ```
336    pub fn history_limit(
337        mut self,
338        limit: usize,
339    ) -> Self {
340        self.history_limit = Some(limit);
341        self
342    }
343
344    /// 添加事件处理器
345    ///
346    /// # 示例
347    /// ```rust
348    /// let builder = ForgeRuntimeBuilder::new()
349    ///     .event_handler(my_handler);
350    /// ```
351    pub fn event_handler(
352        mut self,
353        handler: Arc<
354            dyn crate::event::EventHandler<crate::event::Event> + Send + Sync,
355        >,
356    ) -> Self {
357        self.event_handlers.push(handler);
358        self
359    }
360
361    // ==================== 高级配置 ====================
362
363    /// 使用完整的 ForgeConfig
364    ///
365    /// 这会覆盖之前设置的所有配置项。
366    ///
367    /// # 示例
368    /// ```rust
369    /// let config = ForgeConfig::for_environment(Environment::Production);
370    /// let builder = ForgeRuntimeBuilder::new()
371    ///     .with_config(config);
372    /// ```
373    pub fn with_config(
374        mut self,
375        config: ForgeConfig,
376    ) -> Self {
377        self.full_config = Some(config);
378        self
379    }
380
381    /// 从 JSON 配置文件加载
382    ///
383    /// # 示例
384    /// ```rust
385    /// let builder = ForgeRuntimeBuilder::from_config_file("config.json").await?;
386    /// ```
387    pub async fn from_config_file(path: &str) -> ForgeResult<Self> {
388        let content = tokio::fs::read_to_string(path).await.map_err(|e| {
389            crate::error::error_utils::storage_error(format!(
390                "Failed to read config file: {}",
391                e
392            ))
393        })?;
394
395        let config: ForgeConfig =
396            serde_json::from_str(&content).map_err(|e| {
397                crate::error::error_utils::config_error(format!(
398                    "Failed to parse JSON config: {}",
399                    e
400                ))
401            })?;
402
403        Ok(Self::new().with_config(config))
404    }
405
406    // ==================== 构建方法 ====================
407
408    /// 构建运行时实例
409    ///
410    /// 这是最终的构建方法,会:
411    /// 1. 合并所有配置
412    /// 2. 检测系统资源(如果需要)
413    /// 3. 创建运行时实例
414    ///
415    /// # 返回值
416    /// * `ForgeResult<AnyRuntime>` - 运行时实例或错误
417    ///
418    /// # 示例
419    /// ```rust
420    /// let runtime = ForgeRuntimeBuilder::new()
421    ///     .runtime_type(RuntimeType::Async)
422    ///     .max_concurrent_tasks(20)
423    ///     .build()
424    ///     .await?;
425    /// ```
426    pub async fn build(self) -> ForgeResult<AnyRuntime> {
427        // 1. 构建最终配置
428        let (config, options) = self.build_config_and_options().await?;
429
430        // 2. 确定运行时类型
431        let runtime_type = match config.runtime.runtime_type {
432            RuntimeType::Auto => {
433                let resources = SystemResources::detect();
434                let selected =
435                    AdaptiveRuntimeSelector::select_runtime(&resources);
436
437                info!(
438                    "🖥️  系统资源: {} 核心 / {} 线程, {} GB 内存 ({})",
439                    resources.cpu_cores,
440                    resources.cpu_threads,
441                    resources.total_memory_mb / 1024,
442                    resources.tier_description()
443                );
444                info!("⚡ 自动选择运行时: {:?}", selected);
445
446                selected
447            },
448            rt => {
449                info!("⚡ 使用指定运行时: {:?}", rt);
450                rt
451            },
452        };
453
454        // 3. 创建运行时实例
455        Self::create_runtime(runtime_type, options, config).await
456    }
457
458    /// 构建配置和选项
459    async fn build_config_and_options(
460        self
461    ) -> ForgeResult<(ForgeConfig, RuntimeOptions)> {
462        // 如果提供了完整配置,使用它作为基础
463        let mut config = self.full_config.unwrap_or_else(|| {
464            // 否则,根据环境创建默认配置
465            match self.environment {
466                Some(env) => ForgeConfig::for_environment(env),
467                None => {
468                    // 检测系统资源并生成自适应配置
469                    let resources = SystemResources::detect();
470                    AdaptiveRuntimeSelector::generate_config(&resources)
471                },
472            }
473        });
474
475        // 应用用户指定的配置覆盖
476        if let Some(rt) = self.runtime_type {
477            config.runtime.runtime_type = rt;
478        }
479        if let Some(tasks) = self.max_concurrent_tasks {
480            config.processor.max_concurrent_tasks = tasks;
481        }
482        if let Some(size) = self.queue_size {
483            config.processor.max_queue_size = size;
484        }
485        if let Some(enable) = self.enable_monitoring {
486            config.performance.enable_monitoring = enable;
487        }
488        if let Some(timeout) = self.middleware_timeout_ms {
489            config.performance.middleware_timeout_ms = timeout;
490        }
491
492        // 如果指定了 schema 路径,添加到配置中
493        if !self.schema_paths.is_empty() {
494            config.extension.xml_schema_paths = self.schema_paths;
495        }
496
497        // 构建 RuntimeOptions
498        let mut options_builder = EditorOptionsBuilder::new();
499
500        if let Some(content) = self.content {
501            options_builder = options_builder.content(content);
502        }
503
504        options_builder = options_builder.extensions(self.extensions);
505
506        if let Some(limit) = self.history_limit {
507            options_builder = options_builder.history_limit(limit);
508        }
509
510        options_builder = options_builder.event_handlers(self.event_handlers);
511
512        let options = options_builder.build();
513
514        Ok((config, options))
515    }
516
517    /// 创建运行时实例
518    async fn create_runtime(
519        runtime_type: RuntimeType,
520        options: RuntimeOptions,
521        config: ForgeConfig,
522    ) -> ForgeResult<AnyRuntime> {
523        match runtime_type {
524            RuntimeType::Sync => {
525                let runtime =
526                    ForgeRuntime::create_with_config(options, config).await?;
527                Ok(AnyRuntime::Sync(runtime))
528            },
529            RuntimeType::Async => {
530                let runtime =
531                    ForgeAsyncRuntime::create_with_config(options, config)
532                        .await?;
533                Ok(AnyRuntime::Async(runtime))
534            },
535            RuntimeType::Actor => {
536                let runtime =
537                    ForgeActorRuntime::create_with_config(options, config)
538                        .await?;
539                Ok(AnyRuntime::Actor(runtime))
540            },
541            RuntimeType::Auto => {
542                unreachable!("Auto should be resolved before this point")
543            },
544        }
545    }
546}
547
548/// 统一的运行时枚举
549///
550/// 相比 `Box<dyn RuntimeTrait>`,这个枚举:
551/// - 避免了动态分发的性能开销
552/// - 保留了具体类型信息
553/// - 支持类型特化优化
554/// - 可以添加运行时特有的方法
555///
556/// # 示例
557/// ```rust
558/// let runtime = ForgeRuntimeBuilder::new().build().await?;
559///
560/// match &runtime {
561///     AnyRuntime::Sync(rt) => println!("Using sync runtime"),
562///     AnyRuntime::Async(rt) => println!("Using async runtime"),
563///     AnyRuntime::Actor(rt) => println!("Using actor runtime"),
564/// }
565/// ```
566pub enum AnyRuntime {
567    Sync(ForgeRuntime),
568    Async(ForgeAsyncRuntime),
569    Actor(ForgeActorRuntime),
570}
571
572impl AnyRuntime {
573    /// 获取运行时类型
574    pub fn runtime_type(&self) -> RuntimeType {
575        match self {
576            Self::Sync(_) => RuntimeType::Sync,
577            Self::Async(_) => RuntimeType::Async,
578            Self::Actor(_) => RuntimeType::Actor,
579        }
580    }
581
582    /// 尝试获取 Sync 运行时的引用
583    pub fn as_sync(&self) -> Option<&ForgeRuntime> {
584        match self {
585            Self::Sync(rt) => Some(rt),
586            _ => None,
587        }
588    }
589
590    /// 尝试获取 Async 运行时的引用
591    pub fn as_async(&self) -> Option<&ForgeAsyncRuntime> {
592        match self {
593            Self::Async(rt) => Some(rt),
594            _ => None,
595        }
596    }
597
598    /// 尝试获取 Actor 运行时的引用
599    pub fn as_actor(&self) -> Option<&ForgeActorRuntime> {
600        match self {
601            Self::Actor(rt) => Some(rt),
602            _ => None,
603        }
604    }
605
606    /// 尝试获取 Sync 运行时的可变引用
607    pub fn as_sync_mut(&mut self) -> Option<&mut ForgeRuntime> {
608        match self {
609            Self::Sync(rt) => Some(rt),
610            _ => None,
611        }
612    }
613
614    /// 尝试获取 Async 运行时的可变引用
615    pub fn as_async_mut(&mut self) -> Option<&mut ForgeAsyncRuntime> {
616        match self {
617            Self::Async(rt) => Some(rt),
618            _ => None,
619        }
620    }
621
622    /// 尝试获取 Actor 运行时的可变引用
623    pub fn as_actor_mut(&mut self) -> Option<&mut ForgeActorRuntime> {
624        match self {
625            Self::Actor(rt) => Some(rt),
626            _ => None,
627        }
628    }
629}
630
631// 为 AnyRuntime 提供便捷方法(委托给具体的运行时)
632impl AnyRuntime {
633    /// 分发事务
634    pub async fn dispatch(
635        &mut self,
636        transaction: mf_state::Transaction,
637    ) -> ForgeResult<()> {
638        match self {
639            Self::Sync(rt) => rt.dispatch(transaction).await,
640            Self::Async(rt) => rt.dispatch(transaction).await,
641            Self::Actor(rt) => rt.dispatch(transaction).await,
642        }
643    }
644
645    /// 分发事务(带元信息)
646    pub async fn dispatch_with_meta(
647        &mut self,
648        transaction: mf_state::Transaction,
649        description: String,
650        meta: serde_json::Value,
651    ) -> ForgeResult<()> {
652        match self {
653            Self::Sync(rt) => {
654                rt.dispatch_with_meta(transaction, description, meta).await
655            },
656            Self::Async(rt) => {
657                rt.dispatch_with_meta(transaction, description, meta).await
658            },
659            Self::Actor(rt) => {
660                rt.dispatch_with_meta(transaction, description, meta).await
661            },
662        }
663    }
664
665    /// 执行命令
666    pub async fn command(
667        &mut self,
668        command: Arc<dyn mf_state::transaction::Command>,
669    ) -> ForgeResult<()> {
670        match self {
671            Self::Sync(rt) => rt.command(command).await,
672            Self::Async(rt) => rt.command(command).await,
673            Self::Actor(rt) => rt.command(command).await,
674        }
675    }
676
677    /// 执行命令(带元信息)
678    pub async fn command_with_meta(
679        &mut self,
680        command: Arc<dyn mf_state::transaction::Command>,
681        description: String,
682        meta: serde_json::Value,
683    ) -> ForgeResult<()> {
684        match self {
685            Self::Sync(rt) => {
686                rt.command_with_meta(command, description, meta).await
687            },
688            Self::Async(rt) => {
689                rt.command_with_meta(command, description, meta).await
690            },
691            Self::Actor(rt) => {
692                rt.command_with_meta(command, description, meta).await
693            },
694        }
695    }
696
697    /// 获取当前状态
698    pub async fn get_state(&self) -> ForgeResult<Arc<mf_state::State>> {
699        match self {
700            Self::Sync(rt) => Ok(Arc::clone(rt.get_state())),
701            Self::Async(rt) => rt.get_state().await,
702            Self::Actor(rt) => rt.get_state().await,
703        }
704    }
705
706    /// 获取新事务
707    pub async fn get_tr(&self) -> ForgeResult<mf_state::Transaction> {
708        match self {
709            Self::Sync(rt) => Ok(rt.get_tr()),
710            Self::Async(rt) => rt.get_tr().await,
711            Self::Actor(rt) => rt.get_tr().await,
712        }
713    }
714
715    /// 获取文档
716    pub async fn doc(&self) -> ForgeResult<Arc<mf_model::NodePool>> {
717        match self {
718            Self::Sync(rt) => Ok(rt.doc()),
719            Self::Async(rt) => rt.doc().await,
720            Self::Actor(rt) => rt.doc().await,
721        }
722    }
723
724    /// 获取 Schema
725    pub async fn schema(&self) -> ForgeResult<Arc<mf_model::Schema>> {
726        match self {
727            Self::Sync(rt) => Ok(rt.get_schema()),
728            Self::Async(rt) => rt.get_schema().await,
729            Self::Actor(rt) => rt.get_schema().await,
730        }
731    }
732
733    /// 撤销
734    pub async fn undo(&mut self) -> ForgeResult<()> {
735        match self {
736            Self::Sync(rt) => {
737                rt.undo();
738                Ok(())
739            },
740            Self::Async(rt) => rt.undo().await,
741            Self::Actor(rt) => rt.undo().await,
742        }
743    }
744
745    /// 重做
746    pub async fn redo(&mut self) -> ForgeResult<()> {
747        match self {
748            Self::Sync(rt) => {
749                rt.redo();
750                Ok(())
751            },
752            Self::Async(rt) => rt.redo().await,
753            Self::Actor(rt) => rt.redo().await,
754        }
755    }
756
757    /// 跳转到指定历史位置
758    pub async fn jump(
759        &mut self,
760        steps: isize,
761    ) -> ForgeResult<()> {
762        match self {
763            Self::Sync(rt) => {
764                rt.jump(steps);
765                Ok(())
766            },
767            Self::Async(rt) => rt.jump(steps).await,
768            Self::Actor(rt) => rt.jump(steps).await,
769        }
770    }
771
772    /// 获取运行时配置
773    pub fn get_config(&self) -> &crate::config::ForgeConfig {
774        match self {
775            Self::Sync(rt) => rt.get_config(),
776            Self::Async(rt) => rt.get_config(),
777            Self::Actor(rt) => rt.get_config(),
778        }
779    }
780
781    /// 更新运行时配置
782    pub fn update_config(
783        &mut self,
784        config: crate::config::ForgeConfig,
785    ) {
786        match self {
787            Self::Sync(rt) => rt.update_config(config),
788            Self::Async(rt) => rt.update_config(config),
789            Self::Actor(rt) => rt.update_config(config),
790        }
791    }
792
793    /// 获取运行时选项
794    ///
795    /// 注意:Actor 运行时返回默认选项,因为它不直接持有 options
796    pub fn get_options(&self) -> crate::types::RuntimeOptions {
797        match self {
798            Self::Sync(rt) => rt.get_options().clone(),
799            Self::Async(rt) => rt.get_options().clone(),
800            Self::Actor(rt) => rt.get_options(),
801        }
802    }
803
804    /// 销毁运行时
805    pub async fn destroy(&mut self) -> ForgeResult<()> {
806        match self {
807            Self::Sync(rt) => rt.destroy().await,
808            Self::Async(rt) => rt.destroy().await,
809            Self::Actor(rt) => rt.destroy().await,
810        }
811    }
812}