From f6e33a59d5e49f4a4688b4098fd1fe26cb0aac1d Mon Sep 17 00:00:00 2001 From: "Nathan.fooo" <86001920+appflowy@users.noreply.github.com> Date: Wed, 5 Jun 2024 12:40:31 +0800 Subject: [PATCH 01/16] chore: fix document test (#5470) * chore: fix document test --- frontend/rust-lib/flowy-document/Cargo.toml | 1 + .../flowy-document/tests/document/document_redo_undo_test.rs | 1 + .../rust-lib/flowy-document/tests/document/document_test.rs | 4 ++++ frontend/rust-lib/flowy-document/tests/document/util.rs | 1 + 4 files changed, 7 insertions(+) diff --git a/frontend/rust-lib/flowy-document/Cargo.toml b/frontend/rust-lib/flowy-document/Cargo.toml index 813d87d589..1b2cf3c593 100644 --- a/frontend/rust-lib/flowy-document/Cargo.toml +++ b/frontend/rust-lib/flowy-document/Cargo.toml @@ -45,6 +45,7 @@ getrandom = { version = "0.2", features = ["js"] } tempfile = "3.4.0" tracing-subscriber = { version = "0.3.3", features = ["env-filter"] } collab-integrate = { workspace = true } +tokio = { workspace = true, features = ["rt", "rt-multi-thread"] } [build-dependencies] flowy-codegen.workspace = true diff --git a/frontend/rust-lib/flowy-document/tests/document/document_redo_undo_test.rs b/frontend/rust-lib/flowy-document/tests/document/document_redo_undo_test.rs index 54be6a2d52..fc8268fd71 100644 --- a/frontend/rust-lib/flowy-document/tests/document/document_redo_undo_test.rs +++ b/frontend/rust-lib/flowy-document/tests/document/document_redo_undo_test.rs @@ -22,6 +22,7 @@ async fn undo_redo_test() { .await; // open a document + test.open_document(&doc_id).await.unwrap(); let document = test.get_document(&doc_id).await.unwrap(); let document = document.lock(); let page_block = document.get_block(&data.page_id).unwrap(); diff --git a/frontend/rust-lib/flowy-document/tests/document/document_test.rs b/frontend/rust-lib/flowy-document/tests/document/document_test.rs index 1296bc3c7c..754cba2ef0 100644 --- a/frontend/rust-lib/flowy-document/tests/document/document_test.rs +++ b/frontend/rust-lib/flowy-document/tests/document/document_test.rs @@ -20,6 +20,7 @@ async fn restore_document() { .unwrap(); let data_a = test.get_document_data(&doc_id).await.unwrap(); assert_eq!(data_a, data); + test.open_document(&doc_id).await.unwrap(); let data_b = test .get_document(&doc_id) @@ -59,6 +60,7 @@ async fn document_apply_insert_action() { _ = test.create_document(uid, &doc_id, Some(data.clone())).await; // open a document + test.open_document(&doc_id).await.unwrap(); let document = test.get_document(&doc_id).await.unwrap(); let page_block = document.lock().get_block(&data.page_id).unwrap(); @@ -112,6 +114,7 @@ async fn document_apply_update_page_action() { _ = test.create_document(uid, &doc_id, Some(data.clone())).await; // open a document + test.open_document(&doc_id).await.unwrap(); let document = test.get_document(&doc_id).await.unwrap(); let page_block = document.lock().get_block(&data.page_id).unwrap(); @@ -155,6 +158,7 @@ async fn document_apply_update_action() { _ = test.create_document(uid, &doc_id, Some(data.clone())).await; // open a document + test.open_document(&doc_id).await.unwrap(); let document = test.get_document(&doc_id).await.unwrap(); let page_block = document.lock().get_block(&data.page_id).unwrap(); diff --git a/frontend/rust-lib/flowy-document/tests/document/util.rs b/frontend/rust-lib/flowy-document/tests/document/util.rs index 4367b4d157..b08a7ec079 100644 --- a/frontend/rust-lib/flowy-document/tests/document/util.rs +++ b/frontend/rust-lib/flowy-document/tests/document/util.rs @@ -123,6 +123,7 @@ pub async fn create_and_open_empty_document() -> (DocumentTest, Arc Date: Wed, 5 Jun 2024 14:08:19 +0800 Subject: [PATCH 02/16] feat: support server render html (#5471) * feat: node server * fix: replace node to bun --- .github/workflows/deploy_test_web.yaml | 2 +- frontend/appflowy_web_app/Dockerfile | 15 ++- frontend/appflowy_web_app/index.html | 22 +++- frontend/appflowy_web_app/nginx.conf | 17 ++- frontend/appflowy_web_app/pnpm-lock.yaml | 6 +- frontend/appflowy_web_app/server.cjs | 114 ++++++++++++++++++ .../components/editor/CollaborativeEditor.tsx | 1 + frontend/appflowy_web_app/start.sh | 10 ++ 8 files changed, 179 insertions(+), 8 deletions(-) create mode 100644 frontend/appflowy_web_app/server.cjs create mode 100644 frontend/appflowy_web_app/start.sh diff --git a/.github/workflows/deploy_test_web.yaml b/.github/workflows/deploy_test_web.yaml index 49a96458f9..f7d3339d77 100644 --- a/.github/workflows/deploy_test_web.yaml +++ b/.github/workflows/deploy_test_web.yaml @@ -62,7 +62,7 @@ jobs: with: SSH_PRIVATE_KEY: ${{ env.SSH_PRIVATE_KEY }} ARGS: "-rlgoDzvc -i" - SOURCE: "frontend/appflowy_web_app/dist frontend/appflowy_web_app/Dockerfile frontend/appflowy_web_app/nginx.conf frontend/appflowy_web_app/.env nginx-signed.crt nginx-signed.key" + SOURCE: "frontend/appflowy_web_app/dist frontend/appflowy_web_app/server.cjs frontend/appflowy_web_app/start.sh frontend/appflowy_web_app/Dockerfile frontend/appflowy_web_app/nginx.conf frontend/appflowy_web_app/.env nginx-signed.crt nginx-signed.key" REMOTE_HOST: ${{ env.REMOTE_HOST }} REMOTE_USER: ${{ env.REMOTE_USER }} EXCLUDE: "frontend/appflowy_web_app/dist/, frontend/appflowy_web_app/node_modules/" diff --git a/frontend/appflowy_web_app/Dockerfile b/frontend/appflowy_web_app/Dockerfile index e7094ffe14..97e3a85559 100644 --- a/frontend/appflowy_web_app/Dockerfile +++ b/frontend/appflowy_web_app/Dockerfile @@ -1,8 +1,14 @@ -FROM node:latest +FROM oven/bun:latest + +WORKDIR /app RUN apt-get update && \ apt-get install -y nginx +RUN bun install cheerio pino axios pino-pretty + +COPY . . + RUN addgroup --system nginx && \ adduser --system --no-create-home --disabled-login --ingroup nginx nginx @@ -18,6 +24,11 @@ COPY nginx-signed.key /etc/ssl/private/nginx-signed.key RUN chown -R nginx:nginx /etc/ssl/certs/nginx-signed.crt /etc/ssl/private/nginx-signed.key +COPY start.sh /app/start.sh + +RUN chmod +x /app/start.sh + + EXPOSE 80 443 -CMD ["nginx", "-g", "daemon off;"] +CMD ["/app/start.sh"] diff --git a/frontend/appflowy_web_app/index.html b/frontend/appflowy_web_app/index.html index 3d8bc89cd6..a71f082fc3 100644 --- a/frontend/appflowy_web_app/index.html +++ b/frontend/appflowy_web_app/index.html @@ -4,8 +4,28 @@ - AppFlowy + + + + + + + + + + +
diff --git a/frontend/appflowy_web_app/nginx.conf b/frontend/appflowy_web_app/nginx.conf index 56529cca1a..729255a778 100644 --- a/frontend/appflowy_web_app/nginx.conf +++ b/frontend/appflowy_web_app/nginx.conf @@ -30,6 +30,10 @@ http { gzip_http_version 1.0; + gzip_comp_level 5; + + gzip_vary on; + gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript application/wasm; # Existing server block for HTTP @@ -61,15 +65,22 @@ http { ssl_prefer_server_ciphers on; location / { - root /usr/share/nginx/html; - index index.html index.htm; - try_files $uri $uri/ /index.html; + proxy_pass http://localhost:3000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; } location /static/ { root /usr/share/nginx/html; expires 30d; access_log off; + location ~* \.wasm$ { + types { application/wasm wasm; } + default_type application/wasm; + } } location /appflowy.svg { diff --git a/frontend/appflowy_web_app/pnpm-lock.yaml b/frontend/appflowy_web_app/pnpm-lock.yaml index b3e7c8496a..37a34b9470 100644 --- a/frontend/appflowy_web_app/pnpm-lock.yaml +++ b/frontend/appflowy_web_app/pnpm-lock.yaml @@ -8862,7 +8862,7 @@ packages: /randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: - safe-buffer: 5.1.2 + safe-buffer: 5.2.1 dev: true /react-beautiful-dnd@13.1.1(react-dom@18.2.0)(react@18.2.0): @@ -9604,6 +9604,10 @@ packages: /safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: true + /safe-regex-test@1.0.3: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} diff --git a/frontend/appflowy_web_app/server.cjs b/frontend/appflowy_web_app/server.cjs new file mode 100644 index 0000000000..e13c337faa --- /dev/null +++ b/frontend/appflowy_web_app/server.cjs @@ -0,0 +1,114 @@ +const path = require('path'); +const fs = require('fs'); +const pino = require('pino'); +const cheerio = require('cheerio'); +const axios = require('axios'); + +const distDir = path.join(__dirname, 'dist'); +const indexPath = path.join(distDir, 'index.html'); + +const setOrUpdateMetaTag = ($, selector, attribute, content) => { + if ($(selector).length === 0) { + $('head').append(``); + } else { + $(selector).attr('content', content); + } +}; +// Create a new logger instance +const logger = pino({ + transport: { + target: 'pino-pretty', + level: 'info', + options: { + colorize: true, + translateTime: 'SYS:standard', + destination: `${__dirname}/pino-logger.log`, + }, + }, +}); + +const logRequestTimer = (req) => { + const start = Date.now(); + const pathname = new URL(req.url).pathname; + logger.info(`Incoming request: ${pathname}`); + return () => { + const duration = Date.now() - start; + logger.info(`Request for ${pathname} took ${duration}ms`); + }; +}; + +const fetchMetaData = async (url) => { + try { + const response = await axios.get(url); + return response.data; + } catch (error) { + logger.error('Error fetching meta data', error); + return null; + } +}; + +const createServer = async (req) => { + const timer = logRequestTimer(req); + + if (req.method === 'GET') { + const pageId = req.url.split('/').pop(); + let htmlData = fs.readFileSync(indexPath, 'utf8'); + const $ = cheerio.load(htmlData); + if (!pageId) { + timer(); + return new Response($.html(), { + headers: { 'Content-Type': 'text/html' }, + }); + } + + const description = 'Write, share, comment, react, and publish docs quickly and securely on AppFlowy.'; + let title = 'AppFlowy'; + const url = 'https://appflowy.com'; + let image = 'https://d3uafhn8yrvdfn.cloudfront.net/website/production/_next/static/media/og-image.e347bfb5.png'; + // Inject meta data into the HTML to support SEO and social sharing + // if (metaData) { + // title = metaData.title; + // image = metaData.image; + // } + + $('title').text(title); + setOrUpdateMetaTag($, 'meta[name="description"]', 'name', description); + setOrUpdateMetaTag($, 'meta[property="og:title"]', 'property', title); + setOrUpdateMetaTag($, 'meta[property="og:description"]', 'property', description); + setOrUpdateMetaTag($, 'meta[property="og:image"]', 'property', image); + setOrUpdateMetaTag($, 'meta[property="og:url"]', 'property', url); + setOrUpdateMetaTag($, 'meta[property="og:type"]', 'property', 'article'); + setOrUpdateMetaTag($, 'meta[name="twitter:card"]', 'name', 'summary_large_image'); + setOrUpdateMetaTag($, 'meta[name="twitter:title"]', 'name', title); + setOrUpdateMetaTag($, 'meta[name="twitter:description"]', 'name', description); + setOrUpdateMetaTag($, 'meta[name="twitter:image"]', 'name', image); + + timer(); + return new Response($.html(), { + headers: { 'Content-Type': 'text/html' }, + }); + } else { + timer(); + logger.error({ message: 'Method not allowed', method: req.method }); + return new Response('Method not allowed', { status: 405 }); + } +}; + +const start = () => { + try { + Bun.serve({ + port: 3000, + fetch: createServer, + error: (err) => { + logger.error(`Internal Server Error: ${err}`); + return new Response('Internal Server Error', { status: 500 }); + }, + }); + logger.info(`Server is running on port 3000`); + } catch (err) { + logger.error(err); + process.exit(1); + } +}; + +start(); diff --git a/frontend/appflowy_web_app/src/components/editor/CollaborativeEditor.tsx b/frontend/appflowy_web_app/src/components/editor/CollaborativeEditor.tsx index 8820296780..02a27f17ed 100644 --- a/frontend/appflowy_web_app/src/components/editor/CollaborativeEditor.tsx +++ b/frontend/appflowy_web_app/src/components/editor/CollaborativeEditor.tsx @@ -30,6 +30,7 @@ function CollaborativeEditor({ doc }: { doc: Y.Doc }) { useEffect(() => { if (!editor) return; + editor.connect(); setIsConnected(true); diff --git a/frontend/appflowy_web_app/start.sh b/frontend/appflowy_web_app/start.sh new file mode 100644 index 0000000000..b4691baa1a --- /dev/null +++ b/frontend/appflowy_web_app/start.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# Start the frontend server +bun run server.cjs & + +# Start the nginx server +service nginx start + +tail -f /dev/null + From d8ca6939763172c1fe557703ceaa5ed084d22604 Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Wed, 5 Jun 2024 16:01:42 +0800 Subject: [PATCH 03/16] feat: enable search (#5474) --- frontend/appflowy_flutter/lib/shared/feature_flags.dart | 2 ++ .../home/menu/sidebar/header/sidebar_top_menu.dart | 2 +- .../lib/workspace/presentation/home/menu/sidebar/sidebar.dart | 3 ++- .../home/menu/sidebar/workspace/_sidebar_workspace_icon.dart | 2 +- .../packages/flowy_infra_ui/lib/style_widget/text.dart | 2 +- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/frontend/appflowy_flutter/lib/shared/feature_flags.dart b/frontend/appflowy_flutter/lib/shared/feature_flags.dart index 9f578c177a..41d9d4d94d 100644 --- a/frontend/appflowy_flutter/lib/shared/feature_flags.dart +++ b/frontend/appflowy_flutter/lib/shared/feature_flags.dart @@ -85,6 +85,8 @@ enum FeatureFlag { bool get isOn { if ([ + // release this feature in version 0.5.9 + FeatureFlag.search, // release this feature in version 0.5.6 FeatureFlag.collaborativeWorkspace, FeatureFlag.membersSettings, diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/header/sidebar_top_menu.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/header/sidebar_top_menu.dart index 67bcbc782f..88ac6ee3c3 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/header/sidebar_top_menu.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/header/sidebar_top_menu.dart @@ -56,7 +56,7 @@ class SidebarTopMenu extends StatelessWidget { : FlowySvgs.flowy_logo_text_xl; return Padding( - padding: const EdgeInsets.only(top: 12.0, left: 4), + padding: const EdgeInsets.only(top: 12.0, left: 8), child: FlowySvg( svgData, size: const Size(92, 17), diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar.dart index fe8b0db70b..ae3ba81735 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar.dart @@ -333,7 +333,8 @@ class _SidebarSearchButton extends StatelessWidget { return FlowyButton( onTap: () => CommandPalette.of(context).toggle(), leftIcon: const FlowySvg(FlowySvgs.search_s), - iconPadding: 10.0, + iconPadding: 12.0, + margin: const EdgeInsets.only(left: 8.0), text: FlowyText.regular(LocaleKeys.search_label.tr()), ); } diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_icon.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_icon.dart index c05cf1e148..491e1c42cf 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_icon.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_icon.dart @@ -40,7 +40,7 @@ class _WorkspaceIconState extends State { Widget build(BuildContext context) { Widget child = widget.workspace.icon.isNotEmpty ? Container( - width: widget.emojiSize ?? widget.iconSize, + width: widget.iconSize, alignment: widget.alignment ?? Alignment.center, child: FlowyText.emoji( widget.workspace.icon, diff --git a/frontend/appflowy_flutter/packages/flowy_infra_ui/lib/style_widget/text.dart b/frontend/appflowy_flutter/packages/flowy_infra_ui/lib/style_widget/text.dart index 71be43364f..fafee3f623 100644 --- a/frontend/appflowy_flutter/packages/flowy_infra_ui/lib/style_widget/text.dart +++ b/frontend/appflowy_flutter/packages/flowy_infra_ui/lib/style_widget/text.dart @@ -170,7 +170,7 @@ class FlowyText extends StatelessWidget { textAlign: textAlign, overflow: overflow ?? TextOverflow.clip, style: textStyle, - strutStyle: Platform.isMacOS + strutStyle: (Platform.isMacOS || Platform.isLinux) & !isEmoji ? StrutStyle.fromTextStyle( textStyle, forceStrutHeight: true, From 6e7d044208ffaa1dab54e930a01715dde244ca41 Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Wed, 5 Jun 2024 17:32:30 +0800 Subject: [PATCH 04/16] chore: update chat icon (#5476) * chore: update chat icon * chore: update translation --- .../bottom_sheet/bottom_sheet_add_new_page.dart | 8 ++++---- .../bottom_sheet/bottom_sheet_view_page.dart | 11 ++++------- .../bottom_sheet/default_mobile_action_pane.dart | 15 ++++++++------- .../card_detail/mobile_card_detail_screen.dart | 4 ++-- .../database/field/mobile_quick_field_editor.dart | 2 +- .../view/database_view_quick_actions.dart | 6 +++--- .../presentation/page_item/mobile_view_item.dart | 9 ++++++--- .../application/favorite/favorite_service.dart | 3 ++- .../windows/runner/flutter_window.cpp | 2 +- .../resources/flowy_icons/16x/chat_ai_page.svg | 5 ++++- .../flowy_icons/16x/workspace_three_dots.svg | 12 ++++++------ frontend/resources/translations/en.json | 2 +- 12 files changed, 42 insertions(+), 37 deletions(-) diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/bottom_sheet/bottom_sheet_add_new_page.dart b/frontend/appflowy_flutter/lib/mobile/presentation/bottom_sheet/bottom_sheet_add_new_page.dart index bc8706f8b8..1a8ff64f2b 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/bottom_sheet/bottom_sheet_add_new_page.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/bottom_sheet/bottom_sheet_add_new_page.dart @@ -23,7 +23,7 @@ class AddNewPageWidgetBottomSheet extends StatelessWidget { text: LocaleKeys.document_menuName.tr(), height: 52.0, leftIcon: const FlowySvg( - FlowySvgs.document_s, + FlowySvgs.icon_document_s, size: Size.square(18), ), showTopBorder: false, @@ -33,7 +33,7 @@ class AddNewPageWidgetBottomSheet extends StatelessWidget { text: LocaleKeys.grid_menuName.tr(), height: 52.0, leftIcon: const FlowySvg( - FlowySvgs.grid_s, + FlowySvgs.icon_grid_s, size: Size.square(18), ), showTopBorder: false, @@ -43,7 +43,7 @@ class AddNewPageWidgetBottomSheet extends StatelessWidget { text: LocaleKeys.board_menuName.tr(), height: 52.0, leftIcon: const FlowySvg( - FlowySvgs.board_s, + FlowySvgs.icon_board_s, size: Size.square(18), ), showTopBorder: false, @@ -53,7 +53,7 @@ class AddNewPageWidgetBottomSheet extends StatelessWidget { text: LocaleKeys.calendar_menuName.tr(), height: 52.0, leftIcon: const FlowySvg( - FlowySvgs.calendar_s, + FlowySvgs.icon_calendar_s, size: Size.square(18), ), showTopBorder: false, diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/bottom_sheet/bottom_sheet_view_page.dart b/frontend/appflowy_flutter/lib/mobile/presentation/bottom_sheet/bottom_sheet_view_page.dart index de9d51311c..62d471a093 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/bottom_sheet/bottom_sheet_view_page.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/bottom_sheet/bottom_sheet_view_page.dart @@ -89,7 +89,7 @@ class MobileViewBottomSheetBody extends StatelessWidget { children: [ MobileQuickActionButton( text: LocaleKeys.button_rename.tr(), - icon: FlowySvgs.m_rename_s, + icon: FlowySvgs.view_item_rename_s, onTap: () => onAction( MobileViewBottomSheetBodyAction.rename, ), @@ -99,10 +99,7 @@ class MobileViewBottomSheetBody extends StatelessWidget { text: isFavorite ? LocaleKeys.button_removeFromFavorites.tr() : LocaleKeys.button_addToFavorites.tr(), - icon: isFavorite - ? FlowySvgs.m_favorite_selected_lg - : FlowySvgs.m_favorite_unselected_lg, - iconColor: isFavorite ? Colors.yellow : null, + icon: isFavorite ? FlowySvgs.unfavorite_s : FlowySvgs.favorite_s, onTap: () => onAction( isFavorite ? MobileViewBottomSheetBodyAction.removeFromFavorites @@ -112,7 +109,7 @@ class MobileViewBottomSheetBody extends StatelessWidget { _divider(), MobileQuickActionButton( text: LocaleKeys.button_duplicate.tr(), - icon: FlowySvgs.m_duplicate_s, + icon: FlowySvgs.duplicate_s, onTap: () => onAction( MobileViewBottomSheetBodyAction.duplicate, ), @@ -121,7 +118,7 @@ class MobileViewBottomSheetBody extends StatelessWidget { MobileQuickActionButton( text: LocaleKeys.button_delete.tr(), textColor: Theme.of(context).colorScheme.error, - icon: FlowySvgs.m_delete_s, + icon: FlowySvgs.trash_s, iconColor: Theme.of(context).colorScheme.error, onTap: () => onAction( MobileViewBottomSheetBodyAction.delete, diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/bottom_sheet/default_mobile_action_pane.dart b/frontend/appflowy_flutter/lib/mobile/presentation/bottom_sheet/default_mobile_action_pane.dart index 022d0c224c..ad489a5645 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/bottom_sheet/default_mobile_action_pane.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/bottom_sheet/default_mobile_action_pane.dart @@ -74,13 +74,14 @@ enum MobilePaneActionType { return AddNewPageWidgetBottomSheet( view: view, onAction: (layout) { - context.read().add( - ViewEvent.createView( - LocaleKeys.menuAppHeader_defaultNewPageName.tr(), - layout, - section: spaceType!.toViewSectionPB, - ), - ); + Navigator.of(sheetContext).pop(); + viewBloc.add( + ViewEvent.createView( + LocaleKeys.menuAppHeader_defaultNewPageName.tr(), + layout, + section: spaceType!.toViewSectionPB, + ), + ); }, ); }, diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/database/card/card_detail/mobile_card_detail_screen.dart b/frontend/appflowy_flutter/lib/mobile/presentation/database/card/card_detail/mobile_card_detail_screen.dart index 08f6c0b48b..c65f899c34 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/database/card/card_detail/mobile_card_detail_screen.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/database/card/card_detail/mobile_card_detail_screen.dart @@ -140,7 +140,7 @@ class _MobileRowDetailPageState extends State { MobileQuickActionButton( onTap: () => _performAction(viewId, _bloc.state.currentRowId, false), - icon: FlowySvgs.copy_s, + icon: FlowySvgs.duplicate_s, text: LocaleKeys.button_duplicate.tr(), ), const Divider(height: 8.5, thickness: 0.5), @@ -148,7 +148,7 @@ class _MobileRowDetailPageState extends State { onTap: () => _performAction(viewId, _bloc.state.currentRowId, true), text: LocaleKeys.button_delete.tr(), textColor: Theme.of(context).colorScheme.error, - icon: FlowySvgs.m_delete_m, + icon: FlowySvgs.trash_s, iconColor: Theme.of(context).colorScheme.error, ), const Divider(height: 8.5, thickness: 0.5), diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_quick_field_editor.dart b/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_quick_field_editor.dart index f3b76447f4..0b415b04a6 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_quick_field_editor.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_quick_field_editor.dart @@ -5,8 +5,8 @@ import 'package:appflowy/mobile/presentation/database/field/mobile_field_bottom_ import 'package:appflowy/mobile/presentation/widgets/widgets.dart'; import 'package:appflowy/plugins/database/application/field/field_controller.dart'; import 'package:appflowy/plugins/database/application/field/field_editor_bloc.dart'; -import 'package:appflowy/plugins/database/domain/field_backend_service.dart'; import 'package:appflowy/plugins/database/application/field/field_info.dart'; +import 'package:appflowy/plugins/database/domain/field_backend_service.dart'; import 'package:appflowy/plugins/database/widgets/setting/field_visibility_extension.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart'; import 'package:easy_localization/easy_localization.dart'; diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_view_quick_actions.dart b/frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_view_quick_actions.dart index eff4dc5e0b..652c93496e 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_view_quick_actions.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_view_quick_actions.dart @@ -107,9 +107,9 @@ enum _Action { FlowySvgData get icon { return switch (this) { - edit => FlowySvgs.edit_s, - duplicate => FlowySvgs.copy_s, - delete => FlowySvgs.delete_s, + edit => FlowySvgs.view_item_rename_s, + duplicate => FlowySvgs.duplicate_s, + delete => FlowySvgs.trash_s, }; } diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/page_item/mobile_view_item.dart b/frontend/appflowy_flutter/lib/mobile/presentation/page_item/mobile_view_item.dart index 2d20581b98..737145d501 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/page_item/mobile_view_item.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/page_item/mobile_view_item.dart @@ -298,9 +298,12 @@ class _SingleMobileInnerViewItemState extends State { widget.view.icon.value, fontSize: 20.0, ) - : SizedBox.square( - dimension: 18.0, - child: widget.view.defaultIcon(), + : Opacity( + opacity: 0.7, + child: SizedBox.square( + dimension: 18.0, + child: widget.view.defaultIcon(), + ), ); return icon; } diff --git a/frontend/appflowy_flutter/lib/workspace/application/favorite/favorite_service.dart b/frontend/appflowy_flutter/lib/workspace/application/favorite/favorite_service.dart index 71bb8423df..e21db62ccb 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/favorite/favorite_service.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/favorite/favorite_service.dart @@ -34,7 +34,8 @@ class FavoriteService { bool isPinned, ) async { try { - final current = view.extra.isNotEmpty ? jsonDecode(view.extra) : {}; + final current = + view.extra.isNotEmpty ? jsonDecode(view.extra) : {}; final merged = mergeMaps( current, {ViewExtKeys.isPinnedKey: isPinned}, diff --git a/frontend/appflowy_flutter/windows/runner/flutter_window.cpp b/frontend/appflowy_flutter/windows/runner/flutter_window.cpp index b43b9095ea..8e9deabc69 100644 --- a/frontend/appflowy_flutter/windows/runner/flutter_window.cpp +++ b/frontend/appflowy_flutter/windows/runner/flutter_window.cpp @@ -17,7 +17,7 @@ bool FlutterWindow::OnCreate() { RECT frame = GetClientArea(); // The size here must match the window dimensions to avoid unnecessary surface - // creation / destruction in the startup path. +// creation / destruction in the startup path. flutter_controller_ = std::make_unique( frame.right - frame.left, frame.bottom - frame.top, project_); // Ensure that basic setup of the controller was successful. diff --git a/frontend/resources/flowy_icons/16x/chat_ai_page.svg b/frontend/resources/flowy_icons/16x/chat_ai_page.svg index e3585e4ec6..3033ab47a0 100644 --- a/frontend/resources/flowy_icons/16x/chat_ai_page.svg +++ b/frontend/resources/flowy_icons/16x/chat_ai_page.svg @@ -1 +1,4 @@ - \ No newline at end of file + + + + diff --git a/frontend/resources/flowy_icons/16x/workspace_three_dots.svg b/frontend/resources/flowy_icons/16x/workspace_three_dots.svg index 93aa13693a..54332fb08b 100644 --- a/frontend/resources/flowy_icons/16x/workspace_three_dots.svg +++ b/frontend/resources/flowy_icons/16x/workspace_three_dots.svg @@ -1,7 +1,7 @@ - - - - - - + + + + + + diff --git a/frontend/resources/translations/en.json b/frontend/resources/translations/en.json index 38057a15b0..8bd65ffc1f 100644 --- a/frontend/resources/translations/en.json +++ b/frontend/resources/translations/en.json @@ -148,7 +148,7 @@ "newCalendarText": "New calendar", "newBoardText": "New board", "chat": { - "newChat": "New chat", + "newChat": "AI Chat", "inputMessageHint": "Message AppFlowy AI", "unsupportedCloudPrompt": "This feature is only available when using AppFlowy Cloud", "relatedQuestion": "Related", From bd7977d8ba3a8f5c1e01b411a9ff7833bb6076a8 Mon Sep 17 00:00:00 2001 From: Mathias Mogensen <42929161+Xazin@users.noreply.github.com> Date: Wed, 5 Jun 2024 13:44:32 +0200 Subject: [PATCH 05/16] fix: search improvements (#5473) * fix: search workspace sync indexing * chore: update collab rev temporarily * feat: revert comparison and implement index check * chore: fixes after merg * feat: clean code + support delete workspace * fix: improve code * fix: improvements after merge * fix: cargo fmt * fix: remove indices for workspace method * fix: clippy errors * fix: clippy too many arguments --- .../command_palette/widgets/search_field.dart | 32 ++- frontend/appflowy_tauri/src-tauri/Cargo.toml | 2 +- frontend/appflowy_web/wasm-libs/Cargo.toml | 2 +- .../appflowy_web_app/src-tauri/Cargo.lock | 1 + .../appflowy_web_app/src-tauri/Cargo.toml | 2 +- .../src/deps_resolve/folder_deps.rs | 13 +- .../flowy-core/src/deps_resolve/user_deps.rs | 8 + frontend/rust-lib/flowy-core/src/lib.rs | 11 +- .../flowy-folder/src/entities/workspace.rs | 5 - frontend/rust-lib/flowy-folder/src/manager.rs | 8 + .../rust-lib/flowy-folder/src/manager_init.rs | 60 +++--- .../rust-lib/flowy-search-pub/src/entities.rs | 9 +- .../flowy-search/src/folder/indexer.rs | 185 +++++++++++------- frontend/rust-lib/flowy-sqlite/src/schema.rs | 12 +- .../flowy-user-pub/src/workspace_service.rs | 3 + .../user_manager/manager_user_workspace.rs | 11 +- 16 files changed, 240 insertions(+), 124 deletions(-) diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/command_palette/widgets/search_field.dart b/frontend/appflowy_flutter/lib/workspace/presentation/command_palette/widgets/search_field.dart index d171123e7d..545905d918 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/command_palette/widgets/search_field.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/command_palette/widgets/search_field.dart @@ -12,12 +12,37 @@ import 'package:flowy_infra_ui/widget/flowy_tooltip.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -class SearchField extends StatelessWidget { +class SearchField extends StatefulWidget { const SearchField({super.key, this.query, this.isLoading = false}); final String? query; final bool isLoading; + @override + State createState() => _SearchFieldState(); +} + +class _SearchFieldState extends State { + final focusNode = FocusNode(); + late final controller = TextEditingController(text: widget.query); + + @override + void initState() { + super.initState(); + focusNode.requestFocus(); + controller.selection = TextSelection( + baseOffset: 0, + extentOffset: controller.text.length, + ); + } + + @override + void dispose() { + focusNode.dispose(); + controller.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { return Row( @@ -29,7 +54,8 @@ class SearchField extends StatelessWidget { ), Expanded( child: FlowyTextField( - controller: TextEditingController(text: query), + focusNode: focusNode, + controller: controller, textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(fontSize: 14), decoration: InputDecoration( @@ -84,7 +110,7 @@ class SearchField extends StatelessWidget { .add(CommandPaletteEvent.searchChanged(search: value)), ), ), - if (isLoading) ...[ + if (widget.isLoading) ...[ const HSpace(12), FlowyTooltip( message: LocaleKeys.commandPalette_loadingTooltip.tr(), diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.toml b/frontend/appflowy_tauri/src-tauri/Cargo.toml index 5f9b079392..ea09264aad 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.toml +++ b/frontend/appflowy_tauri/src-tauri/Cargo.toml @@ -112,4 +112,4 @@ collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlow collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } \ No newline at end of file +collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } diff --git a/frontend/appflowy_web/wasm-libs/Cargo.toml b/frontend/appflowy_web/wasm-libs/Cargo.toml index 225c339b1c..2f0c25023a 100644 --- a/frontend/appflowy_web/wasm-libs/Cargo.toml +++ b/frontend/appflowy_web/wasm-libs/Cargo.toml @@ -76,4 +76,4 @@ collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlow collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } \ No newline at end of file +collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } diff --git a/frontend/appflowy_web_app/src-tauri/Cargo.lock b/frontend/appflowy_web_app/src-tauri/Cargo.lock index 2ba17e8683..43806f61fb 100644 --- a/frontend/appflowy_web_app/src-tauri/Cargo.lock +++ b/frontend/appflowy_web_app/src-tauri/Cargo.lock @@ -2173,6 +2173,7 @@ dependencies = [ "nanoid", "parking_lot 0.12.1", "protobuf", + "serde", "serde_json", "strum_macros 0.21.1", "tokio", diff --git a/frontend/appflowy_web_app/src-tauri/Cargo.toml b/frontend/appflowy_web_app/src-tauri/Cargo.toml index 21df3b1bbc..8625530b8c 100644 --- a/frontend/appflowy_web_app/src-tauri/Cargo.toml +++ b/frontend/appflowy_web_app/src-tauri/Cargo.toml @@ -113,4 +113,4 @@ collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlow collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } \ No newline at end of file +collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } diff --git a/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs b/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs index e826a3f4c4..5c383d204a 100644 --- a/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs +++ b/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs @@ -33,28 +33,21 @@ pub struct FolderDepsResolver(); impl FolderDepsResolver { pub async fn resolve( authenticate_user: Weak, - document_manager: &Arc, - database_manager: &Arc, collab_builder: Arc, server_provider: Arc, folder_indexer: Arc, store_preferences: Arc, - chat_manager: &Arc, + operation_handlers: FolderOperationHandlers, ) -> Arc { let user: Arc = Arc::new(FolderUserImpl { authenticate_user: authenticate_user.clone(), }); - let handlers = folder_operation_handlers( - document_manager.clone(), - database_manager.clone(), - chat_manager.clone(), - ); Arc::new( FolderManager::new( user.clone(), collab_builder, - handlers, + operation_handlers, server_provider.clone(), folder_indexer, store_preferences, @@ -64,7 +57,7 @@ impl FolderDepsResolver { } } -fn folder_operation_handlers( +pub fn folder_operation_handlers( document_manager: Arc, database_manager: Arc, chat_manager: Arc, diff --git a/frontend/rust-lib/flowy-core/src/deps_resolve/user_deps.rs b/frontend/rust-lib/flowy-core/src/deps_resolve/user_deps.rs index b8d18af390..1d580e6cee 100644 --- a/frontend/rust-lib/flowy-core/src/deps_resolve/user_deps.rs +++ b/frontend/rust-lib/flowy-core/src/deps_resolve/user_deps.rs @@ -59,4 +59,12 @@ impl UserWorkspaceService for UserWorkspaceServiceImpl { .await?; Ok(()) } + + fn did_delete_workspace(&self, workspace_id: String) -> FlowyResult<()> { + self + .folder_manager + .remove_indices_for_workspace(workspace_id)?; + + Ok(()) + } } diff --git a/frontend/rust-lib/flowy-core/src/lib.rs b/frontend/rust-lib/flowy-core/src/lib.rs index 02f63c6f1d..c0cf2b9491 100644 --- a/frontend/rust-lib/flowy-core/src/lib.rs +++ b/frontend/rust-lib/flowy-core/src/lib.rs @@ -173,15 +173,20 @@ impl AppFlowyCore { let folder_indexer = Arc::new(FolderIndexManagerImpl::new(Some(Arc::downgrade( &authenticate_user, )))); + + let folder_operation_handlers = folder_operation_handlers( + document_manager.clone(), + database_manager.clone(), + chat_manager.clone(), + ); + let folder_manager = FolderDepsResolver::resolve( Arc::downgrade(&authenticate_user), - &document_manager, - &database_manager, collab_builder.clone(), server_provider.clone(), folder_indexer.clone(), store_preference.clone(), - &chat_manager, + folder_operation_handlers, ) .await; diff --git a/frontend/rust-lib/flowy-folder/src/entities/workspace.rs b/frontend/rust-lib/flowy-folder/src/entities/workspace.rs index e78eb6e307..21ff046226 100644 --- a/frontend/rust-lib/flowy-folder/src/entities/workspace.rs +++ b/frontend/rust-lib/flowy-folder/src/entities/workspace.rs @@ -232,8 +232,3 @@ pub struct UserFolderPB { #[pb(index = 2)] pub workspace_id: String, } - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Eq, PartialEq)] -pub struct IndexedWorkspaceIds { - pub workspace_ids: Vec, -} diff --git a/frontend/rust-lib/flowy-folder/src/manager.rs b/frontend/rust-lib/flowy-folder/src/manager.rs index 71be3778ee..265fa5118b 100644 --- a/frontend/rust-lib/flowy-folder/src/manager.rs +++ b/frontend/rust-lib/flowy-folder/src/manager.rs @@ -1201,6 +1201,14 @@ impl FolderManager { .filter(|id| !my_private_view_ids.contains(id)) .collect() } + + pub fn remove_indices_for_workspace(&self, workspace_id: String) -> FlowyResult<()> { + self + .folder_indexer + .remove_indices_for_workspace(workspace_id)?; + + Ok(()) + } } /// Return the views that belong to the workspace. The views are filtered by the trash and all the private views. diff --git a/frontend/rust-lib/flowy-folder/src/manager_init.rs b/frontend/rust-lib/flowy-folder/src/manager_init.rs index 07fc973f05..d1266a146e 100644 --- a/frontend/rust-lib/flowy-folder/src/manager_init.rs +++ b/frontend/rust-lib/flowy-folder/src/manager_init.rs @@ -1,9 +1,8 @@ -use crate::entities::IndexedWorkspaceIds; use crate::manager::{FolderInitDataSource, FolderManager}; use crate::manager_observer::*; use crate::user_default::DefaultFolderBuilder; use collab::core::collab::DataSource; -use collab_entity::CollabType; +use collab_entity::{CollabType, EncodedCollab}; use collab_folder::{Folder, FolderNotify, UserId}; use collab_integrate::CollabKVDB; use flowy_error::{FlowyError, FlowyResult}; @@ -11,8 +10,6 @@ use std::sync::{Arc, Weak}; use tokio::task::spawn_blocking; use tracing::{event, info, Level}; -pub const INDEXED_WORKSPACE_KEY: &str = "indexed-workspace-ids"; - impl FolderManager { /// Called immediately after the application launched if the user already sign in/sign up. #[tracing::instrument(level = "info", skip(self, initial_data), err)] @@ -187,28 +184,27 @@ impl FolderManager { } fn handle_index_folder(&self, workspace_id: String, folder: &Folder) { - let index_all; - if self.folder_indexer.is_indexed() { - // If indexes already exist, we check if the workspace was - // previously indexed, if it wasn't we index all - let indexed_ids = self - .store_preferences - .get_object::(INDEXED_WORKSPACE_KEY); - if let Some(indexed_ids) = indexed_ids { - index_all = !indexed_ids.workspace_ids.contains(&workspace_id.clone()); - if !index_all { - let mut workspace_ids = indexed_ids.workspace_ids.clone(); - workspace_ids.push(workspace_id.clone()); - let _ = self - .store_preferences - .set_object(INDEXED_WORKSPACE_KEY, IndexedWorkspaceIds { workspace_ids }); + let mut index_all = true; + + let encoded_collab = self + .store_preferences + .get_object::(&workspace_id); + + if let Some(encoded_collab) = encoded_collab { + if let Ok(changes) = folder.calculate_view_changes(encoded_collab) { + let folder_indexer = self.folder_indexer.clone(); + + let views = folder.views.get_all_views(); + let wid = workspace_id.clone(); + + if !changes.is_empty() && !views.is_empty() { + spawn_blocking(move || { + // We index the changes + folder_indexer.index_view_changes(views, changes, wid); + }); + index_all = false; } - } else { - index_all = true; } - } else { - // If there exists no indexes, we index all views in workspace - index_all = true; } if index_all { @@ -218,8 +214,24 @@ impl FolderManager { // We spawn a blocking task to index all views in the folder spawn_blocking(move || { + // We remove old indexes just in case + let _ = folder_indexer.remove_indices_for_workspace(wid.clone()); + + // We index all views from the workspace folder_indexer.index_all_views(views, wid); }); } + + self.save_collab_to_preferences(folder); + } + + fn save_collab_to_preferences(&self, folder: &Folder) { + let encoded_collab = folder.encode_collab_v1(); + + if let Ok(encoded) = encoded_collab { + let _ = self + .store_preferences + .set_object(&folder.get_workspace_id(), encoded); + } } } diff --git a/frontend/rust-lib/flowy-search-pub/src/entities.rs b/frontend/rust-lib/flowy-search-pub/src/entities.rs index 8b9b4a3cb6..65e23a9ddb 100644 --- a/frontend/rust-lib/flowy-search-pub/src/entities.rs +++ b/frontend/rust-lib/flowy-search-pub/src/entities.rs @@ -2,7 +2,7 @@ use std::any::Any; use std::sync::Arc; use collab::core::collab::IndexContentReceiver; -use collab_folder::{View, ViewIcon, ViewLayout}; +use collab_folder::{folder_diff::FolderViewChange, View, ViewIcon, ViewLayout}; use flowy_error::FlowyError; pub struct IndexableData { @@ -30,6 +30,7 @@ pub trait IndexManager: Send + Sync { fn add_index(&self, data: IndexableData) -> Result<(), FlowyError>; fn update_index(&self, data: IndexableData) -> Result<(), FlowyError>; fn remove_indices(&self, ids: Vec) -> Result<(), FlowyError>; + fn remove_indices_for_workspace(&self, workspace_id: String) -> Result<(), FlowyError>; fn is_indexed(&self) -> bool; fn as_any(&self) -> &dyn Any; @@ -37,4 +38,10 @@ pub trait IndexManager: Send + Sync { pub trait FolderIndexManager: IndexManager { fn index_all_views(&self, views: Vec>, workspace_id: String); + fn index_view_changes( + &self, + views: Vec>, + changes: Vec, + workspace_id: String, + ); } diff --git a/frontend/rust-lib/flowy-search/src/folder/indexer.rs b/frontend/rust-lib/flowy-search/src/folder/indexer.rs index 39192806b8..146da46a49 100644 --- a/frontend/rust-lib/flowy-search/src/folder/indexer.rs +++ b/frontend/rust-lib/flowy-search/src/folder/indexer.rs @@ -15,15 +15,15 @@ use crate::{ }, }; use collab::core::collab::{IndexContent, IndexContentReceiver}; -use collab_folder::{View, ViewIcon, ViewIndexContent, ViewLayout}; +use collab_folder::{folder_diff::FolderViewChange, View, ViewIcon, ViewIndexContent, ViewLayout}; use flowy_error::{FlowyError, FlowyResult}; use flowy_search_pub::entities::{FolderIndexManager, IndexManager, IndexableData}; use flowy_user::services::authenticate_user::AuthenticateUser; use lib_dispatch::prelude::af_spawn; use strsim::levenshtein; use tantivy::{ - collector::TopDocs, directory::MmapDirectory, doc, query::QueryParser, Index, IndexReader, - IndexWriter, Term, + collector::TopDocs, directory::MmapDirectory, doc, query::QueryParser, schema::Field, Index, + IndexReader, IndexWriter, Term, }; use super::entities::FolderIndexData; @@ -40,7 +40,6 @@ const FOLDER_INDEX_DIR: &str = "folder_index"; impl FolderIndexManagerImpl { pub fn new(auth_user: Option>) -> Self { - // TODO(Mathias): Temporarily disable seaerch let auth_user = match auth_user { Some(auth_user) => auth_user, None => { @@ -74,52 +73,45 @@ impl FolderIndexManagerImpl { } } - // We open the existing or newly created folder_index directory - // This is required by the Tantivy Index, as it will use it to store - // and read index data - let dir = MmapDirectory::open(index_path); - if let Err(e) = dir { - tracing::error!("FolderIndexManager failed to open index directory: {:?}", e); - return FolderIndexManagerImpl::empty(); - } - // The folder schema is used to define the fields of the index along // with how they are stored and if the field is indexed let folder_schema = FolderSchema::new(); - // We open or create an index that takes the directory r/w and the schema. - let index_res = Index::open_or_create(dir.unwrap(), folder_schema.schema.clone()); - if let Err(e) = index_res { - tracing::error!("FolderIndexManager failed to open index: {:?}", e); - return FolderIndexManagerImpl::empty(); - } + // We open the existing or newly created folder_index directory + // This is required by the Tantivy Index, as it will use it to store + // and read index data + let index = match MmapDirectory::open(index_path) { + // We open or create an index that takes the directory r/w and the schema. + Ok(dir) => match Index::open_or_create(dir, folder_schema.schema.clone()) { + Ok(index) => index, + Err(e) => { + tracing::error!("FolderIndexManager failed to open index: {:?}", e); + return FolderIndexManagerImpl::empty(); + }, + }, + Err(e) => { + tracing::error!("FolderIndexManager failed to open index directory: {:?}", e); + return FolderIndexManagerImpl::empty(); + }, + }; - let index = index_res.unwrap(); - - // We read the index reader, we only need one IndexReader per index + // We only need one IndexReader per index let index_reader = index.reader(); - if let Err(e) = index_reader { - tracing::error!( - "FolderIndexManager failed to instantiate index reader: {:?}", - e - ); - return FolderIndexManagerImpl::empty(); - } - let index_writer = index.writer(50_000_000); - if let Err(e) = index_writer { - tracing::error!( - "FolderIndexManager failed to instantiate index writer: {:?}", - e - ); - return FolderIndexManagerImpl::empty(); - } + + let (index_reader, index_writer) = match (index_reader, index_writer) { + (Ok(reader), Ok(writer)) => (reader, writer), + _ => { + tracing::error!("FolderIndexManager failed to instantiate index writer and/or reader"); + return FolderIndexManagerImpl::empty(); + }, + }; Self { folder_schema: Some(folder_schema), index: Some(index), - index_reader: Some(index_reader.unwrap()), - index_writer: Some(Arc::new(Mutex::new(index_writer.unwrap()))), + index_reader: Some(index_reader), + index_writer: Some(Arc::new(Mutex::new(index_writer))), } } @@ -129,7 +121,6 @@ impl FolderIndexManagerImpl { } let mut index_writer = self.get_index_writer()?; - let folder_schema = self.get_folder_schema()?; let id_field = folder_schema.schema.get_field(FOLDER_ID_FIELD_NAME)?; @@ -223,15 +214,11 @@ impl FolderIndexManagerImpl { ) -> Result, FlowyError> { let folder_schema = self.get_folder_schema()?; - let index = match &self.index { - Some(index) => index, - None => return Err(FlowyError::folder_index_manager_unavailable()), - }; - - let index_reader = match &self.index_reader { - Some(index_reader) => index_reader, - None => return Err(FlowyError::folder_index_manager_unavailable()), - }; + let (index, index_reader) = self + .index + .as_ref() + .zip(self.index_reader.as_ref()) + .ok_or_else(FlowyError::folder_index_manager_unavailable)?; let title_field = folder_schema.schema.get_field(FOLDER_TITLE_FIELD_NAME)?; @@ -272,6 +259,29 @@ impl FolderIndexManagerImpl { let distance = levenshtein(query, term) as f64; 1.0 / (distance + 1.0) } + + fn get_schema_fields(&self) -> Result<(Field, Field, Field, Field, Field), FlowyError> { + let folder_schema = match self.folder_schema.clone() { + Some(schema) => schema, + _ => return Err(FlowyError::folder_index_manager_unavailable()), + }; + + let id_field = folder_schema.schema.get_field(FOLDER_ID_FIELD_NAME)?; + let title_field = folder_schema.schema.get_field(FOLDER_TITLE_FIELD_NAME)?; + let icon_field = folder_schema.schema.get_field(FOLDER_ICON_FIELD_NAME)?; + let icon_ty_field = folder_schema.schema.get_field(FOLDER_ICON_TY_FIELD_NAME)?; + let workspace_id_field = folder_schema + .schema + .get_field(FOLDER_WORKSPACE_ID_FIELD_NAME)?; + + Ok(( + id_field, + title_field, + icon_field, + icon_ty_field, + workspace_id_field, + )) + } } impl IndexManager for FolderIndexManagerImpl { @@ -288,9 +298,12 @@ impl IndexManager for FolderIndexManagerImpl { let wid = workspace_id.clone(); af_spawn(async move { while let Ok(msg) = rx.recv().await { + tracing::warn!("[Indexer] Message received: {:?}", msg); match msg { IndexContent::Create(value) => match serde_json::from_value::(value) { Ok(view) => { + tracing::warn!("[Indexer] CREATE: {:?}", view); + let _ = indexer.add_index(IndexableData { id: view.id, data: view.name, @@ -303,6 +316,7 @@ impl IndexManager for FolderIndexManagerImpl { }, IndexContent::Update(value) => match serde_json::from_value::(value) { Ok(view) => { + tracing::warn!("[Indexer] UPDATE: {:?}", view); let _ = indexer.update_index(IndexableData { id: view.id, data: view.name, @@ -314,6 +328,7 @@ impl IndexManager for FolderIndexManagerImpl { Err(err) => tracing::error!("FolderIndexManager error deserialize: {:?}", err), }, IndexContent::Delete(ids) => { + tracing::warn!("[Indexer] DELETE: {:?}", ids); if let Err(e) = indexer.remove_indices(ids) { tracing::error!("FolderIndexManager error deserialize: {:?}", e); } @@ -326,15 +341,8 @@ impl IndexManager for FolderIndexManagerImpl { fn update_index(&self, data: IndexableData) -> Result<(), FlowyError> { let mut index_writer = self.get_index_writer()?; - let folder_schema = self.get_folder_schema()?; - let id_field = folder_schema.schema.get_field(FOLDER_ID_FIELD_NAME)?; - let title_field = folder_schema.schema.get_field(FOLDER_TITLE_FIELD_NAME)?; - let icon_field = folder_schema.schema.get_field(FOLDER_ICON_FIELD_NAME)?; - let icon_ty_field: tantivy::schema::Field = - folder_schema.schema.get_field(FOLDER_ICON_TY_FIELD_NAME)?; - let workspace_id_field = folder_schema - .schema - .get_field(FOLDER_WORKSPACE_ID_FIELD_NAME)?; + let (id_field, title_field, icon_field, icon_ty_field, workspace_id_field) = + self.get_schema_fields()?; let delete_term = Term::from_field_text(id_field, &data.id.clone()); @@ -361,7 +369,6 @@ impl IndexManager for FolderIndexManagerImpl { let mut index_writer = self.get_index_writer()?; let folder_schema = self.get_folder_schema()?; - let id_field = folder_schema.schema.get_field(FOLDER_ID_FIELD_NAME)?; for id in ids { let delete_term = Term::from_field_text(id_field, &id); @@ -376,15 +383,8 @@ impl IndexManager for FolderIndexManagerImpl { fn add_index(&self, data: IndexableData) -> Result<(), FlowyError> { let mut index_writer = self.get_index_writer()?; - let folder_schema = self.get_folder_schema()?; - - let id_field = folder_schema.schema.get_field(FOLDER_ID_FIELD_NAME)?; - let title_field = folder_schema.schema.get_field(FOLDER_TITLE_FIELD_NAME)?; - let icon_field = folder_schema.schema.get_field(FOLDER_ICON_FIELD_NAME)?; - let icon_ty_field = folder_schema.schema.get_field(FOLDER_ICON_TY_FIELD_NAME)?; - let workspace_id_field = folder_schema - .schema - .get_field(FOLDER_WORKSPACE_ID_FIELD_NAME)?; + let (id_field, title_field, icon_field, icon_ty_field, workspace_id_field) = + self.get_schema_fields()?; let (icon, icon_ty) = self.extract_icon(data.icon, data.layout); @@ -402,6 +402,24 @@ impl IndexManager for FolderIndexManagerImpl { Ok(()) } + /// Removes all indexes that are related by workspace id. This is useful + /// for cleaning indexes when eg. removing/leaving a workspace. + /// + fn remove_indices_for_workspace(&self, workspace_id: String) -> Result<(), FlowyError> { + let mut index_writer = self.get_index_writer()?; + + let folder_schema = self.get_folder_schema()?; + let id_field = folder_schema + .schema + .get_field(FOLDER_WORKSPACE_ID_FIELD_NAME)?; + let delete_term = Term::from_field_text(id_field, &workspace_id); + index_writer.delete_term(delete_term); + + index_writer.commit()?; + + Ok(()) + } + fn as_any(&self) -> &dyn Any { self } @@ -416,4 +434,35 @@ impl FolderIndexManager for FolderIndexManagerImpl { let _ = self.index_all(indexable_data); } + + fn index_view_changes( + &self, + views: Vec>, + changes: Vec, + workspace_id: String, + ) { + let mut views_iter = views.into_iter(); + for change in changes { + match change { + FolderViewChange::Inserted { view_id } => { + let view = views_iter.find(|view| view.id == view_id); + if let Some(view) = view { + let indexable_data = IndexableData::from_view(view, workspace_id.clone()); + let _ = self.add_index(indexable_data); + } + }, + FolderViewChange::Updated { view_id } => { + let view = views_iter.find(|view| view.id == view_id); + if let Some(view) = view { + let indexable_data = IndexableData::from_view(view, workspace_id.clone()); + let _ = self.update_index(indexable_data); + } + }, + FolderViewChange::Deleted { view_ids } => { + tracing::warn!("[Indexer] ViewChange Reached Deleted: {:?}", view_ids); + let _ = self.remove_indices(view_ids); + }, + }; + } + } } diff --git a/frontend/rust-lib/flowy-sqlite/src/schema.rs b/frontend/rust-lib/flowy-sqlite/src/schema.rs index 24290ea5d8..b1737d85eb 100644 --- a/frontend/rust-lib/flowy-sqlite/src/schema.rs +++ b/frontend/rust-lib/flowy-sqlite/src/schema.rs @@ -68,10 +68,10 @@ diesel::table! { } diesel::allow_tables_to_appear_in_same_query!( - chat_message_table, - chat_table, - collab_snapshot, - user_data_migration_records, - user_table, - user_workspace_table, + chat_message_table, + chat_table, + collab_snapshot, + user_data_migration_records, + user_table, + user_workspace_table, ); diff --git a/frontend/rust-lib/flowy-user-pub/src/workspace_service.rs b/frontend/rust-lib/flowy-user-pub/src/workspace_service.rs index 7938f8a862..d588945618 100644 --- a/frontend/rust-lib/flowy-user-pub/src/workspace_service.rs +++ b/frontend/rust-lib/flowy-user-pub/src/workspace_service.rs @@ -10,4 +10,7 @@ pub trait UserWorkspaceService: Send + Sync { &self, ids_by_database_id: HashMap>, ) -> FlowyResult<()>; + + /// Removes local indexes when a workspace is left/deleted + fn did_delete_workspace(&self, workspace_id: String) -> FlowyResult<()>; } diff --git a/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs b/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs index 8e30c43df7..0f74c563b1 100644 --- a/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs +++ b/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs @@ -261,7 +261,11 @@ impl UserManager { // delete workspace from local sqlite db let uid = self.user_id()?; let conn = self.db_connection(uid)?; - delete_user_workspaces(conn, workspace_id) + delete_user_workspaces(conn, workspace_id)?; + + self + .user_workspace_service + .did_delete_workspace(workspace_id.to_string()) } #[instrument(level = "info", skip(self), err)] @@ -275,6 +279,11 @@ impl UserManager { let uid = self.user_id()?; let conn = self.db_connection(uid)?; delete_user_workspaces(conn, workspace_id)?; + + self + .user_workspace_service + .did_delete_workspace(workspace_id.to_string())?; + Ok(()) } From ff93fbf0e6c51e6a72dcde403b75d87ad70940ce Mon Sep 17 00:00:00 2001 From: Mathias Mogensen <42929161+Xazin@users.noreply.github.com> Date: Wed, 5 Jun 2024 13:56:22 +0200 Subject: [PATCH 06/16] fix: use bitsdojo_window on windows (#5477) Co-authored-by: APPFLOWY\tsuiy --- .../lib/startup/tasks/windows.dart | 57 ++++++++++++------- frontend/appflowy_flutter/pubspec.lock | 44 +++++++++++++- frontend/appflowy_flutter/pubspec.yaml | 8 ++- .../appflowy_flutter/windows/runner/main.cpp | 3 + 4 files changed, 89 insertions(+), 23 deletions(-) diff --git a/frontend/appflowy_flutter/lib/startup/tasks/windows.dart b/frontend/appflowy_flutter/lib/startup/tasks/windows.dart index 2e564cc760..4d7bd47a33 100644 --- a/frontend/appflowy_flutter/lib/startup/tasks/windows.dart +++ b/frontend/appflowy_flutter/lib/startup/tasks/windows.dart @@ -1,12 +1,14 @@ import 'dart:async'; import 'dart:ui'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + import 'package:appflowy/core/helpers/helpers.dart'; import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/tasks/app_window_size_manager.dart'; import 'package:appflowy_editor/appflowy_editor.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; +import 'package:bitsdojo_window/bitsdojo_window.dart'; import 'package:scaled_app/scaled_app.dart'; import 'package:window_manager/window_manager.dart'; @@ -17,7 +19,7 @@ class InitAppWindowTask extends LaunchTask with WindowListener { final String title; - final windowsManager = WindowSizeManager(); + final windowSizeManager = WindowSizeManager(); @override Future initialize(LaunchContext context) async { @@ -29,7 +31,7 @@ class InitAppWindowTask extends LaunchTask with WindowListener { await windowManager.ensureInitialized(); windowManager.addListener(this); - final windowSize = await windowsManager.getSize(); + final windowSize = await windowSizeManager.getSize(); final windowOptions = WindowOptions( size: windowSize, minimumSize: const Size( @@ -43,23 +45,38 @@ class InitAppWindowTask extends LaunchTask with WindowListener { title: title, ); - await windowManager.waitUntilReadyToShow(windowOptions, () async { - await windowManager.show(); - await windowManager.focus(); + final position = await windowSizeManager.getPosition(); - if (PlatformExtension.isWindows) { - // Hide title bar on Windows, we implement a custom solution elsewhere - await windowManager.setTitleBarStyle(TitleBarStyle.hidden); - } + if (PlatformExtension.isWindows) { + doWhenWindowReady(() { + appWindow.minSize = windowOptions.minimumSize; + appWindow.maxSize = windowOptions.maximumSize; + appWindow.size = windowSize; - final position = await windowsManager.getPosition(); - if (position != null) { - await windowManager.setPosition(position); - } - }); + if (position != null) { + appWindow.position = position; + } + + appWindow.show(); + }); + } else { + await windowManager.waitUntilReadyToShow(windowOptions, () async { + await windowManager.show(); + await windowManager.focus(); + + if (PlatformExtension.isWindows) { + // Hide title bar on Windows, we implement a custom solution elsewhere + await windowManager.setTitleBarStyle(TitleBarStyle.hidden); + } + + if (position != null) { + await windowManager.setPosition(position); + } + }); + } unawaited( - windowsManager.getScaleFactor().then( + windowSizeManager.getScaleFactor().then( (v) => ScaledWidgetsFlutterBinding.instance.scaleFactor = (_) => v, ), ); @@ -70,7 +87,7 @@ class InitAppWindowTask extends LaunchTask with WindowListener { super.onWindowResize(); final currentWindowSize = await windowManager.getSize(); - return windowsManager.setSize(currentWindowSize); + return windowSizeManager.setSize(currentWindowSize); } @override @@ -78,7 +95,7 @@ class InitAppWindowTask extends LaunchTask with WindowListener { super.onWindowMaximize(); final currentWindowSize = await windowManager.getSize(); - return windowsManager.setSize(currentWindowSize); + return windowSizeManager.setSize(currentWindowSize); } @override @@ -86,7 +103,7 @@ class InitAppWindowTask extends LaunchTask with WindowListener { super.onWindowMoved(); final position = await windowManager.getPosition(); - return windowsManager.setPosition(position); + return windowSizeManager.setPosition(position); } @override diff --git a/frontend/appflowy_flutter/pubspec.lock b/frontend/appflowy_flutter/pubspec.lock index 2ee1b5eb06..7938fb37c4 100644 --- a/frontend/appflowy_flutter/pubspec.lock +++ b/frontend/appflowy_flutter/pubspec.lock @@ -120,6 +120,46 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + bitsdojo_window: + dependency: "direct main" + description: + name: bitsdojo_window + sha256: "88ef7765dafe52d97d7a3684960fb5d003e3151e662c18645c1641c22b873195" + url: "https://pub.dev" + source: hosted + version: "0.1.6" + bitsdojo_window_linux: + dependency: transitive + description: + name: bitsdojo_window_linux + sha256: "9519c0614f98be733e0b1b7cb15b827007886f6fe36a4fb62cf3d35b9dd578ab" + url: "https://pub.dev" + source: hosted + version: "0.1.4" + bitsdojo_window_macos: + dependency: transitive + description: + name: bitsdojo_window_macos + sha256: f7c5be82e74568c68c5b8449e2c5d8fd12ec195ecd70745a7b9c0f802bb0268f + url: "https://pub.dev" + source: hosted + version: "0.1.4" + bitsdojo_window_platform_interface: + dependency: transitive + description: + name: bitsdojo_window_platform_interface + sha256: "65daa015a0c6dba749bdd35a0f092e7a8ba8b0766aa0480eb3ef808086f6e27c" + url: "https://pub.dev" + source: hosted + version: "0.1.2" + bitsdojo_window_windows: + dependency: transitive + description: + name: bitsdojo_window_windows + sha256: fa982cf61ede53f483e50b257344a1c250af231a3cdc93a7064dd6dc0d720b68 + url: "https://pub.dev" + source: hosted + version: "0.1.6" bloc: dependency: "direct main" description: @@ -2405,10 +2445,10 @@ packages: dependency: "direct main" description: name: window_manager - sha256: b3c895bdf936c77b83c5254bec2e6b3f066710c1f89c38b20b8acc382b525494 + sha256: "8699323b30da4cdbe2aa2e7c9de567a6abd8a97d9a5c850a3c86dcd0b34bbfbf" url: "https://pub.dev" source: hosted - version: "0.3.8" + version: "0.3.9" xdg_directories: dependency: transitive description: diff --git a/frontend/appflowy_flutter/pubspec.yaml b/frontend/appflowy_flutter/pubspec.yaml index 92e82d0c19..cf352947c8 100644 --- a/frontend/appflowy_flutter/pubspec.yaml +++ b/frontend/appflowy_flutter/pubspec.yaml @@ -94,7 +94,6 @@ dependencies: git: url: https://github.com/Xazin/flutter_calendar_view ref: "6fe0c98" - window_manager: ^0.3.4 http: ^1.0.0 path: ^1.8.3 mocktail: ^1.0.1 @@ -119,6 +118,7 @@ dependencies: # TODO: Consider implementing custom package # to gather notification handling for all platforms local_notifier: ^0.1.5 + app_links: ^3.5.0 flutter_slidable: ^3.0.0 image_picker: ^1.0.4 @@ -142,6 +142,12 @@ dependencies: reorderable_tabbar: ^1.0.6 shimmer: ^3.0.0 + # Window Manager for MacOS and Linux + window_manager: ^0.3.9 + + # BitsDojo Window for Windows + bitsdojo_window: ^0.1.6 + dev_dependencies: flutter_lints: ^3.0.1 analyzer: ^6.3.0 diff --git a/frontend/appflowy_flutter/windows/runner/main.cpp b/frontend/appflowy_flutter/windows/runner/main.cpp index 8def4fafbb..8ac91fd693 100644 --- a/frontend/appflowy_flutter/windows/runner/main.cpp +++ b/frontend/appflowy_flutter/windows/runner/main.cpp @@ -5,6 +5,9 @@ #include "flutter_window.h" #include "utils.h" +#include +auto bdw = bitsdojo_window_configure(BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP); + int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, _In_ wchar_t *command_line, _In_ int show_command) { HANDLE hMutexInstance = CreateMutex(NULL, TRUE, L"AppFlowyMutex"); From 383e06ff2da009f7e507c978c5e5c09deab6f452 Mon Sep 17 00:00:00 2001 From: Stefan Weiberg <2744377+suntorytimed@users.noreply.github.com> Date: Wed, 5 Jun 2024 13:57:31 +0200 Subject: [PATCH 07/16] chore: update German translations (#5456) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: update translations with Fink 🐦 * chore: update translations with Fink 🐦 --- frontend/resources/translations/de-DE.json | 46 +++++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/frontend/resources/translations/de-DE.json b/frontend/resources/translations/de-DE.json index f0c08ca52e..892e6ae9a5 100644 --- a/frontend/resources/translations/de-DE.json +++ b/frontend/resources/translations/de-DE.json @@ -47,7 +47,6 @@ "unmatchedPasswordError": "Passwörter stimmen nicht überein", "syncPromptMessage": "Synchronisation kann ein paar Minuten dauern. Diese Seite bitte nicht schließen", "or": "ODER", - "signInWith": "Anmeldeoptionen:", "signInWithGoogle": "Mit Google anmelden", "signInWithGithub": "Mit Github anmelden", "signInWithDiscord": "Mit Discord anmelden", @@ -148,6 +147,21 @@ "newGridText": "Neues Raster", "newCalendarText": "Neuer Kalender", "newBoardText": "Neues Board", + "chat": { + "newChat": "Neuer Chat", + "inputMessageHint": "Nachricht an AppFlowy AI", + "unsupportedCloudPrompt": "Diese Funktion ist nur bei Verwendung der AppFlowy Cloud verfügbar", + "relatedQuestion": "Verwandt", + "serverUnavailable": "Dienst vorübergehend nicht verfügbar. Bitte versuche es später erneut.", + "aiServerUnavailable": "Beim Generieren einer Antwort ist ein Fehler aufgetreten.", + "clickToRetry": "Erneut versuchen", + "regenerateAnswer": "Regenerieren", + "question1": "Wie verwendet man Kanban zur Aufgabenverwaltung?", + "question2": "Erkläre mir die GTD-Methode", + "question3": "Warum sollte ich Rust verwenden?", + "question4": "Gebe mir ein Rezept mit dem, was in meiner Küche ist", + "aiMistakePrompt": "KI kann Fehler machen. Überprüfe wichtige Informationen." + }, "trash": { "text": "Papierkorb", "restoreAll": "Alles wiederherstellen", @@ -249,6 +263,19 @@ "today": "Heute", "thisWeek": "Diese Woche", "others": "Andere", + "justNow": "soeben", + "minutesAgo": "vor {count} Minuten", + "lastViewed": "Zuletzt angesehen", + "favoriteAt": "Zu Favoriten hinzugefügt bei", + "emptyRecent": "Keine aktuellen Dokumente", + "emptyRecentDescription": "Kürzlich aufgerufene Dokumente werden hier, zur vereinfachten Auffindbarkeit, angezeigt.", + "emptyFavorite": "Keine favorisierten Dokumente", + "emptyFavoriteDescription": "Beginne mit der Erkundung und markiere Dokumente als Favoriten. Diese werden hier für den schnellen Zugriff aufgelistet!", + "removePageFromRecent": "Diese Seite aus „Zuletzt angesehen“ entfernen?", + "removeSuccess": "Erfolgreich entfernt", + "favoriteSpace": "Favoriten", + "RecentSpace": "Zuletzt angesehen", + "Spaces": "Gemeinsam genutzte Bereiche", "public": "Öffentlich", "clickToHidePublic": "Hier klicken, um den öffentlichen Bereich auszublenden.\nHier erstellte Seiten sind für jedes Mitglied sichtbar.", "addAPageToPublic": "Eine Seite zum öffentlichen Bereich hinzufügen." @@ -290,6 +317,7 @@ "update": "Update", "share": "Teilen", "removeFromFavorites": "Aus den Favoriten entfernen", + "removeFromRecent": "Aus „Zuletzt angesehen“ entfernen", "addToFavorites": "Zu den Favoriten hinzufügen", "rename": "Umbenennen", "helpCenter": "Hilfe Center", @@ -539,6 +567,10 @@ "enableNotifications": { "label": "Benachrichtigungen aktivieren", "hint": "Wenn diese Funktion ausgeschaltet ist, werden keine lokalen Benachrichtigungen mehr angezeigt." + }, + "showNotificationsIcon": { + "label": "Benachrichtigungssymbol anzeigen", + "hint": "Deaktiviere diese Option, um das Benachrichtigungssymbol in der Seitenleiste auszublenden." } }, "appearance": { @@ -1128,7 +1160,17 @@ "newDatabase": "Neue Datenbank", "linkToDatabase": "Verknüpfung zur Datenbank" }, - "date": "Datum" + "date": "Datum", + "video": { + "label": "Video", + "emptyLabel": "Video hinzufügen", + "placeholder": "Videolink einfügen", + "copiedToPasteBoard": "Der Videolink wurde in die Zwischenablage kopiert", + "insertVideo": "Video hinzufügen", + "invalidVideoUrl": "Die Quell-URL wird noch nicht unterstützt.", + "invalidVideoUrlYouTube": "YouTube wird noch nicht unterstützt.", + "supportedFormats": "Unterstützte Formate: MP4, WebM, MOV, AVI, FLV, MPEG/M4V, H.264" + } }, "outlineBlock": { "placeholder": "Inhaltsverzeichnis" From d73e388d019da3ff09d484d521b19d8ad4b0d749 Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Wed, 5 Jun 2024 21:36:44 +0800 Subject: [PATCH 08/16] chore: disable sync indicator (#5479) --- .../mobile/presentation/base/mobile_view_page.dart | 8 -------- .../lib/plugins/database/tab_bar/tab_bar_view.dart | 11 ----------- .../database_document/database_document_page.dart | 4 ---- .../lib/plugins/document/document.dart | 6 ------ .../lib/plugins/document/document_page.dart | 4 ---- .../flowy_infra_ui/lib/style_widget/text.dart | 6 ++++-- 6 files changed, 4 insertions(+), 35 deletions(-) diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/base/mobile_view_page.dart b/frontend/appflowy_flutter/lib/mobile/presentation/base/mobile_view_page.dart index 591f708546..9e21a002b1 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/base/mobile_view_page.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/base/mobile_view_page.dart @@ -6,7 +6,6 @@ import 'package:appflowy/mobile/presentation/base/view_page/app_bar_buttons.dart import 'package:appflowy/mobile/presentation/widgets/flowy_mobile_state_container.dart'; import 'package:appflowy/plugins/base/emoji/emoji_text.dart'; import 'package:appflowy/plugins/document/presentation/document_collaborators.dart'; -import 'package:appflowy/plugins/shared/sync_indicator.dart'; import 'package:appflowy/shared/feature_flags.dart'; import 'package:appflowy/startup/plugin/plugin.dart'; import 'package:appflowy/startup/startup.dart'; @@ -195,13 +194,6 @@ class _MobileViewPageState extends State { padding: const EdgeInsets.symmetric(vertical: 8), view: view, ), - const HSpace(16.0), - DocumentSyncIndicator(view: view), - const HSpace(12.0), - ]); - } else { - actions.addAll([ - DatabaseSyncIndicator(view: view), const HSpace(12.0), ]); } diff --git a/frontend/appflowy_flutter/lib/plugins/database/tab_bar/tab_bar_view.dart b/frontend/appflowy_flutter/lib/plugins/database/tab_bar/tab_bar_view.dart index aec6d954b4..690bac3fab 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/tab_bar/tab_bar_view.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/tab_bar/tab_bar_view.dart @@ -1,9 +1,7 @@ import 'package:appflowy/plugins/database/application/database_controller.dart'; import 'package:appflowy/plugins/database/application/tab_bar_bloc.dart'; import 'package:appflowy/plugins/database/widgets/share_button.dart'; -import 'package:appflowy/plugins/shared/sync_indicator.dart'; import 'package:appflowy/plugins/util.dart'; -import 'package:appflowy/shared/feature_flags.dart'; import 'package:appflowy/startup/plugin/plugin.dart'; import 'package:appflowy/workspace/application/view/view_bloc.dart'; import 'package:appflowy/workspace/application/view_info/view_info_bloc.dart'; @@ -272,15 +270,6 @@ class DatabasePluginWidgetBuilder extends PluginWidgetBuilder { value: bloc, child: Row( children: [ - ...FeatureFlag.syncDatabase.isOn - ? [ - DatabaseSyncIndicator( - key: ValueKey('sync_state_${view.id}'), - view: view, - ), - const HSpace(16), - ] - : [], DatabaseShareButton(key: ValueKey(view.id), view: view), const HSpace(10), ViewFavoriteButton(view: view), diff --git a/frontend/appflowy_flutter/lib/plugins/database_document/database_document_page.dart b/frontend/appflowy_flutter/lib/plugins/database_document/database_document_page.dart index 9f600e4a4e..c08b32d9ec 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_document/database_document_page.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_document/database_document_page.dart @@ -118,10 +118,6 @@ class _DatabaseDocumentPageState extends State { return Column( children: [ - // Only show the indicator in integration test mode - // if (FlowyRunner.currentMode.isIntegrationTest) - // const DocumentSyncIndicator(), - if (state.isDeleted) _buildBanner(context), Expanded(child: appflowyEditorPage), ], diff --git a/frontend/appflowy_flutter/lib/plugins/document/document.dart b/frontend/appflowy_flutter/lib/plugins/document/document.dart index b13ce1221c..ef11ef3403 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/document.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/document.dart @@ -6,7 +6,6 @@ import 'package:appflowy/plugins/document/application/document_appearance_cubit. import 'package:appflowy/plugins/document/document_page.dart'; import 'package:appflowy/plugins/document/presentation/document_collaborators.dart'; import 'package:appflowy/plugins/document/presentation/share/share_button.dart'; -import 'package:appflowy/plugins/shared/sync_indicator.dart'; import 'package:appflowy/plugins/util.dart'; import 'package:appflowy/shared/feature_flags.dart'; import 'package:appflowy/startup/plugin/plugin.dart'; @@ -153,11 +152,6 @@ class DocumentPluginWidgetBuilder extends PluginWidgetBuilder view: view, ), const HSpace(16), - DocumentSyncIndicator( - key: ValueKey('sync_state_${view.id}'), - view: view, - ), - const HSpace(16), ] : [const HSpace(8)], DocumentShareButton( diff --git a/frontend/appflowy_flutter/lib/plugins/document/document_page.dart b/frontend/appflowy_flutter/lib/plugins/document/document_page.dart index 231ff37bc9..097a23e5c9 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/document_page.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/document_page.dart @@ -139,10 +139,6 @@ class _DocumentPageState extends State return Column( children: [ - // Only show the indicator in integration test mode - // if (FlowyRunner.currentMode.isIntegrationTest) - // const DocumentSyncIndicator(), - if (state.isDeleted) _buildBanner(context), Expanded(child: child), ], diff --git a/frontend/appflowy_flutter/packages/flowy_infra_ui/lib/style_widget/text.dart b/frontend/appflowy_flutter/packages/flowy_infra_ui/lib/style_widget/text.dart index fafee3f623..71ac8e4854 100644 --- a/frontend/appflowy_flutter/packages/flowy_infra_ui/lib/style_widget/text.dart +++ b/frontend/appflowy_flutter/packages/flowy_infra_ui/lib/style_widget/text.dart @@ -143,6 +143,9 @@ class FlowyText extends StatelessWidget { if (fontFamily != null && fallbackFontFamily == null) { fallbackFontFamily = [fontFamily]; } + } + + if (isEmoji && (_useNotoColorEmoji || Platform.isWindows)) { fontSize = fontSize * 0.8; } @@ -199,6 +202,5 @@ class FlowyText extends StatelessWidget { return null; } - bool get _useNotoColorEmoji => - Platform.isLinux || Platform.isAndroid || Platform.isWindows; + bool get _useNotoColorEmoji => Platform.isLinux || Platform.isAndroid; } From 3b72f90ca5037ef84c73c556f83265146fd53b1f Mon Sep 17 00:00:00 2001 From: "Kilu.He" <108015703+qinluhe@users.noreply.github.com> Date: Thu, 6 Jun 2024 17:48:58 +0800 Subject: [PATCH 09/16] feat: improve test coverage (#5481) --- .github/workflows/web_coverage.yaml | 16 +- frontend/appflowy_web_app/.nycrc | 5 +- frontend/appflowy_web_app/jest.config.cjs | 22 +- frontend/appflowy_web_app/package.json | 7 +- frontend/appflowy_web_app/pnpm-lock.yaml | 1067 +++++++++++------ .../scripts/merge-coverage.cjs | 31 - .../src/application/collab.type.ts | 14 +- .../database-yjs/__tests__/filter.test.ts | 10 + .../__tests__/fixtures/sorts.json | 20 + .../database-yjs/__tests__/group.test.ts | 76 +- .../database-yjs/__tests__/parse.test.ts | 72 ++ .../database-yjs/__tests__/selector.test.tsx | 283 +++++ .../database-yjs/__tests__/sort.test.ts | 83 ++ .../database-yjs/__tests__/withTestingCell.ts | 43 + .../database-yjs/__tests__/withTestingData.ts | 154 ++- .../__tests__/withTestingField.ts | 59 +- .../database-yjs/__tests__/withTestingRows.ts | 2 + .../__tests__/withTestingSorts.ts | 22 + .../database-yjs}/cell.parse.ts | 0 .../database-yjs}/cell.type.ts | 2 +- .../src/application/database-yjs/const.ts | 10 +- .../src/application/database-yjs/context.ts | 15 - .../database-yjs/fields/date/utils.test.ts | 21 + .../src/application/database-yjs/filter.ts | 23 +- .../src/application/database-yjs/selector.ts | 21 +- .../src/application/database-yjs/sort.ts | 9 +- .../slate-yjs/__tests__/applyRemoteEvents.ts | 49 + .../slate-yjs/__tests__/convert.test.ts | 268 +++++ .../{utils => }/__tests__/convert.ts | 33 +- .../slate-yjs/__tests__/index.test.ts | 67 ++ .../__tests__/withTestingYjsEditor.ts | 135 +++ .../utils/__tests__/applyRemoteEvents.ts | 67 -- .../slate-yjs/utils/__tests__/index.test.ts | 12 - .../utils/__tests__/withTestingYjsEditor.ts | 45 - .../application/slate-yjs/utils/convert.ts | 105 +- .../calendar/event/EventPaperTitle.tsx | 2 +- .../database/components/cell/Cell.tsx | 2 +- .../database/components/cell/cell.const.ts | 12 - .../components/cell/checkbox/CheckboxCell.tsx | 2 +- .../cell/checklist/ChecklistCell.tsx | 2 +- .../components/cell/date/DateTimeCell.tsx | 2 +- .../components/cell/number/NumberCell.tsx | 2 +- .../components/cell/primary/PrimaryCell.tsx | 2 +- .../components/cell/relation/RelationCell.tsx | 2 +- .../cell/relation/RelationItems.tsx | 2 +- .../cell/relation/RelationPrimaryValue.tsx | 2 +- .../cell/select-option/SelectOptionCell.tsx | 2 +- .../components/cell/text/TextCell.tsx | 2 +- .../database/components/cell/url/UrlCell.tsx | 2 +- .../components/grid/grid-cell/GridCell.tsx | 2 +- .../grid/grid-row/useRenderRows.tsx | 13 +- .../database/components/property/Property.tsx | 2 +- .../property/cheklist/ChecklistProperty.tsx | 2 +- .../components/property/text/TextProperty.tsx | 2 +- .../src/components/database/grid/Grid.tsx | 33 +- frontend/appflowy_web_app/src/utils/font.ts | 15 +- frontend/appflowy_web_app/vite.config.ts | 15 +- 57 files changed, 2274 insertions(+), 716 deletions(-) delete mode 100644 frontend/appflowy_web_app/scripts/merge-coverage.cjs create mode 100644 frontend/appflowy_web_app/src/application/database-yjs/__tests__/parse.test.ts create mode 100644 frontend/appflowy_web_app/src/application/database-yjs/__tests__/selector.test.tsx create mode 100644 frontend/appflowy_web_app/src/application/database-yjs/__tests__/withTestingCell.ts rename frontend/appflowy_web_app/src/{components/database/components/cell => application/database-yjs}/cell.parse.ts (100%) rename frontend/appflowy_web_app/src/{components/database/components/cell => application/database-yjs}/cell.type.ts (99%) create mode 100644 frontend/appflowy_web_app/src/application/database-yjs/fields/date/utils.test.ts create mode 100644 frontend/appflowy_web_app/src/application/slate-yjs/__tests__/applyRemoteEvents.ts create mode 100644 frontend/appflowy_web_app/src/application/slate-yjs/__tests__/convert.test.ts rename frontend/appflowy_web_app/src/application/slate-yjs/{utils => }/__tests__/convert.ts (65%) create mode 100644 frontend/appflowy_web_app/src/application/slate-yjs/__tests__/index.test.ts create mode 100644 frontend/appflowy_web_app/src/application/slate-yjs/__tests__/withTestingYjsEditor.ts delete mode 100644 frontend/appflowy_web_app/src/application/slate-yjs/utils/__tests__/applyRemoteEvents.ts delete mode 100644 frontend/appflowy_web_app/src/application/slate-yjs/utils/__tests__/index.test.ts delete mode 100644 frontend/appflowy_web_app/src/application/slate-yjs/utils/__tests__/withTestingYjsEditor.ts diff --git a/.github/workflows/web_coverage.yaml b/.github/workflows/web_coverage.yaml index 258119664a..7803f719c9 100644 --- a/.github/workflows/web_coverage.yaml +++ b/.github/workflows/web_coverage.yaml @@ -6,6 +6,7 @@ on: - ".github/workflows/web2_ci.yaml" - "frontend/appflowy_web_app/**" - "frontend/resources/**" + env: NODE_VERSION: "18.16.0" PNPM_VERSION: "8.5.0" @@ -52,8 +53,13 @@ jobs: run: | pnpm run test:unit - - name: Generate and post coverage summary - working-directory: frontend/appflowy_web_app - run: | - pnpm run merge-coverage - + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v2 + with: + token: cf9245e0-e136-4e21-b0ee-35755fa0c493 + files: frontend/appflowy_web_app/coverage/jest/lcov.info,frontend/appflowy_web_app/coverage/cypress/lcov.info + flags: appflowy_web_app + name: frontend/appflowy_web_app + fail_ci_if_error: true + verbose: true + diff --git a/frontend/appflowy_web_app/.nycrc b/frontend/appflowy_web_app/.nycrc index 9d69b3c074..dc571c1abb 100644 --- a/frontend/appflowy_web_app/.nycrc +++ b/frontend/appflowy_web_app/.nycrc @@ -1,6 +1,6 @@ { "all": true, - "extends": "@istanbuljs/nyc-config-typescript", + "extends": "@istanbuljs/nyc-config-babel", "include": [ "src/**/*.ts", "src/**/*.tsx" @@ -15,7 +15,8 @@ "text", "html", "text-summary", - "json" + "json", + "lcov" ], "temp-dir": "coverage/.nyc_output", "report-dir": "coverage/cypress" diff --git a/frontend/appflowy_web_app/jest.config.cjs b/frontend/appflowy_web_app/jest.config.cjs index b21b3c1ae3..b226459c4b 100644 --- a/frontend/appflowy_web_app/jest.config.cjs +++ b/frontend/appflowy_web_app/jest.config.cjs @@ -5,7 +5,7 @@ const esModules = ['lodash-es', 'nanoid'].join('|'); /** @type {import('ts-jest').JestConfigWithTsJest} */ module.exports = { preset: 'ts-jest', - testEnvironment: 'node', + testEnvironment: 'jsdom', roots: [''], modulePaths: [compilerOptions.baseUrl], moduleNameMapper: { @@ -14,10 +14,28 @@ module.exports = { '^nanoid(/(.*)|$)': 'nanoid$1', }, 'transform': { + '^.+\\.(j|t)sx?$': 'ts-jest', '(.*)/node_modules/nanoid/.+\\.(j|t)sx?$': 'ts-jest', }, 'transformIgnorePatterns': [`/node_modules/(?!${esModules})`], - testMatch: ['**/*.test.ts'], + testMatch: ['**/*.test.ts', '**/*.test.tsx'], coverageDirectory: '/coverage/jest', collectCoverage: true, + coverageProvider: 'v8', + coveragePathIgnorePatterns: [ + '/cypress/', + '/coverage/', + '/node_modules/', + '/__tests__/', + '/__mocks__/', + '/__fixtures__/', + '/__helpers__/', + '/__utils__/', + '/__constants__/', + '/__types__/', + '/__mocks__/', + '/__stubs__/', + '/__fixtures__/', + '/application/folder-yjs/', + ], }; \ No newline at end of file diff --git a/frontend/appflowy_web_app/package.json b/frontend/appflowy_web_app/package.json index 09dbe21254..f822a6b0f9 100644 --- a/frontend/appflowy_web_app/package.json +++ b/frontend/appflowy_web_app/package.json @@ -21,8 +21,7 @@ "test:components": "cypress run --component --browser chrome --headless", "test:unit": "jest --coverage", "test:cy": "cypress run", - "merge-coverage": "node scripts/merge-coverage.cjs", - "coverage": "pnpm run test:unit && pnpm run test:components && pnpm run merge-coverage" + "coverage": "pnpm run test:unit && pnpm run test:components" }, "dependencies": { "@appflowyinc/client-api-wasm": "0.0.3", @@ -99,11 +98,15 @@ "yjs": "^13.6.14" }, "devDependencies": { + "@babel/preset-env": "^7.24.7", + "@babel/preset-react": "^7.24.7", + "@babel/preset-typescript": "^7.24.7", "@cypress/code-coverage": "^3.12.39", "@istanbuljs/nyc-config-babel": "^3.0.0", "@istanbuljs/nyc-config-typescript": "^1.0.2", "@svgr/plugin-svgo": "^8.0.1", "@tauri-apps/cli": "^1.5.11", + "@testing-library/react": "^16.0.0", "@types/google-protobuf": "^3.15.12", "@types/is-hotkey": "^0.1.7", "@types/jest": "^29.5.3", diff --git a/frontend/appflowy_web_app/pnpm-lock.yaml b/frontend/appflowy_web_app/pnpm-lock.yaml index 37a34b9470..194beaa5dd 100644 --- a/frontend/appflowy_web_app/pnpm-lock.yaml +++ b/frontend/appflowy_web_app/pnpm-lock.yaml @@ -219,9 +219,18 @@ dependencies: version: 13.6.15 devDependencies: + '@babel/preset-env': + specifier: ^7.24.7 + version: 7.24.7(@babel/core@7.24.3) + '@babel/preset-react': + specifier: ^7.24.7 + version: 7.24.7(@babel/core@7.24.3) + '@babel/preset-typescript': + specifier: ^7.24.7 + version: 7.24.7(@babel/core@7.24.3) '@cypress/code-coverage': specifier: ^3.12.39 - version: 3.12.39(@babel/core@7.24.3)(@babel/preset-env@7.24.6)(babel-loader@9.1.3)(cypress@13.7.2)(webpack@5.91.0) + version: 3.12.39(@babel/core@7.24.3)(@babel/preset-env@7.24.7)(babel-loader@9.1.3)(cypress@13.7.2)(webpack@5.91.0) '@istanbuljs/nyc-config-babel': specifier: ^3.0.0 version: 3.0.0(@babel/register@7.24.6)(babel-plugin-istanbul@6.1.1) @@ -234,6 +243,9 @@ devDependencies: '@tauri-apps/cli': specifier: ^1.5.11 version: 1.5.11 + '@testing-library/react': + specifier: ^16.0.0 + version: 16.0.0(@testing-library/dom@10.1.0)(@types/react-dom@18.2.22)(@types/react@18.2.66)(react-dom@18.2.0)(react@18.2.0) '@types/google-protobuf': specifier: ^3.15.12 version: 3.15.12 @@ -491,7 +503,7 @@ packages: /@atlaskit/platform-feature-flags@0.2.5: resolution: {integrity: sha512-0fD2aDxn2mE59D4acUhVib+YF2HDYuuPH50aYwpQdcV/CsVkAaJsMKy8WhWSulcRFeMYp72kfIfdy0qGdRB7Uw==} dependencies: - '@babel/runtime': 7.24.1 + '@babel/runtime': 7.24.6 dev: false /@atlaskit/primitives@5.7.0(@types/react@18.2.66)(react@18.2.0): @@ -552,11 +564,11 @@ packages: '@babel/highlight': 7.24.2 picocolors: 1.0.0 - /@babel/code-frame@7.24.6: - resolution: {integrity: sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==} + /@babel/code-frame@7.24.7: + resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/highlight': 7.24.6 + '@babel/highlight': 7.24.7 picocolors: 1.0.0 dev: true @@ -564,8 +576,8 @@ packages: resolution: {integrity: sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==} engines: {node: '>=6.9.0'} - /@babel/compat-data@7.24.6: - resolution: {integrity: sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ==} + /@babel/compat-data@7.24.7: + resolution: {integrity: sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==} engines: {node: '>=6.9.0'} dev: true @@ -600,18 +612,31 @@ packages: '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 - /@babel/helper-annotate-as-pure@7.24.6: - resolution: {integrity: sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==} + /@babel/generator@7.24.7: + resolution: {integrity: sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.6 + '@babel/types': 7.24.7 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 dev: true - /@babel/helper-builder-binary-assignment-operator-visitor@7.24.6: - resolution: {integrity: sha512-+wnfqc5uHiMYtvRX7qu80Toef8BXeh4HHR1SPeonGb1SKPniNEd4a/nlaJJMv/OIEYvIVavvo0yR7u10Gqz0Iw==} + /@babel/helper-annotate-as-pure@7.24.7: + resolution: {integrity: sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.6 + '@babel/types': 7.24.7 + dev: true + + /@babel/helper-builder-binary-assignment-operator-visitor@7.24.7: + resolution: {integrity: sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true /@babel/helper-compilation-targets@7.23.6: @@ -624,33 +649,35 @@ packages: lru-cache: 5.1.1 semver: 6.3.1 - /@babel/helper-compilation-targets@7.24.6: - resolution: {integrity: sha512-VZQ57UsDGlX/5fFA7GkVPplZhHsVc+vuErWgdOiysI9Ksnw0Pbbd6pnPiR/mmJyKHgyIW0c7KT32gmhiF+cirg==} + /@babel/helper-compilation-targets@7.24.7: + resolution: {integrity: sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/compat-data': 7.24.6 - '@babel/helper-validator-option': 7.24.6 + '@babel/compat-data': 7.24.7 + '@babel/helper-validator-option': 7.24.7 browserslist: 4.23.0 lru-cache: 5.1.1 semver: 6.3.1 dev: true - /@babel/helper-create-class-features-plugin@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-djsosdPJVZE6Vsw3kk7IPRWethP94WHGOhQTc67SNXE0ZzMhHgALw8iGmYS0TD1bbMM0VDROy43od7/hN6WYcA==} + /@babel/helper-create-class-features-plugin@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-kTkaDl7c9vO80zeX1rJxnuRpEsD5tA81yh11X1gQo+PhSti3JS+7qeZo9U4RHobKRiFPKaGK3svUAeb8D0Q7eg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-annotate-as-pure': 7.24.6 - '@babel/helper-environment-visitor': 7.24.6 - '@babel/helper-function-name': 7.24.6 - '@babel/helper-member-expression-to-functions': 7.24.6 - '@babel/helper-optimise-call-expression': 7.24.6 - '@babel/helper-replace-supers': 7.24.6(@babel/core@7.24.3) - '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 - '@babel/helper-split-export-declaration': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-member-expression-to-functions': 7.24.7 + '@babel/helper-optimise-call-expression': 7.24.7 + '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.3) + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 semver: 6.3.1 + transitivePeerDependencies: + - supports-color dev: true /@babel/helper-create-regexp-features-plugin@7.24.6(@babel/core@7.24.3): @@ -660,7 +687,19 @@ packages: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-annotate-as-pure': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.7 + regexpu-core: 5.3.2 + semver: 6.3.1 + dev: true + + /@babel/helper-create-regexp-features-plugin@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-annotate-as-pure': 7.24.7 regexpu-core: 5.3.2 semver: 6.3.1 dev: true @@ -671,8 +710,8 @@ packages: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-compilation-targets': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 debug: 4.3.4(supports-color@8.1.1) lodash.debounce: 4.0.8 resolve: 1.22.8 @@ -684,9 +723,11 @@ packages: resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} engines: {node: '>=6.9.0'} - /@babel/helper-environment-visitor@7.24.6: - resolution: {integrity: sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==} + /@babel/helper-environment-visitor@7.24.7: + resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.7 dev: true /@babel/helper-function-name@7.23.0: @@ -696,12 +737,12 @@ packages: '@babel/template': 7.24.0 '@babel/types': 7.24.0 - /@babel/helper-function-name@7.24.6: - resolution: {integrity: sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==} + /@babel/helper-function-name@7.24.7: + resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.24.6 - '@babel/types': 7.24.6 + '@babel/template': 7.24.7 + '@babel/types': 7.24.7 dev: true /@babel/helper-hoist-variables@7.22.5: @@ -710,18 +751,21 @@ packages: dependencies: '@babel/types': 7.24.0 - /@babel/helper-hoist-variables@7.24.6: - resolution: {integrity: sha512-SF/EMrC3OD7dSta1bLJIlrsVxwtd0UpjRJqLno6125epQMJ/kyFmpTT4pbvPbdQHzCHg+biQ7Syo8lnDtbR+uA==} + /@babel/helper-hoist-variables@7.24.7: + resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.6 + '@babel/types': 7.24.7 dev: true - /@babel/helper-member-expression-to-functions@7.24.6: - resolution: {integrity: sha512-OTsCufZTxDUsv2/eDXanw/mUZHWOxSbEmC3pP8cgjcy5rgeVPWWMStnv274DV60JtHxTk0adT0QrCzC4M9NWGg==} + /@babel/helper-member-expression-to-functions@7.24.7: + resolution: {integrity: sha512-LGeMaf5JN4hAT471eJdBs/GK1DoYIJ5GCtZN/EsL6KUiiDZOvO/eKE11AMZJa2zP4zk4qe9V2O/hxAmkRc8p6w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.6 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true /@babel/helper-module-imports@7.24.3: @@ -730,11 +774,14 @@ packages: dependencies: '@babel/types': 7.24.0 - /@babel/helper-module-imports@7.24.6: - resolution: {integrity: sha512-a26dmxFJBF62rRO9mmpgrfTLsAuyHk4e1hKTUkD/fcMfynt8gvEKwQPQDVxWhca8dHoDck+55DFt42zV0QMw5g==} + /@babel/helper-module-imports@7.24.7: + resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.6 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true /@babel/helper-module-transforms@7.23.3(@babel/core@7.24.3): @@ -750,58 +797,63 @@ packages: '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.22.20 - /@babel/helper-module-transforms@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-Y/YMPm83mV2HJTbX1Qh2sjgjqcacvOlhbzdCCsSlblOKjSYmQqEbO6rUniWQyRo9ncyfjT8hnUjlG06RXDEmcA==} + /@babel/helper-module-transforms@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-environment-visitor': 7.24.6 - '@babel/helper-module-imports': 7.24.6 - '@babel/helper-simple-access': 7.24.6 - '@babel/helper-split-export-declaration': 7.24.6 - '@babel/helper-validator-identifier': 7.24.6 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-optimise-call-expression@7.24.6: - resolution: {integrity: sha512-3SFDJRbx7KuPRl8XDUr8O7GAEB8iGyWPjLKJh/ywP/Iy9WOmEfMrsWbaZpvBu2HSYn4KQygIsz0O7m8y10ncMA==} + /@babel/helper-optimise-call-expression@7.24.7: + resolution: {integrity: sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.6 + '@babel/types': 7.24.7 dev: true /@babel/helper-plugin-utils@7.24.0: resolution: {integrity: sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==} engines: {node: '>=6.9.0'} - /@babel/helper-plugin-utils@7.24.6: - resolution: {integrity: sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==} + /@babel/helper-plugin-utils@7.24.7: + resolution: {integrity: sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==} engines: {node: '>=6.9.0'} - dev: true - /@babel/helper-remap-async-to-generator@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-1Qursq9ArRZPAMOZf/nuzVW8HgJLkTB9y9LfP4lW2MVp4e9WkLJDovfKBxoDcCk6VuzIxyqWHyBoaCtSRP10yg==} + /@babel/helper-remap-async-to-generator@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-annotate-as-pure': 7.24.6 - '@babel/helper-environment-visitor': 7.24.6 - '@babel/helper-wrap-function': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-wrap-function': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-replace-supers@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-mRhfPwDqDpba8o1F8ESxsEkJMQkUF8ZIWrAc0FtWhxnjfextxMWxr22RtFizxxSYLjVHDeMgVsRq8BBZR2ikJQ==} + /@babel/helper-replace-supers@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-environment-visitor': 7.24.6 - '@babel/helper-member-expression-to-functions': 7.24.6 - '@babel/helper-optimise-call-expression': 7.24.6 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-member-expression-to-functions': 7.24.7 + '@babel/helper-optimise-call-expression': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true /@babel/helper-simple-access@7.22.5: @@ -810,18 +862,24 @@ packages: dependencies: '@babel/types': 7.24.0 - /@babel/helper-simple-access@7.24.6: - resolution: {integrity: sha512-nZzcMMD4ZhmB35MOOzQuiGO5RzL6tJbsT37Zx8M5L/i9KSrukGXWTjLe1knIbb/RmxoJE9GON9soq0c0VEMM5g==} + /@babel/helper-simple-access@7.24.7: + resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.6 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-skip-transparent-expression-wrappers@7.24.6: - resolution: {integrity: sha512-jhbbkK3IUKc4T43WadP96a27oYti9gEf1LdyGSP2rHGH77kwLwfhO7TgwnWvxxQVmke0ImmCSS47vcuxEMGD3Q==} + /@babel/helper-skip-transparent-expression-wrappers@7.24.7: + resolution: {integrity: sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.6 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true /@babel/helper-split-export-declaration@7.22.6: @@ -830,11 +888,11 @@ packages: dependencies: '@babel/types': 7.24.0 - /@babel/helper-split-export-declaration@7.24.6: - resolution: {integrity: sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==} + /@babel/helper-split-export-declaration@7.24.7: + resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.6 + '@babel/types': 7.24.7 dev: true /@babel/helper-string-parser@7.24.1: @@ -846,12 +904,17 @@ packages: engines: {node: '>=6.9.0'} dev: true + /@babel/helper-string-parser@7.24.7: + resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/helper-validator-identifier@7.22.20: resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} engines: {node: '>=6.9.0'} - /@babel/helper-validator-identifier@7.24.6: - resolution: {integrity: sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==} + /@babel/helper-validator-identifier@7.24.7: + resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} engines: {node: '>=6.9.0'} dev: true @@ -859,18 +922,21 @@ packages: resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} engines: {node: '>=6.9.0'} - /@babel/helper-validator-option@7.24.6: - resolution: {integrity: sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ==} + /@babel/helper-validator-option@7.24.7: + resolution: {integrity: sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-wrap-function@7.24.6: - resolution: {integrity: sha512-f1JLrlw/jbiNfxvdrfBgio/gRBk3yTAEJWirpAkiJG2Hb22E7cEYKHWo0dFPTv/niPovzIdPdEDetrv6tC6gPQ==} + /@babel/helper-wrap-function@7.24.7: + resolution: {integrity: sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-function-name': 7.24.6 - '@babel/template': 7.24.6 - '@babel/types': 7.24.6 + '@babel/helper-function-name': 7.24.7 + '@babel/template': 7.24.7 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true /@babel/helpers@7.24.1: @@ -892,11 +958,11 @@ packages: js-tokens: 4.0.0 picocolors: 1.0.0 - /@babel/highlight@7.24.6: - resolution: {integrity: sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==} + /@babel/highlight@7.24.7: + resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-validator-identifier': 7.24.6 + '@babel/helper-validator-identifier': 7.24.7 chalk: 2.4.2 js-tokens: 4.0.0 picocolors: 1.0.0 @@ -909,56 +975,58 @@ packages: dependencies: '@babel/types': 7.24.0 - /@babel/parser@7.24.6: - resolution: {integrity: sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==} + /@babel/parser@7.24.7: + resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.24.6 + '@babel/types': 7.24.7 dev: true - /@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-bYndrJ6Ph6Ar+GaB5VAc0JPoP80bQCm4qon6JEzXfRl5QZyQ8Ur1K6k7htxWmPA5z+k7JQvaMUrtXlqclWYzKw==} + /@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-environment-visitor': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-iVuhb6poq5ikqRq2XWU6OQ+R5o9wF+r/or9CeUyovgptz0UlnK4/seOQ1Istu/XybYjAhQv1FRSSfHHufIku5Q==} + /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-c8TER5xMDYzzFcGqOEp9l4hvB7dcbhcGjcLVwxWfe4P5DOafdwjsBJZKsmv+o3aXh7NhopvayQIovHrh2zSRUQ==} + /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.13.0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 - '@babel/plugin-transform-optional-chaining': 7.24.6(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + '@babel/plugin-transform-optional-chaining': 7.24.7(@babel/core@7.24.3) + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-z8zEjYmwBUHN/pCF3NuWBhHQjJCrd33qAi8MgANfMrAvn72k2cImT8VjK9LJFu4ysOLJqhfkYYb3MvwANRUNZQ==} + /@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-environment-visitor': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.3): @@ -976,7 +1044,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-plugin-utils': 7.24.7 /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.3): resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} @@ -992,7 +1060,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-plugin-utils': 7.24.7 /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.3): resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} @@ -1001,7 +1069,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.3): @@ -1010,7 +1078,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.3): @@ -1019,27 +1087,27 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-import-assertions@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-BE6o2BogJKJImTmGpkmOic4V0hlRRxVtzqxiSPa8TIFxyhi4EFjHm08nq1M4STK4RytuLMgnSz0/wfflvGFNOg==} + /@babel/plugin-syntax-import-assertions@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-import-attributes@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-D+CfsVZousPXIdudSII7RGy52+dYRtbyKAZcvtQKq/NpsivyMVduepzcLqG5pMBugtMdedxdC8Ramdpcne9ZWQ==} + /@babel/plugin-syntax-import-attributes@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.3): @@ -1067,13 +1135,23 @@ packages: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 + /@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.7 + dev: true + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.3): resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-plugin-utils': 7.24.7 /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.3): resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} @@ -1122,7 +1200,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.3): @@ -1143,6 +1221,16 @@ packages: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 + /@babel/plugin-syntax-typescript@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.7 + dev: true + /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.3): resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} engines: {node: '>=6.9.0'} @@ -1151,423 +1239,475 @@ packages: dependencies: '@babel/core': 7.24.3 '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.3) - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-arrow-functions@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-jSSSDt4ZidNMggcLx8SaKsbGNEfIl0PHx/4mFEulorE7bpYLbN0d3pDW3eJ7Y5Z3yPhy3L3NaPCYyTUY7TuugQ==} + /@babel/plugin-transform-arrow-functions@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-async-generator-functions@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-VEP2o4iR2DqQU6KPgizTW2mnMx6BG5b5O9iQdrW9HesLkv8GIA8x2daXBQxw1MrsIkFQGA/iJ204CKoQ8UcnAA==} + /@babel/plugin-transform-async-generator-functions@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-environment-visitor': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-remap-async-to-generator': 7.24.6(@babel/core@7.24.3) + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-remap-async-to-generator': 7.24.7(@babel/core@7.24.3) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.3) + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-async-to-generator@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-NTBA2SioI3OsHeIn6sQmhvXleSl9T70YY/hostQLveWs0ic+qvbA3fa0kwAwQ0OA/XGaAerNZRQGJyRfhbJK4g==} + /@babel/plugin-transform-async-to-generator@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-module-imports': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-remap-async-to-generator': 7.24.6(@babel/core@7.24.3) + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-remap-async-to-generator': 7.24.7(@babel/core@7.24.3) + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-block-scoped-functions@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-XNW7jolYHW9CwORrZgA/97tL/k05qe/HL0z/qqJq1mdWhwwCM6D4BJBV7wAz9HgFziN5dTOG31znkVIzwxv+vw==} + /@babel/plugin-transform-block-scoped-functions@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-block-scoping@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-S/t1Xh4ehW7sGA7c1j/hiOBLnEYCp/c2sEG4ZkL8kI1xX9tW2pqJTCHKtdhe/jHKt8nG0pFCrDHUXd4DvjHS9w==} + /@babel/plugin-transform-block-scoping@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-class-properties@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-j6dZ0Z2Z2slWLR3kt9aOmSIrBvnntWjMDN/TVcMPxhXMLmJVqX605CBRlcGI4b32GMbfifTEsdEjGjiE+j/c3A==} + /@babel/plugin-transform-class-properties@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.3) - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-class-static-block@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-1QSRfoPI9RoLRa8Mnakc6v3e0gJxiZQTYrMfLn+mD0sz5+ndSzwymp2hDcYJTyT0MOn0yuWzj8phlIvO72gTHA==} + /@babel/plugin-transform-class-static-block@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.12.0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.3) - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.3) + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-classes@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-+fN+NO2gh8JtRmDSOB6gaCVo36ha8kfCW1nMq2Gc0DABln0VcHN4PrALDvF5/diLzIRKptC7z/d7Lp64zk92Fg==} + /@babel/plugin-transform-classes@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-CFbbBigp8ln4FU6Bpy6g7sE8B/WmCmzvivzUC6xDAdWVsjYTXijpuuGJmYkAaoWAzcItGKT3IOAbxRItZ5HTjw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-annotate-as-pure': 7.24.6 - '@babel/helper-compilation-targets': 7.24.6 - '@babel/helper-environment-visitor': 7.24.6 - '@babel/helper-function-name': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-replace-supers': 7.24.6(@babel/core@7.24.3) - '@babel/helper-split-export-declaration': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.3) + '@babel/helper-split-export-declaration': 7.24.7 globals: 11.12.0 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-computed-properties@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-cRzPobcfRP0ZtuIEkA8QzghoUpSB3X3qSH5W2+FzG+VjWbJXExtx0nbRqwumdBN1x/ot2SlTNQLfBCnPdzp6kg==} + /@babel/plugin-transform-computed-properties@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/template': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/template': 7.24.7 dev: true - /@babel/plugin-transform-destructuring@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-YLW6AE5LQpk5npNXL7i/O+U9CE4XsBCuRPgyjl1EICZYKmcitV+ayuuUGMJm2lC1WWjXYszeTnIxF/dq/GhIZQ==} + /@babel/plugin-transform-destructuring@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-19eJO/8kdCQ9zISOf+SEUJM/bAUIsvY3YDnXZTupUCQ8LgrWnsG/gFB9dvXqdXnRXMAM8fvt7b0CBKQHNGy1mw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-dotall-regex@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-rCXPnSEKvkm/EjzOtLoGvKseK+dS4kZwx1HexO3BtRtgL0fQ34awHn34aeSHuXtZY2F8a1X8xqBBPRtOxDVmcA==} + /@babel/plugin-transform-dotall-regex@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.3) - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-duplicate-keys@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-/8Odwp/aVkZwPFJMllSbawhDAO3UJi65foB00HYnK/uXvvCPm0TAXSByjz1mpRmp0q6oX2SIxpkUOpPFHk7FLA==} + /@babel/plugin-transform-duplicate-keys@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-dynamic-import@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-vpq8SSLRTBLOHUZHSnBqVo0AKX3PBaoPs2vVzYVWslXDTDIpwAcCDtfhUcHSQQoYoUvcFPTdC8TZYXu9ZnLT/w==} + /@babel/plugin-transform-dynamic-import@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.3) dev: true - /@babel/plugin-transform-exponentiation-operator@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-EemYpHtmz0lHE7hxxxYEuTYOOBZ43WkDgZ4arQ4r+VX9QHuNZC+WH3wUWmRNvR8ECpTRne29aZV6XO22qpOtdA==} + /@babel/plugin-transform-exponentiation-operator@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-builder-binary-assignment-operator-visitor': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-export-namespace-from@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-inXaTM1SVrIxCkIJ5gqWiozHfFMStuGbGJAxZFBoHcRRdDP0ySLb3jH6JOwmfiinPwyMZqMBX+7NBDCO4z0NSA==} + /@babel/plugin-transform-export-namespace-from@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.3) dev: true - /@babel/plugin-transform-for-of@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-n3Sf72TnqK4nw/jziSqEl1qaWPbCRw2CziHH+jdRYvw4J6yeCzsj4jdw8hIntOEeDGTmHVe2w4MVL44PN0GMzg==} + /@babel/plugin-transform-for-of@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-function-name@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-sOajCu6V0P1KPljWHKiDq6ymgqB+vfo3isUS4McqW1DZtvSVU2v/wuMhmRmkg3sFoq6GMaUUf8W4WtoSLkOV/Q==} + /@babel/plugin-transform-function-name@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-compilation-targets': 7.24.6 - '@babel/helper-function-name': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-json-strings@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-Uvgd9p2gUnzYJxVdBLcU0KurF8aVhkmVyMKW4MIY1/BByvs3EBpv45q01o7pRTVmTvtQq5zDlytP3dcUgm7v9w==} + /@babel/plugin-transform-json-strings@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.3) dev: true - /@babel/plugin-transform-literals@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-f2wHfR2HF6yMj+y+/y07+SLqnOSwRp8KYLpQKOzS58XLVlULhXbiYcygfXQxJlMbhII9+yXDwOUFLf60/TL5tw==} + /@babel/plugin-transform-literals@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-logical-assignment-operators@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-EKaWvnezBCMkRIHxMJSIIylzhqK09YpiJtDbr2wsXTwnO0TxyjMUkaw4RlFIZMIS0iDj0KyIg7H7XCguHu/YDA==} + /@babel/plugin-transform-logical-assignment-operators@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.3) dev: true - /@babel/plugin-transform-member-expression-literals@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-9g8iV146szUo5GWgXpRbq/GALTnY+WnNuRTuRHWWFfWGbP9ukRL0aO/jpu9dmOPikclkxnNsjY8/gsWl6bmZJQ==} + /@babel/plugin-transform-member-expression-literals@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-modules-amd@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-eAGogjZgcwqAxhyFgqghvoHRr+EYRQPFjUXrTYKBRb5qPnAVxOOglaxc4/byHqjvq/bqO2F3/CGwTHsgKJYHhQ==} + /@babel/plugin-transform-modules-amd@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.3) - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-modules-commonjs@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-JEV8l3MHdmmdb7S7Cmx6rbNEjRCgTQMZxllveHO0mx6uiclB0NflCawlQQ6+o5ZrwjUBYPzHm2XoK4wqGVUFuw==} + /@babel/plugin-transform-modules-commonjs@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-iFI8GDxtevHJ/Z22J5xQpVqFLlMNstcLXh994xifFwxxGslr2ZXXLWgtBeLctOD63UFDArdvN6Tg8RFw+aEmjQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.3) - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-simple-access': 7.24.6 + '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-modules-systemjs@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-xg1Z0J5JVYxtpX954XqaaAT6NpAY6LtZXvYFCJmGFJWwtlz2EmJoR8LycFRGNE8dBKizGWkGQZGegtkV8y8s+w==} + /@babel/plugin-transform-modules-systemjs@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-hoist-variables': 7.24.6 - '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.3) - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-validator-identifier': 7.24.6 + '@babel/helper-hoist-variables': 7.24.7 + '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-modules-umd@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-esRCC/KsSEUvrSjv5rFYnjZI6qv4R1e/iHQrqwbZIoRJqk7xCvEUiN7L1XrmW5QSmQe3n1XD88wbgDTWLbVSyg==} + /@babel/plugin-transform-modules-umd@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.3) - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-named-capturing-groups-regex@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-6DneiCiu91wm3YiNIGDWZsl6GfTTbspuj/toTEqLh9d4cx50UIzSdg+T96p8DuT7aJOBRhFyaE9ZvTHkXrXr6Q==} + /@babel/plugin-transform-named-capturing-groups-regex@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.3) - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-new-target@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-f8liz9JG2Va8A4J5ZBuaSdwfPqN6axfWRK+y66fjKYbwf9VBLuq4WxtinhJhvp1w6lamKUwLG0slK2RxqFgvHA==} + /@babel/plugin-transform-new-target@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-nullish-coalescing-operator@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-+QlAiZBMsBK5NqrBWFXCYeXyiU1y7BQ/OYaiPAcQJMomn5Tyg+r5WuVtyEuvTbpV7L25ZSLfE+2E9ywj4FD48A==} + /@babel/plugin-transform-nullish-coalescing-operator@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.3) dev: true - /@babel/plugin-transform-numeric-separator@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-6voawq8T25Jvvnc4/rXcWZQKKxUNZcKMS8ZNrjxQqoRFernJJKjE3s18Qo6VFaatG5aiX5JV1oPD7DbJhn0a4Q==} + /@babel/plugin-transform-numeric-separator@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.3) dev: true - /@babel/plugin-transform-object-rest-spread@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-OKmi5wiMoRW5Smttne7BwHM8s/fb5JFs+bVGNSeHWzwZkWXWValR1M30jyXo1s/RaqgwwhEC62u4rFH/FBcBPg==} + /@babel/plugin-transform-object-rest-spread@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-compilation-targets': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.3) - '@babel/plugin-transform-parameters': 7.24.6(@babel/core@7.24.3) + '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.24.3) dev: true - /@babel/plugin-transform-object-super@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-N/C76ihFKlZgKfdkEYKtaRUtXZAgK7sOY4h2qrbVbVTXPrKGIi8aww5WGe/+Wmg8onn8sr2ut6FXlsbu/j6JHg==} + /@babel/plugin-transform-object-super@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-replace-supers': 7.24.6(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.3) + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-optional-catch-binding@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-L5pZ+b3O1mSzJ71HmxSCmTVd03VOT2GXOigug6vDYJzE5awLI7P1g0wFcdmGuwSDSrQ0L2rDOe/hHws8J1rv3w==} + /@babel/plugin-transform-optional-catch-binding@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.3) dev: true - /@babel/plugin-transform-optional-chaining@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-cHbqF6l1QP11OkYTYQ+hhVx1E017O5ZcSPXk9oODpqhcAD1htsWG2NpHrrhthEO2qZomLK0FXS+u7NfrkF5aOQ==} + /@babel/plugin-transform-optional-chaining@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-tK+0N9yd4j+x/4hxF3F0e0fu/VdcxU18y5SevtyM/PCFlQvXbR0Zmlo2eBrKtVipGNFzpq56o8WsIIKcJFUCRQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.3) + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-parameters@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-ST7guE8vLV+vI70wmAxuZpIKzVjvFX9Qs8bl5w6tN/6gOypPWUmMQL2p7LJz5E63vEGrDhAiYetniJFyBH1RkA==} + /@babel/plugin-transform-parameters@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-private-methods@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-T9LtDI0BgwXOzyXrvgLTT8DFjCC/XgWLjflczTLXyvxbnSR/gpv0hbmzlHE/kmh9nOvlygbamLKRo6Op4yB6aw==} + /@babel/plugin-transform-private-methods@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.3) - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-private-property-in-object@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-Qu/ypFxCY5NkAnEhCF86Mvg3NSabKsh/TPpBVswEdkGl7+FbsYHy1ziRqJpwGH4thBdQHh8zx+z7vMYmcJ7iaQ==} + /@babel/plugin-transform-private-property-in-object@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-annotate-as-pure': 7.24.6 - '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.3) - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.3) + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-property-literals@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-oARaglxhRsN18OYsnPTpb8TcKQWDYNsPNmTnx5++WOAsUJ0cSC/FZVlIJCKvPbU4yn/UXsS0551CFKJhN0CaMw==} + /@babel/plugin-transform-property-literals@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 + dev: true + + /@babel/plugin-transform-react-display-name@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-H/Snz9PFxKsS1JLI4dJLtnJgCJRoo0AUm3chP6NYr+9En1JMKloheEiLIhlp5MDVznWo+H3AAC1Mc8lmUEpsgg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.7 + dev: true + + /@babel/plugin-transform-react-jsx-development@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-QG9EnzoGn+Qar7rxuW+ZOsbWOt56FvvI93xInqsZDC5fsekx1AlIO4KIJ5M+D0p0SqSH156EpmZyXq630B8OlQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/plugin-transform-react-jsx': 7.24.7(@babel/core@7.24.3) + transitivePeerDependencies: + - supports-color dev: true /@babel/plugin-transform-react-jsx-self@7.24.1(@babel/core@7.24.3): @@ -1590,144 +1730,188 @@ packages: '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-regenerator@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-SMDxO95I8WXRtXhTAc8t/NFQUT7VYbIWwJCJgEli9ml4MhqUMh4S6hxgH6SmAC3eAQNWCDJFxcFeEt9w2sDdXg==} + /@babel/plugin-transform-react-jsx@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-+Dj06GDZEFRYvclU6k4bme55GKBEWUmByM/eoKuqg4zTNQHiApWRhQph5fxQB2wAEFvRzL1tOEj1RJ19wJrhoA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.24.3) + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-react-pure-annotations@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-PLgBVk3fzbmEjBJ/u8kFzOqS9tUeDjiaWud/rRym/yjCo/M9cASPlnrd2ZmmZpQT40fOOrvR8jh+n8jikrOhNA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + dev: true + + /@babel/plugin-transform-regenerator@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.7 regenerator-transform: 0.15.2 dev: true - /@babel/plugin-transform-reserved-words@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-DcrgFXRRlK64dGE0ZFBPD5egM2uM8mgfrvTMOSB2yKzOtjpGegVYkzh3s1zZg1bBck3nkXiaOamJUqK3Syk+4A==} + /@babel/plugin-transform-reserved-words@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-shorthand-properties@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-xnEUvHSMr9eOWS5Al2YPfc32ten7CXdH7Zwyyk7IqITg4nX61oHj+GxpNvl+y5JHjfN3KXE2IV55wAWowBYMVw==} + /@babel/plugin-transform-shorthand-properties@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-spread@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-h/2j7oIUDjS+ULsIrNZ6/TKG97FgmEk1PXryk/HQq6op4XUUUwif2f69fJrzK0wza2zjCS1xhXmouACaWV5uPA==} + /@babel/plugin-transform-spread@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-sticky-regex@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-fN8OcTLfGmYv7FnDrsjodYBo1DhPL3Pze/9mIIE2MGCT1KgADYIOD7rEglpLHZj8PZlC/JFX5WcD+85FLAQusw==} + /@babel/plugin-transform-sticky-regex@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-template-literals@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-BJbEqJIcKwrqUP+KfUIkxz3q8VzXe2R8Wv8TaNgO1cx+nNavxn/2+H8kp9tgFSOL6wYPPEgFvU6IKS4qoGqhmg==} + /@babel/plugin-transform-template-literals@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-typeof-symbol@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-IshCXQ+G9JIFJI7bUpxTE/oA2lgVLAIK8q1KdJNoPXOpvRaNjMySGuvLfBw/Xi2/1lLo953uE8hyYSDW3TSYig==} + /@babel/plugin-transform-typeof-symbol@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-VtR8hDy7YLB7+Pet9IarXjg/zgCMSF+1mNS/EQEiEaUPoFXCVsHG64SIxcaaI2zJgRiv+YmgaQESUfWAdbjzgg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-unicode-escapes@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-bKl3xxcPbkQQo5eX9LjjDpU2xYHeEeNQbOhj0iPvetSzA+Tu9q/o5lujF4Sek60CM6MgYvOS/DJuwGbiEYAnLw==} + /@babel/plugin-transform-typescript@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-iLD3UNkgx2n/HrjBesVbYX6j0yqn/sJktvbtKKgcaLIQ4bTTQ8obAypc1VpyHPD2y4Phh9zHOaAt8e/L14wCpw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-typescript': 7.24.7(@babel/core@7.24.3) + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-unicode-property-regex@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-8EIgImzVUxy15cZiPii9GvLZwsy7Vxc+8meSlR3cXFmBIl5W5Tn9LGBf7CDKkHj4uVfNXCJB8RsVfnmY61iedA==} + /@babel/plugin-transform-unicode-escapes@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.3) - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-unicode-regex@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-pssN6ExsvxaKU638qcWb81RrvvgZom3jDgU/r5xFZ7TONkZGFf4MhI2ltMb8OcQWhHyxgIavEU+hgqtbKOmsPA==} + /@babel/plugin-transform-unicode-property-regex@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.3) - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-unicode-sets-regex@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-quiMsb28oXWIDK0gXLALOJRXLgICLiulqdZGOaPPd0vRT7fQp74NtdADAVu+D8s00C+0Xs0MxVP0VKF/sZEUgw==} + /@babel/plugin-transform-unicode-regex@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.7 + dev: true + + /@babel/plugin-transform-unicode-sets-regex@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-create-regexp-features-plugin': 7.24.6(@babel/core@7.24.3) - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.3) + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/preset-env@7.24.6(@babel/core@7.24.3): - resolution: {integrity: sha512-CrxEAvN7VxfjOG8JNF2Y/eMqMJbZPZ185amwGUBp8D9USK90xQmv7dLdFSa+VbD7fdIqcy/Mfv7WtzG8+/qxKg==} + /@babel/preset-env@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-1YZNsc+y6cTvWlDHidMBsQZrZfEFjRIo/BZCT906PMdzOyXtSLTgqGdrpcuTDCXyd11Am5uQULtDIcCfnTc8fQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.24.6 + '@babel/compat-data': 7.24.7 '@babel/core': 7.24.3 - '@babel/helper-compilation-targets': 7.24.6 - '@babel/helper-plugin-utils': 7.24.6 - '@babel/helper-validator-option': 7.24.6 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.24.6(@babel/core@7.24.3) + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-validator-option': 7.24.7 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.24.7(@babel/core@7.24.3) '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.3) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.3) '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.3) '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.3) '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.3) '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.3) - '@babel/plugin-syntax-import-assertions': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-syntax-import-attributes': 7.24.6(@babel/core@7.24.3) + '@babel/plugin-syntax-import-assertions': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-syntax-import-attributes': 7.24.7(@babel/core@7.24.3) '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.3) '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.3) '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.3) @@ -1739,54 +1923,54 @@ packages: '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.3) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.3) '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.3) - '@babel/plugin-transform-arrow-functions': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-async-generator-functions': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-async-to-generator': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-block-scoped-functions': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-block-scoping': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-class-properties': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-class-static-block': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-classes': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-computed-properties': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-destructuring': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-dotall-regex': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-duplicate-keys': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-dynamic-import': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-exponentiation-operator': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-export-namespace-from': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-for-of': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-function-name': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-json-strings': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-literals': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-logical-assignment-operators': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-member-expression-literals': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-modules-amd': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-modules-commonjs': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-modules-systemjs': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-modules-umd': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-named-capturing-groups-regex': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-new-target': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-nullish-coalescing-operator': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-numeric-separator': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-object-rest-spread': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-object-super': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-optional-catch-binding': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-optional-chaining': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-parameters': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-private-methods': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-private-property-in-object': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-property-literals': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-regenerator': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-reserved-words': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-shorthand-properties': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-spread': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-sticky-regex': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-template-literals': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-typeof-symbol': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-unicode-escapes': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-unicode-property-regex': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-unicode-regex': 7.24.6(@babel/core@7.24.3) - '@babel/plugin-transform-unicode-sets-regex': 7.24.6(@babel/core@7.24.3) + '@babel/plugin-transform-arrow-functions': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-async-generator-functions': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-async-to-generator': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-block-scoped-functions': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-block-scoping': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-class-properties': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-class-static-block': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-classes': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-computed-properties': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-destructuring': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-dotall-regex': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-duplicate-keys': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-dynamic-import': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-exponentiation-operator': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-export-namespace-from': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-for-of': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-function-name': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-json-strings': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-literals': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-logical-assignment-operators': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-member-expression-literals': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-modules-amd': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-modules-commonjs': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-modules-systemjs': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-modules-umd': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-named-capturing-groups-regex': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-new-target': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-nullish-coalescing-operator': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-numeric-separator': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-object-rest-spread': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-object-super': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-optional-catch-binding': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-optional-chaining': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-private-methods': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-private-property-in-object': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-property-literals': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-regenerator': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-reserved-words': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-shorthand-properties': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-spread': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-sticky-regex': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-template-literals': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-typeof-symbol': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-unicode-escapes': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-unicode-property-regex': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-unicode-regex': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-unicode-sets-regex': 7.24.7(@babel/core@7.24.3) '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.3) babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.24.3) babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.3) @@ -1803,11 +1987,44 @@ packages: '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 dependencies: '@babel/core': 7.24.3 - '@babel/helper-plugin-utils': 7.24.6 + '@babel/helper-plugin-utils': 7.24.7 '@babel/types': 7.24.6 esutils: 2.0.3 dev: true + /@babel/preset-react@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-AAH4lEkpmzFWrGVlHaxJB7RLH21uPQ9+He+eFLWHmF9IuFQVugz8eAsamaW0DXRrTfco5zj1wWtpdcXJUOfsag==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-validator-option': 7.24.7 + '@babel/plugin-transform-react-display-name': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-react-jsx': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-react-jsx-development': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-react-pure-annotations': 7.24.7(@babel/core@7.24.3) + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/preset-typescript@7.24.7(@babel/core@7.24.3): + resolution: {integrity: sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-validator-option': 7.24.7 + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-modules-commonjs': 7.24.7(@babel/core@7.24.3) + '@babel/plugin-transform-typescript': 7.24.7(@babel/core@7.24.3) + transitivePeerDependencies: + - supports-color + dev: true + /@babel/register@7.24.6(@babel/core@7.24.3): resolution: {integrity: sha512-WSuFCc2wCqMeXkz/i3yfAAsxwWflEgbVkZzivgAmXl/MxrXeoYFZOOPllbC8R8WTF7u61wSRQtDVZ1879cdu6w==} engines: {node: '>=6.9.0'} @@ -1852,13 +2069,13 @@ packages: '@babel/parser': 7.24.1 '@babel/types': 7.24.0 - /@babel/template@7.24.6: - resolution: {integrity: sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw==} + /@babel/template@7.24.7: + resolution: {integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.24.6 - '@babel/parser': 7.24.6 - '@babel/types': 7.24.6 + '@babel/code-frame': 7.24.7 + '@babel/parser': 7.24.7 + '@babel/types': 7.24.7 dev: true /@babel/traverse@7.24.1: @@ -1878,6 +2095,24 @@ packages: transitivePeerDependencies: - supports-color + /@babel/traverse@7.24.7: + resolution: {integrity: sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-hoist-variables': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 + '@babel/parser': 7.24.7 + '@babel/types': 7.24.7 + debug: 4.3.4(supports-color@8.1.1) + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/types@7.24.0: resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} engines: {node: '>=6.9.0'} @@ -1891,7 +2126,16 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/helper-string-parser': 7.24.6 - '@babel/helper-validator-identifier': 7.24.6 + '@babel/helper-validator-identifier': 7.24.7 + to-fast-properties: 2.0.0 + dev: true + + /@babel/types@7.24.7: + resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 dev: true @@ -1921,7 +2165,7 @@ packages: '@jridgewell/trace-mapping': 0.3.9 dev: true - /@cypress/code-coverage@3.12.39(@babel/core@7.24.3)(@babel/preset-env@7.24.6)(babel-loader@9.1.3)(cypress@13.7.2)(webpack@5.91.0): + /@cypress/code-coverage@3.12.39(@babel/core@7.24.3)(@babel/preset-env@7.24.7)(babel-loader@9.1.3)(cypress@13.7.2)(webpack@5.91.0): resolution: {integrity: sha512-ja7I/GRmkSAW9e3O7pideWcNUEHao0WT6sRyXQEURoxkJUASJssJ7Kb/bd3eMYmkUCiD5CRFqWR5BGF4mWVaUw==} peerDependencies: '@babel/core': ^7.0.1 @@ -1931,8 +2175,8 @@ packages: webpack: ^4 || ^5 dependencies: '@babel/core': 7.24.3 - '@babel/preset-env': 7.24.6(@babel/core@7.24.3) - '@cypress/webpack-preprocessor': 6.0.1(@babel/core@7.24.3)(@babel/preset-env@7.24.6)(babel-loader@9.1.3)(webpack@5.91.0) + '@babel/preset-env': 7.24.7(@babel/core@7.24.3) + '@cypress/webpack-preprocessor': 6.0.1(@babel/core@7.24.3)(@babel/preset-env@7.24.7)(babel-loader@9.1.3)(webpack@5.91.0) babel-loader: 9.1.3(@babel/core@7.24.3)(webpack@5.91.0) chalk: 4.1.2 cypress: 13.7.2 @@ -1972,7 +2216,7 @@ packages: uuid: 8.3.2 dev: true - /@cypress/webpack-preprocessor@6.0.1(@babel/core@7.24.3)(@babel/preset-env@7.24.6)(babel-loader@9.1.3)(webpack@5.91.0): + /@cypress/webpack-preprocessor@6.0.1(@babel/core@7.24.3)(@babel/preset-env@7.24.7)(babel-loader@9.1.3)(webpack@5.91.0): resolution: {integrity: sha512-WVNeFVSnFKxE3WZNRIriduTgqJRpevaiJIPlfqYTTzfXRD7X1Pv4woDE+G4caPV9bJqVKmVFiwzrXMRNeJxpxA==} peerDependencies: '@babel/core': ^7.0.1 @@ -1981,7 +2225,7 @@ packages: webpack: ^4 || ^5 dependencies: '@babel/core': 7.24.3 - '@babel/preset-env': 7.24.6(@babel/core@7.24.3) + '@babel/preset-env': 7.24.7(@babel/core@7.24.3) babel-loader: 9.1.3(@babel/core@7.24.3)(webpack@5.91.0) bluebird: 3.7.1 debug: 4.3.4(supports-color@8.1.1) @@ -3689,6 +3933,43 @@ packages: '@tauri-apps/cli-win32-x64-msvc': 1.5.11 dev: true + /@testing-library/dom@10.1.0: + resolution: {integrity: sha512-wdsYKy5zupPyLCW2Je5DLHSxSfbIp6h80WoHOQc+RPtmPGA52O9x5MJEkv92Sjonpq+poOAtUKhh1kBGAXBrNA==} + engines: {node: '>=18'} + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/runtime': 7.24.6 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + chalk: 4.1.2 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + pretty-format: 27.5.1 + dev: true + + /@testing-library/react@16.0.0(@testing-library/dom@10.1.0)(@types/react-dom@18.2.22)(@types/react@18.2.66)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-guuxUKRWQ+FgNX0h0NS0FIq3Q3uLtWVpBzcLOggmfMoUpgBnzBzvLLd4fbm6yS8ydJd94cIfY4yP9qUQjM2KwQ==} + engines: {node: '>=18'} + peerDependencies: + '@testing-library/dom': ^10.0.0 + '@types/react': ^18.0.0 + '@types/react-dom': ^18.0.0 + react: ^18.0.0 + react-dom: ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.6 + '@testing-library/dom': 10.1.0 + '@types/react': 18.2.66 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: true + /@tootallnate/once@2.0.0: resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} @@ -3715,6 +3996,10 @@ packages: resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} dev: true + /@types/aria-query@5.0.4: + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + dev: true + /@types/babel__core@7.20.5: resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} dependencies: @@ -4494,6 +4779,12 @@ packages: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} dev: true + /aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + dependencies: + dequal: 2.0.3 + dev: true + /array-buffer-byte-length@1.0.1: resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} engines: {node: '>= 0.4'} @@ -4717,7 +5008,7 @@ packages: resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} engines: {node: '>=10', npm: '>=6'} dependencies: - '@babel/runtime': 7.24.1 + '@babel/runtime': 7.24.6 cosmiconfig: 7.1.0 resolve: 1.22.8 dev: false @@ -4727,7 +5018,7 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/compat-data': 7.24.6 + '@babel/compat-data': 7.24.7 '@babel/core': 7.24.3 '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.3) semver: 6.3.1 @@ -5554,7 +5845,6 @@ packages: /dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - dev: false /detect-newline@3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} @@ -5613,6 +5903,10 @@ packages: esutils: 2.0.3 dev: true + /dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + dev: true + /dom-css@2.1.0: resolution: {integrity: sha512-w9kU7FAbaSh3QKijL6n59ofAhkkmMJ31GclJIz/vyQdjogfyxcB6Zf8CZyibOERI5o0Hxz30VmJS7+7r5fEj2Q==} dependencies: @@ -7937,6 +8231,11 @@ packages: engines: {node: '>=12'} dev: false + /lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + dev: true + /magic-string@0.30.8: resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==} engines: {node: '>=12'} @@ -8695,6 +8994,15 @@ packages: engines: {node: '>=6'} dev: true + /pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + dev: true + /pretty-format@29.7.0: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -8990,7 +9298,7 @@ packages: peerDependencies: react: ^16.3.0 dependencies: - '@babel/runtime': 7.24.1 + '@babel/runtime': 7.24.6 prop-types: 15.8.1 react: 18.2.0 warning: 4.0.3 @@ -9038,7 +9346,6 @@ packages: /react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - dev: false /react-is@18.2.0: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} diff --git a/frontend/appflowy_web_app/scripts/merge-coverage.cjs b/frontend/appflowy_web_app/scripts/merge-coverage.cjs deleted file mode 100644 index f059048a0f..0000000000 --- a/frontend/appflowy_web_app/scripts/merge-coverage.cjs +++ /dev/null @@ -1,31 +0,0 @@ -const { execSync } = require('child_process'); -const fs = require('fs'); -const path = require('path'); -const jestCoverageFile = path.join(__dirname, '../coverage/jest/coverage-final.json'); -const cypressCoverageFile = path.join(__dirname, '../coverage/cypress/coverage-final.json'); -// const cypressComponentCoverageFile = path.join(__dirname, '../coverage/cypress-component/coverage-final.json'); -const nycOutputDir = path.join(__dirname, '../coverage/.nyc_output'); -// Ensure .nyc_output directory exists -if (!fs.existsSync(nycOutputDir)) { - fs.mkdirSync(nycOutputDir, { recursive: true }); -} -// Copy Jest coverage file -fs.copyFileSync(jestCoverageFile, path.join(nycOutputDir, 'jest-coverage.json')); -// Copy Cypress E2E coverage file -fs.copyFileSync(cypressCoverageFile, path.join(nycOutputDir, 'cypress-coverage.json')); -// Copy Cypress Component coverage file -// fs.copyFileSync(cypressComponentCoverageFile, path.join(nycOutputDir, 'cypress-component-coverage.json')); -// Merge coverage files -execSync('nyc merge ./coverage/.nyc_output ./coverage/merged/coverage-final.json', { stdio: 'inherit' }); -// Generate final merged report -execSync('nyc report --reporter=html --reporter=text-summary --report-dir=coverage/merged --temp-dir=coverage/.nyc_output', { stdio: 'inherit' }); -console.log(`Merged coverage report written to coverage/merged`); - -const GITHUB_STEP_SUMMARY = process.env.GITHUB_STEP_SUMMARY; - -if (GITHUB_STEP_SUMMARY) { - const coverageSummary = execSync('nyc report --reporter=html --reporter=text-summary --report-dir=coverage/merged --temp-dir=coverage/.nyc_output').toString(); - - fs.appendFileSync(GITHUB_STEP_SUMMARY, `### Coverage Report\n\`\`\`\n${coverageSummary}\n\`\`\`\n`); -} - diff --git a/frontend/appflowy_web_app/src/application/collab.type.ts b/frontend/appflowy_web_app/src/application/collab.type.ts index 4f61246aab..567be3b4ed 100644 --- a/frontend/appflowy_web_app/src/application/collab.type.ts +++ b/frontend/appflowy_web_app/src/application/collab.type.ts @@ -369,7 +369,19 @@ export interface YDocument extends Y.Map { } export interface YBlocks extends Y.Map { - get(key: BlockId): Y.Map; + get(key: BlockId): YBlock; +} + +export interface YBlock extends Y.Map { + get(key: YjsEditorKey.block_id | YjsEditorKey.block_parent): BlockId; + + get(key: YjsEditorKey.block_type): BlockType; + + get(key: YjsEditorKey.block_data): string; + + get(key: YjsEditorKey.block_children): ChildrenId; + + get(key: YjsEditorKey.block_external_id): ExternalId; } export interface YMeta extends Y.Map { diff --git a/frontend/appflowy_web_app/src/application/database-yjs/__tests__/filter.test.ts b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/filter.test.ts index 5b2ed3d37e..979105a982 100644 --- a/frontend/appflowy_web_app/src/application/database-yjs/__tests__/filter.test.ts +++ b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/filter.test.ts @@ -27,6 +27,7 @@ import { filterBy, } from '../filter'; import { expect } from '@jest/globals'; +import * as Y from 'yjs'; describe('Text filter check', () => { const text = 'Hello, world!'; @@ -540,6 +541,15 @@ describe('Database filterBy', () => { expect(result).toBe('1,2,3,4,5,6,7,8,9,10'); }); + it('should return all rows for empty rowMap', () => { + const { filters, fields } = withTestingData(); + const rowMap = new Y.Map() as Y.Map; + const result = filterBy(rows, filters, fields, rowMap) + .map((row) => row.id) + .join(','); + expect(result).toBe('1,2,3,4,5,6,7,8,9,10'); + }); + it('should return rows that match text filter', () => { const { filters, fields, rowMap } = withTestingData(); const filter = withRichTextFilter(); diff --git a/frontend/appflowy_web_app/src/application/database-yjs/__tests__/fixtures/sorts.json b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/fixtures/sorts.json index e07c1647ce..11ae36cf60 100644 --- a/frontend/appflowy_web_app/src/application/database-yjs/__tests__/fixtures/sorts.json +++ b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/fixtures/sorts.json @@ -78,5 +78,25 @@ "field_id": "url_field", "condition": "desc", "id": "sort_desc_url_field" + }, + "sort_asc_created_at": { + "field_id": "created_at_field", + "condition": "asc", + "id": "sort_asc_created_at" + }, + "sort_desc_created_at": { + "field_id": "created_at_field", + "condition": "desc", + "id": "sort_desc_created_at" + }, + "sort_asc_updated_at": { + "field_id": "last_modified_field", + "condition": "asc", + "id": "sort_asc_updated_at" + }, + "sort_desc_updated_at": { + "field_id": "last_modified_field", + "condition": "desc", + "id": "sort_desc_updated_at" } } \ No newline at end of file diff --git a/frontend/appflowy_web_app/src/application/database-yjs/__tests__/group.test.ts b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/group.test.ts index 518918138b..adbe80aaa3 100644 --- a/frontend/appflowy_web_app/src/application/database-yjs/__tests__/group.test.ts +++ b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/group.test.ts @@ -1,8 +1,17 @@ -import { Row } from '@/application/database-yjs'; +import { FieldType, Row } from '@/application/database-yjs'; import { withTestingData } from '@/application/database-yjs/__tests__/withTestingData'; import { withTestingRows } from '@/application/database-yjs/__tests__/withTestingRows'; import { expect } from '@jest/globals'; import { groupByField } from '../group'; +import * as Y from 'yjs'; +import { + YDatabaseField, + YDatabaseFieldTypeOption, + YjsDatabaseKey, + YjsEditorKey, + YMapFieldTypeOption, +} from '@/application/collab.type'; +import { YjsEditor } from '@/application/slate-yjs'; describe('Database group', () => { let rows: Row[]; @@ -95,4 +104,69 @@ describe('Database group', () => { ]); expect(result).toEqual(expectRes); }); + + it('should not group if no options', () => { + const { fields, rowMap } = withTestingData(); + const field = new Y.Map() as YDatabaseField; + const typeOption = new Y.Map() as YDatabaseFieldTypeOption; + const now = Date.now().toString(); + + field.set(YjsDatabaseKey.name, 'Single Select Field'); + field.set(YjsDatabaseKey.id, 'another_single_select_field'); + field.set(YjsDatabaseKey.type, String(FieldType.SingleSelect)); + field.set(YjsDatabaseKey.last_modified, now.valueOf()); + field.set(YjsDatabaseKey.type_option, typeOption); + fields.set('another_single_select_field', field); + expect(groupByField(rows, rowMap, field)).toBeUndefined(); + + const selectTypeOption = new Y.Map() as YMapFieldTypeOption; + + typeOption.set(String(FieldType.SingleSelect), selectTypeOption); + selectTypeOption.set(YjsDatabaseKey.content, JSON.stringify({ disable_color: false, options: [] })); + const expectRes = new Map([['another_single_select_field', rows]]); + expect(groupByField(rows, rowMap, field)).toEqual(expectRes); + }); + + it('should handle empty selected ids', () => { + const { fields, rowMap } = withTestingData(); + const cell = rowMap + .get('1') + ?.getMap(YjsEditorKey.data_section) + ?.get(YjsEditorKey.database_row) + ?.get(YjsDatabaseKey.cells) + ?.get('single_select_field'); + cell?.set(YjsDatabaseKey.data, null); + + const field = fields.get('single_select_field'); + const result = groupByField(rows, rowMap, field); + expect(result).toEqual( + new Map([ + ['single_select_field', [{ id: '1', height: 37 }]], + [ + '2', + [ + { id: '2', height: 37 }, + { id: '5', height: 37 }, + { id: '8', height: 37 }, + ], + ], + [ + '3', + [ + { id: '3', height: 37 }, + { id: '6', height: 37 }, + { id: '9', height: 37 }, + ], + ], + [ + '1', + [ + { id: '4', height: 37 }, + { id: '7', height: 37 }, + { id: '10', height: 37 }, + ], + ], + ]) + ); + }); }); diff --git a/frontend/appflowy_web_app/src/application/database-yjs/__tests__/parse.test.ts b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/parse.test.ts new file mode 100644 index 0000000000..190a4846a1 --- /dev/null +++ b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/parse.test.ts @@ -0,0 +1,72 @@ +import { parseYDatabaseCellToCell } from '@/application/database-yjs/cell.parse'; +import { expect } from '@jest/globals'; +import { withTestingCheckboxCell, withTestingDateCell } from '@/application/database-yjs/__tests__/withTestingCell'; +import * as Y from 'yjs'; +import { + FieldType, + parseSelectOptionTypeOptions, + parseRelationTypeOption, + parseNumberTypeOptions, +} from '@/application/database-yjs'; +import { YDatabaseField, YDatabaseFieldTypeOption, YjsDatabaseKey } from '@/application/collab.type'; +import { withNumberTestingField, withRelationTestingField } from '@/application/database-yjs/__tests__/withTestingField'; + +describe('parseYDatabaseCellToCell', () => { + it('should parse a DateTime cell', () => { + const doc = new Y.Doc(); + const cell = withTestingDateCell(); + doc.getMap('cells').set('date_field', cell); + const parsedCell = parseYDatabaseCellToCell(cell); + expect(parsedCell.data).not.toBe(undefined); + expect(parsedCell.createdAt).not.toBe(undefined); + expect(parsedCell.lastModified).not.toBe(undefined); + expect(parsedCell.fieldType).toBe(Number(FieldType.DateTime)); + }); + it('should parse a Checkbox cell', () => { + const doc = new Y.Doc(); + const cell = withTestingCheckboxCell(); + doc.getMap('cells').set('checkbox_field', cell); + const parsedCell = parseYDatabaseCellToCell(cell); + expect(parsedCell.data).toBe(true); + expect(parsedCell.createdAt).not.toBe(undefined); + expect(parsedCell.lastModified).not.toBe(undefined); + expect(parsedCell.fieldType).toBe(Number(FieldType.Checkbox)); + }); +}); + +describe('Select option field parse', () => { + it('should parse select option type options', () => { + const doc = new Y.Doc(); + const field = new Y.Map() as YDatabaseField; + const typeOption = new Y.Map() as YDatabaseFieldTypeOption; + const now = Date.now().toString(); + + field.set(YjsDatabaseKey.name, 'Single Select Field'); + field.set(YjsDatabaseKey.id, 'single_select_field'); + field.set(YjsDatabaseKey.type, String(FieldType.SingleSelect)); + field.set(YjsDatabaseKey.last_modified, now.valueOf()); + field.set(YjsDatabaseKey.type_option, typeOption); + doc.getMap('fields').set('single_select_field', field); + expect(parseSelectOptionTypeOptions(field)).toEqual(null); + }); +}); + +describe('number field parse', () => { + it('should parse number field', () => { + const doc = new Y.Doc(); + const field = withNumberTestingField(); + doc.getMap('fields').set('number_field', field); + expect(parseNumberTypeOptions(field)).toEqual({ + format: 0, + }); + }); +}); + +describe('relation field parse', () => { + it('should parse relation field', () => { + const doc = new Y.Doc(); + const field = withRelationTestingField(); + doc.getMap('fields').set('relation_field', field); + expect(parseRelationTypeOption(field)).toEqual(undefined); + }); +}); diff --git a/frontend/appflowy_web_app/src/application/database-yjs/__tests__/selector.test.tsx b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/selector.test.tsx new file mode 100644 index 0000000000..23c8bc8221 --- /dev/null +++ b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/selector.test.tsx @@ -0,0 +1,283 @@ +import { renderHook } from '@testing-library/react'; +import { + useCalendarEventsSelector, + useCellSelector, + useFieldSelector, + useFieldsSelector, + useFilterSelector, + useFiltersSelector, + useGroup, + useGroupsSelector, + usePrimaryFieldId, + useRowDataSelector, + useRowDocMapSelector, + useRowMetaSelector, + useRowOrdersSelector, + useRowsByGroup, + useSortSelector, + useSortsSelector, +} from '../selector'; +import { useDatabaseViewId } from '../context'; +import { IdProvider } from '@/components/_shared/context-provider/IdProvider'; +import { DatabaseContextProvider } from '@/components/database/DatabaseContext'; +import { withTestingDatabase } from '@/application/database-yjs/__tests__/withTestingData'; +import { expect } from '@jest/globals'; +import { YDoc, YjsDatabaseKey, YjsEditorKey, YSharedRoot } from '@/application/collab.type'; +import * as Y from 'yjs'; +import { withNumberTestingField, withTestingFields } from '@/application/database-yjs/__tests__/withTestingField'; +import { withTestingRows } from '@/application/database-yjs/__tests__/withTestingRows'; + +const wrapperCreator = + (viewId: string, doc: YDoc, rowDocMap: Y.Map) => + ({ children }: { children: React.ReactNode }) => { + return ( + + + {children} + + + ); + }; + +describe('Database selector', () => { + let wrapper: ({ children }: { children: React.ReactNode }) => JSX.Element; + let rowDocMap: Y.Map; + let doc: YDoc; + + beforeEach(() => { + const data = withTestingDatabase('1'); + + doc = data.doc; + rowDocMap = data.rowDocMap; + wrapper = wrapperCreator('1', doc, rowDocMap); + }); + + it('should select a field', () => { + const { result } = renderHook(() => useFieldSelector('number_field'), { wrapper }); + + const tempDoc = new Y.Doc(); + const field = withNumberTestingField(); + + tempDoc.getMap().set('number_field', field); + + expect(result.current.field?.toJSON()).toEqual(field.toJSON()); + }); + + it('should select all fields', () => { + const { result } = renderHook(() => useFieldsSelector(), { wrapper }); + + expect(result.current.map((item) => item.fieldId)).toEqual(Array.from(withTestingFields().keys())); + }); + + it('should select all filters', () => { + const { result } = renderHook(() => useFiltersSelector(), { wrapper }); + + expect(result.current).toEqual(['filter_multi_select_field']); + }); + + it('should select a filter', () => { + const { result } = renderHook(() => useFilterSelector('filter_multi_select_field'), { wrapper }); + + expect(result.current).toEqual({ + content: '1,3', + condition: 2, + fieldId: 'multi_select_field', + id: 'filter_multi_select_field', + filterType: NaN, + optionIds: ['1', '3'], + }); + }); + + it('should select all sorts', () => { + const { result } = renderHook(() => useSortsSelector(), { wrapper }); + + expect(result.current).toEqual(['sort_asc_text_field']); + }); + + it('should select a sort', () => { + const { result } = renderHook(() => useSortSelector('sort_asc_text_field'), { wrapper }); + + expect(result.current).toEqual({ + fieldId: 'text_field', + id: 'sort_asc_text_field', + condition: 0, + }); + }); + + it('should select all groups', () => { + const { result } = renderHook(() => useGroupsSelector(), { wrapper }); + + expect(result.current).toEqual(['g:single_select_field']); + }); + + it('should select a group', () => { + const { result } = renderHook(() => useGroup('g:single_select_field'), { wrapper }); + + expect(result.current).toEqual({ + fieldId: 'single_select_field', + columns: [ + { + id: '1', + visible: true, + }, + { + id: 'single_select_field', + visible: true, + }, + ], + }); + }); + + it('should select rows by group', () => { + const { result } = renderHook(() => useRowsByGroup('g:single_select_field'), { wrapper }); + + const { fieldId, columns, notFound, groupResult } = result.current; + + expect(fieldId).toEqual('single_select_field'); + expect(columns).toEqual([ + { + id: '1', + visible: true, + }, + { + id: 'single_select_field', + visible: true, + }, + ]); + expect(notFound).toBeFalsy(); + + expect(groupResult).toEqual( + new Map([ + [ + '1', + [ + { id: '1', height: 37 }, + { id: '7', height: 37 }, + ], + ], + [ + '2', + [ + { id: '2', height: 37 }, + { id: '8', height: 37 }, + { id: '5', height: 37 }, + ], + ], + [ + '3', + [ + { id: '9', height: 37 }, + { id: '3', height: 37 }, + { id: '6', height: 37 }, + ], + ], + ]) + ); + }); + + it('should select all row orders', () => { + const { result } = renderHook(() => useRowOrdersSelector(), { wrapper }); + + expect(result.current?.map((item) => item.id).join(',')).toEqual('9,2,3,1,6,8,5,7'); + }); + + it('should select all row doc map', () => { + const { result } = renderHook(() => useRowDocMapSelector(), { wrapper }); + + expect(result.current.rows).toEqual(rowDocMap); + }); + + it('should select a row data', () => { + const rows = withTestingRows(); + const { result } = renderHook(() => useRowDataSelector(rows[0].id), { wrapper }); + + expect(result.current.row.toJSON()).toEqual( + rowDocMap.get(rows[0].id)?.getMap(YjsEditorKey.data_section)?.get(YjsEditorKey.database_row)?.toJSON() + ); + }); + + it('should select a cell', () => { + const rows = withTestingRows(); + const { result } = renderHook( + () => + useCellSelector({ + rowId: rows[0].id, + fieldId: 'number_field', + }), + { wrapper } + ); + + expect(result.current).toEqual({ + createdAt: NaN, + data: 123, + fieldType: 1, + lastModified: NaN, + }); + }); + + it('should select a primary field id', () => { + const { result } = renderHook(() => usePrimaryFieldId(), { wrapper }); + + expect(result.current).toEqual('text_field'); + }); + + it('should select a row meta', () => { + const rows = withTestingRows(); + const { result } = renderHook(() => useRowMetaSelector(rows[0].id), { wrapper }); + + expect(result.current?.documentId).not.toBeNull(); + }); + + it('should select all calendar events', () => { + const { result } = renderHook(() => useCalendarEventsSelector(), { wrapper }); + + expect(result.current.events.length).toEqual(8); + expect(result.current.emptyEvents.length).toEqual(0); + }); + + it('should select view id', () => { + const { result } = renderHook(() => useDatabaseViewId(), { wrapper }); + + expect(result.current).toEqual('1'); + }); + + it('should select all rows if filter is not found', () => { + const view = (doc.get(YjsEditorKey.data_section) as YSharedRoot) + .get(YjsEditorKey.database) + .get(YjsDatabaseKey.views) + .get('1'); + + view.set(YjsDatabaseKey.filters, new Y.Array()); + + const { result } = renderHook(() => useRowOrdersSelector(), { wrapper }); + + expect(result.current?.map((item) => item.id).join(',')).toEqual('9,2,3,4,1,6,10,8,5,7'); + }); + + it('should select original row orders if sorts is not found', () => { + const view = (doc.get(YjsEditorKey.data_section) as YSharedRoot) + .get(YjsEditorKey.database) + .get(YjsDatabaseKey.views) + .get('1'); + + view.set(YjsDatabaseKey.sorts, new Y.Array()); + + const { result } = renderHook(() => useRowOrdersSelector(), { wrapper }); + + expect(result.current?.map((item) => item.id).join(',')).toEqual('1,2,3,5,6,7,8,9'); + }); + + it('should select all rows if filters and sorts are not found', () => { + const view = (doc.get(YjsEditorKey.data_section) as YSharedRoot) + .get(YjsEditorKey.database) + .get(YjsDatabaseKey.views) + .get('1'); + + view.set(YjsDatabaseKey.filters, new Y.Array()); + view.set(YjsDatabaseKey.sorts, new Y.Array()); + + const { result } = renderHook(() => useRowOrdersSelector(), { wrapper }); + + expect(result.current?.map((item) => item.id).join(',')).toEqual('1,2,3,4,5,6,7,8,9,10'); + }); +}); diff --git a/frontend/appflowy_web_app/src/application/database-yjs/__tests__/sort.test.ts b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/sort.test.ts index 39ffa2abe5..e790b05fdd 100644 --- a/frontend/appflowy_web_app/src/application/database-yjs/__tests__/sort.test.ts +++ b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/sort.test.ts @@ -4,7 +4,9 @@ import { withTestingRows } from '@/application/database-yjs/__tests__/withTestin import { withCheckboxSort, withChecklistSort, + withCreatedAtSort, withDateTimeSort, + withLastModifiedSort, withMultiSelectOptionSort, withNumberSort, withRichTextSort, @@ -19,10 +21,12 @@ import { withSelectOptionTestingField, withURLTestingField, withChecklistTestingField, + withRelationTestingField, } from './withTestingField'; import { sortBy, parseCellDataForSort } from '../sort'; import * as Y from 'yjs'; import { expect } from '@jest/globals'; +import { YjsDatabaseKey, YjsEditorKey } from '@/application/collab.type'; describe('parseCellDataForSort', () => { it('should parse data correctly based on field type', () => { @@ -127,6 +131,17 @@ describe('parseCellDataForSort', () => { expect(result).toBe(0); }); + + it('should return empty string for Relation field', () => { + const doc = new Y.Doc(); + const field = withRelationTestingField(); + doc.getMap().set('field', field); + const data = ''; + + const result = parseCellDataForSort(field, data); + + expect(result).toBe(''); + }); }); describe('Database sortBy', () => { @@ -136,6 +151,53 @@ describe('Database sortBy', () => { rows = withTestingRows(); }); + it('should not sort rows if no sort is provided', () => { + const { sorts, fields, rowMap } = withTestingData(); + + const sortedRows = sortBy(rows, sorts, fields, rowMap) + .map((row) => row.id) + .join(','); + expect(sortedRows).toBe('1,2,3,4,5,6,7,8,9,10'); + }); + + it('should not sort rows if no rows are provided', () => { + const { sorts, fields } = withTestingData(); + const rowMap = new Y.Map() as Y.Map; + const sortedRows = sortBy(rows, sorts, fields, rowMap) + .map((row) => row.id) + .join(','); + expect(sortedRows).toBe('1,2,3,4,5,6,7,8,9,10'); + }); + + it('should return default data if rowMeta is not found', () => { + const { sorts, fields, rowMap } = withTestingData(); + const sort = withNumberSort(); + sorts.push([sort]); + rowMap.delete('1'); + + const sortedRows = sortBy(rows, sorts, fields, rowMap) + .map((row) => row.id) + .join(','); + expect(sortedRows).toBe('1,2,3,4,5,6,7,8,9,10'); + }); + + it('should return default data if cell is not found', () => { + const { sorts, fields, rowMap } = withTestingData(); + const sort = withNumberSort(); + sorts.push([sort]); + const rowDoc = rowMap.get('1'); + rowDoc + ?.getMap(YjsEditorKey.data_section) + .get(YjsEditorKey.database_row) + ?.get(YjsDatabaseKey.cells) + .delete('number_field'); + + const sortedRows = sortBy(rows, sorts, fields, rowMap) + .map((row) => row.id) + .join(','); + expect(sortedRows).toBe('1,2,3,4,5,6,7,8,9,10'); + }); + it('should sort by number field in ascending order', () => { const { sorts, fields, rowMap } = withTestingData(); const sort = withNumberSort(); @@ -311,4 +373,25 @@ describe('Database sortBy', () => { .join(','); expect(sortedRows).toBe('3,9,1,2,5,6,7,8,4,10'); }); + + it('should sort by CreatedAt field in ascending order', () => { + const { sorts, fields, rowMap } = withTestingData(); + const sort = withCreatedAtSort(); + sorts.push([sort]); + + const sortedRows = sortBy(rows, sorts, fields, rowMap) + .map((row) => row.id) + .join(','); + expect(sortedRows).toBe('1,2,3,4,5,6,7,8,9,10'); + }); + + it('should sort by LastEditedTime field', () => { + const { sorts, fields, rowMap } = withTestingData(); + const sort = withLastModifiedSort(); + sorts.push([sort]); + const sortedRows = sortBy(rows, sorts, fields, rowMap) + .map((row) => row.id) + .join(','); + expect(sortedRows).toBe('1,2,3,4,5,6,7,8,9,10'); + }); }); diff --git a/frontend/appflowy_web_app/src/application/database-yjs/__tests__/withTestingCell.ts b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/withTestingCell.ts new file mode 100644 index 0000000000..4021903b36 --- /dev/null +++ b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/withTestingCell.ts @@ -0,0 +1,43 @@ +import * as Y from 'yjs'; +import { YDatabaseCell, YjsDatabaseKey } from '@/application/collab.type'; +import { FieldType } from '@/application/database-yjs'; + +export function withTestingDateCell() { + const cell = new Y.Map() as YDatabaseCell; + + cell.set(YjsDatabaseKey.id, 'date_field'); + cell.set(YjsDatabaseKey.data, Date.now()); + cell.set(YjsDatabaseKey.field_type, Number(FieldType.DateTime)); + cell.set(YjsDatabaseKey.created_at, Date.now()); + cell.set(YjsDatabaseKey.last_modified, Date.now()); + cell.set(YjsDatabaseKey.end_timestamp, Date.now() + 1000); + cell.set(YjsDatabaseKey.include_time, true); + cell.set(YjsDatabaseKey.is_range, true); + cell.set(YjsDatabaseKey.reminder_id, 'reminderId'); + + return cell; +} + +export function withTestingCheckboxCell() { + const cell = new Y.Map() as YDatabaseCell; + + cell.set(YjsDatabaseKey.id, 'checkbox_field'); + cell.set(YjsDatabaseKey.data, 'Yes'); + cell.set(YjsDatabaseKey.field_type, Number(FieldType.Checkbox)); + cell.set(YjsDatabaseKey.created_at, Date.now()); + cell.set(YjsDatabaseKey.last_modified, Date.now()); + + return cell; +} + +export function withTestingSingleOptionCell() { + const cell = new Y.Map() as YDatabaseCell; + + cell.set(YjsDatabaseKey.id, 'single_select_field'); + cell.set(YjsDatabaseKey.data, 'optionId'); + cell.set(YjsDatabaseKey.field_type, Number(FieldType.SingleSelect)); + cell.set(YjsDatabaseKey.created_at, Date.now()); + cell.set(YjsDatabaseKey.last_modified, Date.now()); + + return cell; +} diff --git a/frontend/appflowy_web_app/src/application/database-yjs/__tests__/withTestingData.ts b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/withTestingData.ts index 40633223be..3ff4a32b12 100644 --- a/frontend/appflowy_web_app/src/application/database-yjs/__tests__/withTestingData.ts +++ b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/withTestingData.ts @@ -1,7 +1,29 @@ -import { YDatabaseFields, YDatabaseFilters, YDatabaseSorts } from '@/application/collab.type'; +import { + YDatabase, + YDatabaseField, + YDatabaseFields, + YDatabaseFilters, + YDatabaseGroup, + YDatabaseGroupColumn, + YDatabaseGroupColumns, + YDatabaseLayoutSettings, + YDatabaseSorts, + YDatabaseView, + YDatabaseViews, + YDoc, + YjsDatabaseKey, + YjsEditorKey, +} from '@/application/collab.type'; import { withTestingFields } from '@/application/database-yjs/__tests__/withTestingField'; -import { withTestingRowDataMap } from '@/application/database-yjs/__tests__/withTestingRows'; +import { + withTestingRowData, + withTestingRowDataMap, + withTestingRows, +} from '@/application/database-yjs/__tests__/withTestingRows'; import * as Y from 'yjs'; +import { withMultiSelectOptionFilter } from '@/application/database-yjs/__tests__/withTestingFilters'; +import { withRichTextSort } from '@/application/database-yjs/__tests__/withTestingSorts'; +import { metaIdFromRowId, RowMetaKey } from '@/application/database-yjs'; export function withTestingData() { const doc = new Y.Doc(); @@ -27,5 +49,133 @@ export function withTestingData() { rowMap, sorts, filters, + doc, + }; +} + +export function withTestingDatabase(viewId: string) { + const doc = new Y.Doc(); + const sharedRoot = doc.getMap(YjsEditorKey.data_section); + const database = new Y.Map() as YDatabase; + + sharedRoot.set(YjsEditorKey.database, database); + + const fields = withTestingFields() as YDatabaseFields; + + database.set(YjsDatabaseKey.fields, fields); + database.set(YjsDatabaseKey.id, viewId); + + const metas = new Y.Map(); + + database.set(YjsDatabaseKey.metas, metas); + metas.set(YjsDatabaseKey.iid, viewId); + + const views = new Y.Map() as YDatabaseViews; + + database.set(YjsDatabaseKey.views, views); + + const view = new Y.Map() as YDatabaseView; + + views.set('1', view); + view.set(YjsDatabaseKey.id, viewId); + view.set(YjsDatabaseKey.layout, 0); + view.set(YjsDatabaseKey.name, 'View 1'); + view.set(YjsDatabaseKey.database_id, viewId); + + const layoutSetting = new Y.Map() as YDatabaseLayoutSettings; + + const calendarSetting = new Y.Map(); + + calendarSetting.set(YjsDatabaseKey.field_id, 'date_field'); + layoutSetting.set('2', calendarSetting); + + view.set(YjsDatabaseKey.layout_settings, layoutSetting); + + const filters = new Y.Array() as YDatabaseFilters; + const filter = withMultiSelectOptionFilter(); + + filters.push([filter]); + + const sorts = new Y.Array() as YDatabaseSorts; + const sort = withRichTextSort(); + + sorts.push([sort]); + + const groups = new Y.Array(); + const group = new Y.Map() as YDatabaseGroup; + + groups.push([group]); + group.set(YjsDatabaseKey.id, 'g:single_select_field'); + group.set(YjsDatabaseKey.field_id, 'single_select_field'); + group.set(YjsDatabaseKey.type, '3'); + group.set(YjsDatabaseKey.content, ''); + + const groupColumns = new Y.Array() as YDatabaseGroupColumns; + + group.set(YjsDatabaseKey.groups, groupColumns); + + const column1 = new Y.Map() as YDatabaseGroupColumn; + const column2 = new Y.Map() as YDatabaseGroupColumn; + + column1.set(YjsDatabaseKey.id, '1'); + column1.set(YjsDatabaseKey.visible, true); + column2.set(YjsDatabaseKey.id, 'single_select_field'); + column2.set(YjsDatabaseKey.visible, true); + + groupColumns.push([column1]); + groupColumns.push([column2]); + + view.set(YjsDatabaseKey.filters, filters); + view.set(YjsDatabaseKey.sorts, sorts); + view.set(YjsDatabaseKey.groups, groups); + + const fieldSettings = new Y.Map(); + const fieldOrder = new Y.Array(); + const rowOrders = new Y.Array(); + + Array.from(fields).forEach(([fieldId, field]) => { + const setting = new Y.Map(); + + if (fieldId === 'text_field') { + (field as YDatabaseField).set(YjsDatabaseKey.is_primary, true); + } + + fieldOrder.push([fieldId]); + fieldSettings.set(fieldId, setting); + setting.set(YjsDatabaseKey.visibility, 0); + }); + const rows = withTestingRows(); + + rows.forEach(({ id, height }) => { + const row = new Y.Map(); + + row.set(YjsDatabaseKey.id, id); + row.set(YjsDatabaseKey.height, height); + rowOrders.push([row]); + }); + + view.set(YjsDatabaseKey.field_settings, fieldSettings); + view.set(YjsDatabaseKey.field_orders, fieldOrder); + view.set(YjsDatabaseKey.row_orders, rowOrders); + + const rowMapDoc = new Y.Doc(); + + const rowMapFolder = rowMapDoc.getMap(); + + rows.forEach((row, index) => { + const rowDoc = new Y.Doc(); + const rowData = withTestingRowData(row.id, index); + const rowMeta = new Y.Map(); + const parser = metaIdFromRowId('281e76fb-712e-59e2-8370-678bf0788355'); + + rowMeta.set(parser(RowMetaKey.IconId), '😊'); + rowDoc.getMap(YjsEditorKey.data_section).set(YjsEditorKey.meta, rowMeta); + rowDoc.getMap(YjsEditorKey.data_section).set(YjsEditorKey.database_row, rowData); + rowMapFolder.set(row.id, rowDoc); + }); + + return { + rowDocMap: rowMapFolder as Y.Map, + doc: doc as YDoc, }; } diff --git a/frontend/appflowy_web_app/src/application/database-yjs/__tests__/withTestingField.ts b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/withTestingField.ts index 417a3b99a7..869acfe55e 100644 --- a/frontend/appflowy_web_app/src/application/database-yjs/__tests__/withTestingField.ts +++ b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/withTestingField.ts @@ -4,7 +4,8 @@ import { YjsDatabaseKey, YMapFieldTypeOption, } from '@/application/collab.type'; -import { FieldType, SelectOptionColor } from '@/application/database-yjs'; +import { FieldType } from '@/application/database-yjs'; +import { SelectOptionColor } from '@/application/database-yjs/fields/select-option'; import * as Y from 'yjs'; export function withTestingFields() { @@ -39,6 +40,14 @@ export function withTestingFields() { fields.set('checklist_field', checklistField); + const createdAtField = withCreatedAtTestingField(); + + fields.set('created_at_field', createdAtField); + + const lastModifiedField = withLastModifiedTestingField(); + + fields.set('last_modified_field', lastModifiedField); + return fields; } @@ -56,13 +65,31 @@ export function withRichTextTestingField() { export function withNumberTestingField() { const field = new Y.Map() as YDatabaseField; - - const now = Date.now().toString(); - + field.set(YjsDatabaseKey.name, 'Number Field'); field.set(YjsDatabaseKey.id, 'number_field'); field.set(YjsDatabaseKey.type, String(FieldType.Number)); + const typeOption = new Y.Map() as YDatabaseFieldTypeOption; + + const numberTypeOption = new Y.Map() as YMapFieldTypeOption; + + typeOption.set(String(FieldType.Number), numberTypeOption); + numberTypeOption.set(YjsDatabaseKey.format, '0'); + field.set(YjsDatabaseKey.type_option, typeOption); + + return field; +} + +export function withRelationTestingField() { + const field = new Y.Map() as YDatabaseField; + const typeOption = new Y.Map() as YDatabaseFieldTypeOption; + const now = Date.now().toString(); + + field.set(YjsDatabaseKey.name, 'Relation Field'); + field.set(YjsDatabaseKey.id, 'relation_field'); + field.set(YjsDatabaseKey.type, String(FieldType.Relation)); field.set(YjsDatabaseKey.last_modified, now.valueOf()); + field.set(YjsDatabaseKey.type_option, typeOption); return field; } @@ -151,3 +178,27 @@ export function withChecklistTestingField() { return field; } + +export function withCreatedAtTestingField() { + const field = new Y.Map() as YDatabaseField; + const now = Date.now().toString(); + + field.set(YjsDatabaseKey.name, 'Created At Field'); + field.set(YjsDatabaseKey.id, 'created_at_field'); + field.set(YjsDatabaseKey.type, String(FieldType.CreatedTime)); + field.set(YjsDatabaseKey.last_modified, now.valueOf()); + + return field; +} + +export function withLastModifiedTestingField() { + const field = new Y.Map() as YDatabaseField; + const now = Date.now().toString(); + + field.set(YjsDatabaseKey.name, 'Last Modified Field'); + field.set(YjsDatabaseKey.id, 'last_modified_field'); + field.set(YjsDatabaseKey.type, String(FieldType.LastEditedTime)); + field.set(YjsDatabaseKey.last_modified, now.valueOf()); + + return field; +} diff --git a/frontend/appflowy_web_app/src/application/database-yjs/__tests__/withTestingRows.ts b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/withTestingRows.ts index fc4c8c4f4c..3ed75b409c 100644 --- a/frontend/appflowy_web_app/src/application/database-yjs/__tests__/withTestingRows.ts +++ b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/withTestingRows.ts @@ -39,6 +39,8 @@ export function withTestingRowData(id: string, index: number) { rowData.set(YjsDatabaseKey.id, id); rowData.set(YjsDatabaseKey.height, 37); + rowData.set(YjsDatabaseKey.last_modified, Date.now() + index * 1000); + rowData.set(YjsDatabaseKey.created_at, Date.now() + index * 1000); const cells = new Y.Map() as YDatabaseCells; diff --git a/frontend/appflowy_web_app/src/application/database-yjs/__tests__/withTestingSorts.ts b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/withTestingSorts.ts index f5c1fd5a16..d97c6f4f71 100644 --- a/frontend/appflowy_web_app/src/application/database-yjs/__tests__/withTestingSorts.ts +++ b/frontend/appflowy_web_app/src/application/database-yjs/__tests__/withTestingSorts.ts @@ -89,3 +89,25 @@ export function withChecklistSort(isAscending: boolean = true) { return sort; } + +export function withCreatedAtSort(isAscending: boolean = true) { + const sort = new Y.Map() as YDatabaseSort; + const sortJSON = isAscending ? sortsJson.sort_asc_created_at : sortsJson.sort_desc_created_at; + + sort.set(YjsDatabaseKey.id, sortJSON.id); + sort.set(YjsDatabaseKey.field_id, sortJSON.field_id); + sort.set(YjsDatabaseKey.condition, sortJSON.condition === 'asc' ? '0' : '1'); + + return sort; +} + +export function withLastModifiedSort(isAscending: boolean = true) { + const sort = new Y.Map() as YDatabaseSort; + const sortJSON = isAscending ? sortsJson.sort_asc_updated_at : sortsJson.sort_desc_updated_at; + + sort.set(YjsDatabaseKey.id, sortJSON.id); + sort.set(YjsDatabaseKey.field_id, sortJSON.field_id); + sort.set(YjsDatabaseKey.condition, sortJSON.condition === 'asc' ? '0' : '1'); + + return sort; +} diff --git a/frontend/appflowy_web_app/src/components/database/components/cell/cell.parse.ts b/frontend/appflowy_web_app/src/application/database-yjs/cell.parse.ts similarity index 100% rename from frontend/appflowy_web_app/src/components/database/components/cell/cell.parse.ts rename to frontend/appflowy_web_app/src/application/database-yjs/cell.parse.ts diff --git a/frontend/appflowy_web_app/src/components/database/components/cell/cell.type.ts b/frontend/appflowy_web_app/src/application/database-yjs/cell.type.ts similarity index 99% rename from frontend/appflowy_web_app/src/components/database/components/cell/cell.type.ts rename to frontend/appflowy_web_app/src/application/database-yjs/cell.type.ts index 1c82465a84..9e4bf77737 100644 --- a/frontend/appflowy_web_app/src/components/database/components/cell/cell.type.ts +++ b/frontend/appflowy_web_app/src/application/database-yjs/cell.type.ts @@ -1,5 +1,5 @@ import { FieldId, RowId } from '@/application/collab.type'; -import { DateFormat, TimeFormat } from '@/application/database-yjs'; +import { DateFormat, TimeFormat } from '@/application/database-yjs/index'; import { FieldType } from '@/application/database-yjs/database.type'; import React from 'react'; import { YArray } from 'yjs/dist/src/types/YArray'; diff --git a/frontend/appflowy_web_app/src/application/database-yjs/const.ts b/frontend/appflowy_web_app/src/application/database-yjs/const.ts index c67b9edec8..436f28ef91 100644 --- a/frontend/appflowy_web_app/src/application/database-yjs/const.ts +++ b/frontend/appflowy_web_app/src/application/database-yjs/const.ts @@ -18,7 +18,15 @@ export const getCellData = (rowId: string, fieldId: string, rowMetas: Y.Map { - const namespace = uuidParse(rowId); + let namespace: Uint8Array; + + try { + namespace = uuidParse(rowId); + } catch (e) { + namespace = uuidParse(generateUUID()); + } return (key: RowMetaKey) => uuidv5(key, namespace).toString(); }; + +export const generateUUID = () => uuidv5(Date.now().toString(), uuidv5.URL); diff --git a/frontend/appflowy_web_app/src/application/database-yjs/context.ts b/frontend/appflowy_web_app/src/application/database-yjs/context.ts index 4e0824762c..5d51001976 100644 --- a/frontend/appflowy_web_app/src/application/database-yjs/context.ts +++ b/frontend/appflowy_web_app/src/application/database-yjs/context.ts @@ -1,5 +1,4 @@ import { YDatabase, YDatabaseRow, YDoc, YjsDatabaseKey, YjsEditorKey } from '@/application/collab.type'; -import { Row } from '@/application/database-yjs/selector'; import { createContext, useContext } from 'react'; import * as Y from 'yjs'; @@ -72,17 +71,3 @@ export function useDatabaseFields() { return database.get(YjsDatabaseKey.fields); } - -export interface RowsState { - rowOrders: Row[]; -} - -export const RowsContext = createContext(null); - -export function useRowsContext() { - return useContext(RowsContext); -} - -export function useRows() { - return useRowsContext()?.rowOrders; -} diff --git a/frontend/appflowy_web_app/src/application/database-yjs/fields/date/utils.test.ts b/frontend/appflowy_web_app/src/application/database-yjs/fields/date/utils.test.ts new file mode 100644 index 0000000000..9d3821ba1c --- /dev/null +++ b/frontend/appflowy_web_app/src/application/database-yjs/fields/date/utils.test.ts @@ -0,0 +1,21 @@ +import { getTimeFormat, getDateFormat } from './utils'; +import { expect } from '@jest/globals'; +import { DateFormat, TimeFormat } from '@/application/database-yjs'; + +describe('DateFormat', () => { + it('should return time format', () => { + expect(getTimeFormat(TimeFormat.TwelveHour)).toEqual('h:mm A'); + expect(getTimeFormat(TimeFormat.TwentyFourHour)).toEqual('HH:mm'); + expect(getTimeFormat(56)).toEqual('HH:mm'); + }); + + it('should return date format', () => { + expect(getDateFormat(DateFormat.US)).toEqual('YYYY/MM/DD'); + expect(getDateFormat(DateFormat.ISO)).toEqual('YYYY-MM-DD'); + expect(getDateFormat(DateFormat.Friendly)).toEqual('MMM DD, YYYY'); + expect(getDateFormat(DateFormat.Local)).toEqual('MM/DD/YYYY'); + expect(getDateFormat(DateFormat.DayMonthYear)).toEqual('DD/MM/YYYY'); + + expect(getDateFormat(56)).toEqual('YYYY-MM-DD'); + }); +}); diff --git a/frontend/appflowy_web_app/src/application/database-yjs/filter.ts b/frontend/appflowy_web_app/src/application/database-yjs/filter.ts index 235897b6c5..0bf25e4ca8 100644 --- a/frontend/appflowy_web_app/src/application/database-yjs/filter.ts +++ b/frontend/appflowy_web_app/src/application/database-yjs/filter.ts @@ -78,6 +78,9 @@ function createPredicate(conditions: ((row: Row) => boolean)[]) { export function filterBy(rows: Row[], filters: YDatabaseFilters, fields: YDatabaseFields, rowMetas: Y.Map) { const filterArray = filters.toArray(); + + if (filterArray.length === 0 || rowMetas.size === 0 || fields.size === 0) return rows; + const conditions = filterArray.map((filter) => { return (row: { id: string }) => { const fieldId = filter.get(YjsDatabaseKey.field_id); @@ -142,12 +145,12 @@ export function textFilterCheck(data: string, content: string, condition: TextFi export function numberFilterCheck(data: string, content: string, condition: number) { if (isNaN(Number(data)) || isNaN(Number(content)) || data === '' || content === '') { - if (condition === NumberFilterCondition.NumberIsEmpty && data === '') { - return true; + if (condition === NumberFilterCondition.NumberIsEmpty) { + return data === ''; } - if (condition === NumberFilterCondition.NumberIsNotEmpty && data !== '') { - return true; + if (condition === NumberFilterCondition.NumberIsNotEmpty) { + return data !== ''; } return false; @@ -169,10 +172,6 @@ export function numberFilterCheck(data: string, content: string, condition: numb return decimal < filterDecimal; case NumberFilterCondition.LessThanOrEqualTo: return decimal <= filterDecimal; - case NumberFilterCondition.NumberIsEmpty: - return data === ''; - case NumberFilterCondition.NumberIsNotEmpty: - return data !== ''; default: return false; } @@ -228,14 +227,6 @@ export function selectOptionFilterCheck(data: string, content: string, condition case SelectOptionFilterCondition.OptionDoesNotContain: return some(filterOptionIds, (option) => !selectedOptionIds.includes(option)); - // Ensure selectedOptionIds is empty - case SelectOptionFilterCondition.OptionIsEmpty: - return selectedOptionIds.length === 0; - - // Ensure selectedOptionIds is not empty - case SelectOptionFilterCondition.OptionIsNotEmpty: - return selectedOptionIds.length !== 0; - // Default case, if no conditions match default: return false; diff --git a/frontend/appflowy_web_app/src/application/database-yjs/selector.ts b/frontend/appflowy_web_app/src/application/database-yjs/selector.ts index c7d1272c9d..49fceb885c 100644 --- a/frontend/appflowy_web_app/src/application/database-yjs/selector.ts +++ b/frontend/appflowy_web_app/src/application/database-yjs/selector.ts @@ -14,18 +14,17 @@ import { useDatabaseView, useIsDatabaseRowPage, useRowDocMap, - useRows, useViewId, } from '@/application/database-yjs/context'; import { filterBy, parseFilter } from '@/application/database-yjs/filter'; import { groupByField } from '@/application/database-yjs/group'; import { sortBy } from '@/application/database-yjs/sort'; import { useViewsIdSelector } from '@/application/folder-yjs'; -import { parseYDatabaseCellToCell } from '@/components/database/components/cell/cell.parse'; -import { DateTimeCell } from '@/components/database/components/cell/cell.type'; -import dayjs from 'dayjs'; +import { parseYDatabaseCellToCell } from '@/application/database-yjs/cell.parse'; +import { DateTimeCell } from '@/application/database-yjs/cell.type'; +import * as dayjs from 'dayjs'; import { throttle } from 'lodash-es'; -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import Y from 'yjs'; import { CalendarLayoutSetting, FieldType, FieldVisibility, Filter, RowMetaKey, SortCondition } from './database.type'; @@ -149,12 +148,6 @@ export function useFieldsSelector(visibilitys: FieldVisibility[] = defaultVisibl return columns; } -export function useRowsSelector() { - const rowOrders = useRows(); - - return useMemo(() => rowOrders ?? [], [rowOrders]); -} - export function useFieldSelector(fieldId: string) { const database = useDatabase(); const [field, setField] = useState(null); @@ -403,7 +396,7 @@ export function useRowsByGroup(groupId: string) { if (!fieldId || !rowOrders || !rows) return; const onConditionsChange = () => { - if (rows.size !== rowOrders?.length) return; + if (rows.size < rowOrders?.length) return; const newResult = new Map(); @@ -456,7 +449,7 @@ export function useRowOrdersSelector() { if (!originalRowOrders || !rows) return; - if (originalRowOrders.length !== rows.size && !isDatabaseRowPage) return; + if (originalRowOrders.length > rows.size && !isDatabaseRowPage) return; if (sorts?.length === 0 && filters?.length === 0) { setRowOrders(originalRowOrders); return; @@ -691,7 +684,7 @@ export function useCalendarLayoutSetting() { export function usePrimaryFieldId() { const database = useDatabase(); - const [primaryFieldId, setPrimaryFieldId] = React.useState(null); + const [primaryFieldId, setPrimaryFieldId] = useState(null); useEffect(() => { const fields = database?.get(YjsDatabaseKey.fields); diff --git a/frontend/appflowy_web_app/src/application/database-yjs/sort.ts b/frontend/appflowy_web_app/src/application/database-yjs/sort.ts index 43ba0408a5..cead275830 100644 --- a/frontend/appflowy_web_app/src/application/database-yjs/sort.ts +++ b/frontend/appflowy_web_app/src/application/database-yjs/sort.ts @@ -15,6 +15,8 @@ import * as Y from 'yjs'; export function sortBy(rows: Row[], sorts: YDatabaseSorts, fields: YDatabaseFields, rowMetas: Y.Map) { const sortArray = sorts.toArray(); + + if (sortArray.length === 0 || rowMetas.size === 0 || fields.size === 0) return rows; const iteratees = sortArray.map((sort) => { return (row: { id: string }) => { const fieldId = sort.get(YjsDatabaseKey.field_id); @@ -26,8 +28,7 @@ export function sortBy(rows: Row[], sorts: YDatabaseSorts, fields: YDatabaseFiel const defaultData = parseCellDataForSort(field, ''); - if (!rowMeta) return defaultData; - const meta = rowMeta.getMap(YjsEditorKey.data_section).get(YjsEditorKey.database_row) as YDatabaseRow; + const meta = rowMeta?.getMap(YjsEditorKey.data_section).get(YjsEditorKey.database_row) as YDatabaseRow; if (!meta) return defaultData; if (fieldType === FieldType.LastEditedTime) { @@ -69,9 +70,9 @@ export function parseCellDataForSort(field: YDatabaseField, data: string | boole return data === 'Yes'; case FieldType.SingleSelect: case FieldType.MultiSelect: - return parseSelectOptionCellData(field, typeof data === 'string' ? data : ''); + return parseSelectOptionCellData(field, data as string); case FieldType.Checklist: - return parseChecklistData(typeof data === 'string' ? data : '')?.percentage ?? 0; + return parseChecklistData(data as string)?.percentage ?? 0; case FieldType.DateTime: return Number(data); case FieldType.Relation: diff --git a/frontend/appflowy_web_app/src/application/slate-yjs/__tests__/applyRemoteEvents.ts b/frontend/appflowy_web_app/src/application/slate-yjs/__tests__/applyRemoteEvents.ts new file mode 100644 index 0000000000..62c24c12b8 --- /dev/null +++ b/frontend/appflowy_web_app/src/application/slate-yjs/__tests__/applyRemoteEvents.ts @@ -0,0 +1,49 @@ +import { CollabOrigin } from '@/application/collab.type'; +import { yDocToSlateContent } from '@/application/slate-yjs/utils/convert'; +import { generateId, insertBlock, withTestingYDoc, withTestingYjsEditor } from './withTestingYjsEditor'; +import { createEditor } from 'slate'; +import { expect } from '@jest/globals'; +import * as Y from 'yjs'; + +export async function runApplyRemoteEventsTest() { + const pageId = generateId(); + const remoteDoc = withTestingYDoc(pageId); + const remote = withTestingYjsEditor(createEditor(), remoteDoc); + + const localDoc = new Y.Doc(); + + Y.applyUpdateV2(localDoc, Y.encodeStateAsUpdateV2(remoteDoc)); + const editor = withTestingYjsEditor(createEditor(), localDoc); + + editor.connect(); + expect(editor.children).toEqual(remote.children); + + // update remote doc + const id = generateId(); + + const { applyDelta } = insertBlock({ + doc: remoteDoc, + blockObject: { + id, + ty: 'paragraph', + relation_id: id, + text_id: id, + data: JSON.stringify({ level: 1 }), + }, + }); + + applyDelta([{ insert: 'Hello ' }, { insert: 'World', attributes: { bold: true } }]); + + remote.children = yDocToSlateContent(remoteDoc)?.children ?? []; + + // apply remote changes to local doc + Y.transact( + localDoc, + () => { + Y.applyUpdateV2(localDoc, Y.encodeStateAsUpdateV2(remoteDoc)); + }, + CollabOrigin.Remote + ); + + expect(editor.children).toEqual(remote.children); +} diff --git a/frontend/appflowy_web_app/src/application/slate-yjs/__tests__/convert.test.ts b/frontend/appflowy_web_app/src/application/slate-yjs/__tests__/convert.test.ts new file mode 100644 index 0000000000..0e473517d8 --- /dev/null +++ b/frontend/appflowy_web_app/src/application/slate-yjs/__tests__/convert.test.ts @@ -0,0 +1,268 @@ +import { generateId, getTestingDocData, insertBlock, withTestingYDoc } from './withTestingYjsEditor'; +import { yDocToSlateContent, deltaInsertToSlateNode, yDataToSlateContent } from '@/application/slate-yjs/utils/convert'; +import { expect } from '@jest/globals'; +import * as Y from 'yjs'; + +describe('convert yjs data to slate content', () => { + it('should return undefined if root block is not exist', () => { + const doc = new Y.Doc(); + + expect(() => yDocToSlateContent(doc)).toThrowError(); + + const doc2 = withTestingYDoc('1'); + const { blocks, childrenMap, textMap, pageId } = getTestingDocData(doc2); + expect(yDataToSlateContent({ blocks, rootId: '2', childrenMap, textMap })).toBeUndefined(); + + blocks.delete(pageId); + + expect(yDataToSlateContent({ blocks, rootId: pageId, childrenMap, textMap })).toBeUndefined(); + }); + it('should match empty array', () => { + const doc = withTestingYDoc('1'); + const slateContent = yDocToSlateContent(doc)!; + + expect(slateContent).not.toBeUndefined(); + expect(slateContent.children).toMatchObject([]); + }); + it('should match single paragraph', () => { + const doc = withTestingYDoc('1'); + const id = generateId(); + + const { applyDelta } = insertBlock({ + doc, + blockObject: { + id, + ty: 'paragraph', + relation_id: id, + text_id: id, + data: JSON.stringify({ level: 1 }), + }, + }); + + applyDelta([{ insert: 'Hello ' }, { insert: 'World', attributes: { bold: true } }]); + const slateContent = yDocToSlateContent(doc)!; + + expect(slateContent).not.toBeUndefined(); + expect(slateContent.children).toEqual([ + { + blockId: id, + relationId: id, + type: 'paragraph', + data: { level: 1 }, + children: [ + { + textId: id, + type: 'text', + children: [{ text: 'Hello ' }, { text: 'World', bold: true }], + }, + ], + }, + ]); + }); + it('should match nesting paragraphs', () => { + const doc = withTestingYDoc('1'); + const id1 = generateId(); + const id2 = generateId(); + + const { applyDelta, appendChild } = insertBlock({ + doc, + blockObject: { + id: id1, + ty: 'paragraph', + relation_id: id1, + text_id: id1, + data: '', + }, + }); + + applyDelta([{ insert: 'Hello ' }, { insert: 'World', attributes: { bold: true } }]); + appendChild({ + id: id2, + ty: 'paragraph', + relation_id: id2, + text_id: id2, + data: '', + }).applyDelta([{ insert: 'I am nested' }]); + + const slateContent = yDocToSlateContent(doc)!; + + expect(slateContent).not.toBeUndefined(); + expect(slateContent.children).toEqual([ + { + blockId: id1, + relationId: id1, + type: 'paragraph', + data: {}, + children: [ + { + textId: id1, + type: 'text', + children: [{ text: 'Hello ' }, { text: 'World', bold: true }], + }, + { + blockId: id2, + relationId: id2, + type: 'paragraph', + data: {}, + children: [{ textId: id2, type: 'text', children: [{ text: 'I am nested' }] }], + }, + ], + }, + ]); + }); + it('should compatible with delta in data', () => { + const doc = withTestingYDoc('1'); + const id = generateId(); + + insertBlock({ + doc, + blockObject: { + id, + ty: 'paragraph', + relation_id: id, + text_id: id, + data: JSON.stringify({ + delta: [ + { insert: 'Hello ' }, + { insert: 'World', attributes: { bold: true } }, + { insert: ' ', attributes: { code: true } }, + ], + }), + }, + }); + + const slateContent = yDocToSlateContent(doc)!; + + expect(slateContent).not.toBeUndefined(); + expect(slateContent.children).toEqual([ + { + blockId: id, + relationId: id, + type: 'paragraph', + data: { + delta: [ + { insert: 'Hello ' }, + { insert: 'World', attributes: { bold: true } }, + { + insert: ' ', + attributes: { code: true }, + }, + ], + }, + children: [ + { + textId: id, + type: 'text', + children: [{ text: 'Hello ' }, { text: 'World', bold: true }, { text: ' ', code: true }], + }, + { + text: '', + }, + ], + }, + ]); + }); + it('should return undefined if data is invalid', () => { + const doc = withTestingYDoc('1'); + const id = generateId(); + + insertBlock({ + doc, + blockObject: { + id, + ty: 'paragraph', + relation_id: id, + text_id: id, + data: 'invalid', + }, + }); + + const slateContent = yDocToSlateContent(doc)!; + + expect(slateContent).not.toBeUndefined(); + expect(slateContent.children).toEqual([undefined]); + }); + it('should return a normalize node if the delta is not exist', () => { + const doc = withTestingYDoc('1'); + const id = generateId(); + + insertBlock({ + doc, + blockObject: { + id, + ty: 'paragraph', + relation_id: id, + text_id: id, + data: JSON.stringify({}), + }, + }); + + const slateContent = yDocToSlateContent(doc)!; + + expect(slateContent).not.toBeUndefined(); + expect(slateContent.children).toEqual([ + { + blockId: id, + relationId: id, + type: 'paragraph', + data: {}, + children: [{ text: '' }], + }, + ]); + }); +}); + +describe('test deltaInsertToSlateNode', () => { + it('should match text node', () => { + const node = deltaInsertToSlateNode({ insert: 'Hello' }); + + expect(node).toEqual({ text: 'Hello' }); + }); + + it('should match text node with attributes', () => { + const node = deltaInsertToSlateNode({ insert: 'Hello', attributes: { bold: true } }); + + expect(node).toEqual({ text: 'Hello', bold: true }); + }); + + it('should delete empty string attributes', () => { + const node = deltaInsertToSlateNode({ insert: 'Hello', attributes: { bold: false, font_color: '' } }); + + expect(node).toEqual({ text: 'Hello' }); + }); + + it('should generate formula inline node', () => { + const node = deltaInsertToSlateNode({ + insert: '$$', + attributes: { formula: 'world' }, + }); + + expect(node).toEqual([ + { + type: 'formula', + data: 'world', + children: [{ text: '$' }], + }, + { + type: 'formula', + data: 'world', + children: [{ text: '$' }], + }, + ]); + }); + + it('should generate mention inline node', () => { + const node = deltaInsertToSlateNode({ + insert: '@', + attributes: { mention: 'world' }, + }); + + expect(node).toEqual([ + { + type: 'mention', + data: 'world', + children: [{ text: '@' }], + }, + ]); + }); +}); diff --git a/frontend/appflowy_web_app/src/application/slate-yjs/utils/__tests__/convert.ts b/frontend/appflowy_web_app/src/application/slate-yjs/__tests__/convert.ts similarity index 65% rename from frontend/appflowy_web_app/src/application/slate-yjs/utils/__tests__/convert.ts rename to frontend/appflowy_web_app/src/application/slate-yjs/__tests__/convert.ts index ef0c26b054..6aa830b6b0 100644 --- a/frontend/appflowy_web_app/src/application/slate-yjs/utils/__tests__/convert.ts +++ b/frontend/appflowy_web_app/src/application/slate-yjs/__tests__/convert.ts @@ -1,5 +1,5 @@ import { withTestingYDoc, withTestingYjsEditor } from './withTestingYjsEditor'; -import { yDocToSlateContent } from '../convert'; +import { yDocToSlateContent } from '../utils/convert'; import { createEditor, Editor } from 'slate'; import { expect } from '@jest/globals'; import * as Y from 'yjs'; @@ -39,3 +39,34 @@ export async function runCollaborationTest() { expect(yjsEditor.children).toEqual(remote.children); expect(normalizedSlateDoc(doc)).toEqual(yjsEditor.children); } + +export function runLocalChangeTest() { + const doc = withTestingYDoc('1'); + const editor = withTestingYjsEditor(createEditor(), doc); + + editor.connect(); + + editor.insertNode( + { + type: 'paragraph', + blockId: '1', + children: [ + { + textId: '1', + type: 'text', + children: [{ text: 'Hello' }], + }, + ], + }, + { + at: [0], + } + ); + + editor.apply({ + type: 'set_selection', + properties: {}, + newProperties: { anchor: { path: [0, 0], offset: 5 }, focus: { path: [0, 0], offset: 5 } }, + }); + // expect(editor.children).toEqual(yDocToSlateContent(doc)?.children); +} diff --git a/frontend/appflowy_web_app/src/application/slate-yjs/__tests__/index.test.ts b/frontend/appflowy_web_app/src/application/slate-yjs/__tests__/index.test.ts new file mode 100644 index 0000000000..f261b2244f --- /dev/null +++ b/frontend/appflowy_web_app/src/application/slate-yjs/__tests__/index.test.ts @@ -0,0 +1,67 @@ +import { runCollaborationTest, runLocalChangeTest } from './convert'; +import { runApplyRemoteEventsTest } from './applyRemoteEvents'; +import { + getTestingDocData, + withTestingYDoc, + withTestingYjsEditor, +} from '@/application/slate-yjs/__tests__/withTestingYjsEditor'; +import { createEditor } from 'slate'; +import Y from 'yjs'; +import { expect } from '@jest/globals'; +import { YjsEditor } from '@/application/slate-yjs'; + +describe('slate-yjs adapter', () => { + it('should pass the collaboration test', async () => { + await runCollaborationTest(); + }); + + it('should pass the apply remote events test', async () => { + await runApplyRemoteEventsTest(); + }); + + it('should store local changes', () => { + runLocalChangeTest(); + }); + + it('should throw error when already connected', () => { + const doc = withTestingYDoc('1'); + const editor = withTestingYjsEditor(createEditor(), doc); + editor.connect(); + expect(() => editor.connect()).toThrowError(); + }); + + it('should re connect after disconnect', () => { + const doc = withTestingYDoc('1'); + const editor = withTestingYjsEditor(createEditor(), doc); + editor.connect(); + editor.disconnect(); + expect(() => editor.connect()).not.toThrowError(); + }); + + it('should ensure the editor is connected before disconnecting', () => { + const doc = withTestingYDoc('1'); + const editor = withTestingYjsEditor(createEditor(), doc); + expect(() => editor.disconnect()).toThrowError(); + }); + + it('should have been called', () => { + const doc = withTestingYDoc('1'); + const editor = withTestingYjsEditor(createEditor(), doc); + editor.connect = jest.fn(); + YjsEditor.connect(editor); + expect(editor.connect).toHaveBeenCalled(); + + editor.disconnect = jest.fn(); + YjsEditor.disconnect(editor); + expect(editor.disconnect).toHaveBeenCalled(); + }); + + it('should can not be converted to slate content', () => { + const doc = withTestingYDoc('1'); + const { blocks, childrenMap, textMap, pageId } = getTestingDocData(doc); + blocks.delete(pageId); + const editor = withTestingYjsEditor(createEditor(), doc); + YjsEditor.connect(editor); + expect(editor.children).toEqual([]); + }); +}); diff --git a/frontend/appflowy_web_app/src/application/slate-yjs/__tests__/withTestingYjsEditor.ts b/frontend/appflowy_web_app/src/application/slate-yjs/__tests__/withTestingYjsEditor.ts new file mode 100644 index 0000000000..81ffce4f9e --- /dev/null +++ b/frontend/appflowy_web_app/src/application/slate-yjs/__tests__/withTestingYjsEditor.ts @@ -0,0 +1,135 @@ +import { + CollabOrigin, + YBlocks, + YChildrenMap, + YjsEditorKey, + YMeta, + YSharedRoot, + YTextMap, +} from '@/application/collab.type'; +import { withYjs } from '@/application/slate-yjs'; +import { YDelta } from '@/application/slate-yjs/utils/convert'; +import { Editor } from 'slate'; +import * as Y from 'yjs'; +import { v4 as uuidv4 } from 'uuid'; + +export function generateId() { + return uuidv4(); +} + +export function withTestingYjsEditor(editor: Editor, doc: Y.Doc) { + const yjdEditor = withYjs(editor, doc, { + localOrigin: CollabOrigin.LocalSync, + }); + + return yjdEditor; +} + +export function getTestingDocData(doc: Y.Doc) { + const sharedRoot = doc.getMap(YjsEditorKey.data_section) as YSharedRoot; + const document = sharedRoot.get(YjsEditorKey.document); + const blocks = document.get(YjsEditorKey.blocks) as YBlocks; + const meta = document.get(YjsEditorKey.meta) as YMeta; + const childrenMap = meta.get(YjsEditorKey.children_map) as YChildrenMap; + const textMap = meta.get(YjsEditorKey.text_map) as YTextMap; + const pageId = document.get(YjsEditorKey.page_id) as string; + + return { + sharedRoot, + document, + blocks, + meta, + childrenMap, + textMap, + pageId, + }; +} + +export function withTestingYDoc(docId: string) { + const doc = new Y.Doc(); + const sharedRoot = doc.getMap(YjsEditorKey.data_section) as YSharedRoot; + const document = new Y.Map(); + const blocks = new Y.Map(); + const meta = new Y.Map(); + const children_map = new Y.Map(); + const text_map = new Y.Map(); + const rootBlock = new Y.Map(); + const blockOrders = new Y.Array(); + const pageId = docId; + + sharedRoot.set(YjsEditorKey.document, document); + document.set(YjsEditorKey.page_id, pageId); + document.set(YjsEditorKey.blocks, blocks); + document.set(YjsEditorKey.meta, meta); + meta.set(YjsEditorKey.children_map, children_map); + meta.set(YjsEditorKey.text_map, text_map); + children_map.set(pageId, blockOrders); + blocks.set(pageId, rootBlock); + rootBlock.set(YjsEditorKey.block_id, pageId); + rootBlock.set(YjsEditorKey.block_children, pageId); + rootBlock.set(YjsEditorKey.block_type, 'page'); + rootBlock.set(YjsEditorKey.block_data, '{}'); + rootBlock.set(YjsEditorKey.block_external_id, ''); + return doc; +} + +export interface BlockObject { + id: string; + ty: string; + relation_id: string; + text_id: string; + data: string; +} + +export function insertBlock({ + doc, + parentBlockId, + prevBlockId, + blockObject, +}: { + doc: Y.Doc; + parentBlockId?: string; + prevBlockId?: string; + blockObject: BlockObject; +}) { + const { blocks, childrenMap, textMap, pageId } = getTestingDocData(doc); + const block = new Y.Map(); + const { id, ty, relation_id, text_id, data } = blockObject; + + block.set(YjsEditorKey.block_id, id); + block.set(YjsEditorKey.block_type, ty); + block.set(YjsEditorKey.block_children, relation_id); + block.set(YjsEditorKey.block_external_id, text_id); + block.set(YjsEditorKey.block_data, data); + blocks.set(id, block); + + const blockParentId = parentBlockId || pageId; + const blockParentChildren = childrenMap.get(blockParentId); + const index = prevBlockId ? blockParentChildren.toArray().indexOf(prevBlockId) + 1 : 0; + + blockParentChildren.insert(index, [id]); + + return { + applyDelta: (delta: YDelta[]) => { + let text = textMap.get(text_id); + + if (!text) { + text = new Y.Text(); + textMap.set(text_id, text); + } + + text.applyDelta(delta); + }, + appendChild: (childBlock: BlockObject) => { + if (!childrenMap.has(relation_id)) { + childrenMap.set(relation_id, new Y.Array()); + } + + return insertBlock({ + doc, + parentBlockId: id, + blockObject: childBlock, + }); + }, + }; +} diff --git a/frontend/appflowy_web_app/src/application/slate-yjs/utils/__tests__/applyRemoteEvents.ts b/frontend/appflowy_web_app/src/application/slate-yjs/utils/__tests__/applyRemoteEvents.ts deleted file mode 100644 index 7348ce0029..0000000000 --- a/frontend/appflowy_web_app/src/application/slate-yjs/utils/__tests__/applyRemoteEvents.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { - CollabOrigin, - YBlocks, - YChildrenMap, - YjsEditorKey, - YMeta, - YSharedRoot, - YTextMap, -} from '@/application/collab.type'; -import { yDocToSlateContent } from '@/application/slate-yjs/utils/convert'; -import { generateId, withTestingYDoc, withTestingYjsEditor } from './withTestingYjsEditor'; -import { createEditor } from 'slate'; -import { expect } from '@jest/globals'; -import * as Y from 'yjs'; - -export async function runApplyRemoteEventsTest() { - const pageId = generateId(); - const remoteDoc = withTestingYDoc(pageId); - const remote = withTestingYjsEditor(createEditor(), remoteDoc); - - const localDoc = new Y.Doc(); - - Y.applyUpdateV2(localDoc, Y.encodeStateAsUpdateV2(remoteDoc)); - const editor = withTestingYjsEditor(createEditor(), localDoc); - - editor.connect(); - expect(editor.children).toEqual(remote.children); - - // update remote doc - insertBlock(remoteDoc, generateId(), pageId, 0); - remote.children = yDocToSlateContent(remoteDoc)?.children ?? []; - - // apply remote changes to local doc - Y.transact( - localDoc, - () => { - Y.applyUpdateV2(localDoc, Y.encodeStateAsUpdateV2(remoteDoc)); - }, - CollabOrigin.Remote - ); - - expect(editor.children).toEqual(remote.children); -} - -function insertBlock(doc: Y.Doc, blockId: string, parentId: string, index: number) { - const sharedRoot = doc.getMap(YjsEditorKey.data_section) as YSharedRoot; - const document = sharedRoot.get(YjsEditorKey.document); - const blocks = document.get(YjsEditorKey.blocks) as YBlocks; - const meta = document.get(YjsEditorKey.meta) as YMeta; - const childrenMap = meta.get(YjsEditorKey.children_map) as YChildrenMap; - const textMap = meta.get(YjsEditorKey.text_map) as YTextMap; - - const block = new Y.Map(); - - block.set(YjsEditorKey.block_id, blockId); - block.set(YjsEditorKey.block_children, blockId); - block.set(YjsEditorKey.block_type, 'paragraph'); - block.set(YjsEditorKey.block_data, '{}'); - block.set(YjsEditorKey.block_external_id, blockId); - blocks.set(blockId, block); - childrenMap.set(blockId, new Y.Array()); - childrenMap.get(parentId).insert(index, [blockId]); - const text = new Y.Text(); - - text.insert(0, 'Hello, World!'); - textMap.set(blockId, text); -} diff --git a/frontend/appflowy_web_app/src/application/slate-yjs/utils/__tests__/index.test.ts b/frontend/appflowy_web_app/src/application/slate-yjs/utils/__tests__/index.test.ts deleted file mode 100644 index bcbd87176f..0000000000 --- a/frontend/appflowy_web_app/src/application/slate-yjs/utils/__tests__/index.test.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { runCollaborationTest } from './convert'; -import { runApplyRemoteEventsTest } from './applyRemoteEvents'; - -describe('slate-yjs adapter', () => { - it('should pass the collaboration test', async () => { - await runCollaborationTest(); - }); - - it('should pass the apply remote events test', async () => { - await runApplyRemoteEventsTest(); - }); -}); diff --git a/frontend/appflowy_web_app/src/application/slate-yjs/utils/__tests__/withTestingYjsEditor.ts b/frontend/appflowy_web_app/src/application/slate-yjs/utils/__tests__/withTestingYjsEditor.ts deleted file mode 100644 index 9d6922ad62..0000000000 --- a/frontend/appflowy_web_app/src/application/slate-yjs/utils/__tests__/withTestingYjsEditor.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { CollabOrigin, YjsEditorKey, YSharedRoot } from '@/application/collab.type'; -import { withYjs } from '@/application/slate-yjs'; -import { Editor } from 'slate'; -import * as Y from 'yjs'; -import { v4 as uuidv4 } from 'uuid'; - -export function generateId() { - return uuidv4(); -} - -export function withTestingYjsEditor(editor: Editor, doc: Y.Doc) { - const yjdEditor = withYjs(editor, doc, { - localOrigin: CollabOrigin.LocalSync, - }); - - return yjdEditor; -} - -export function withTestingYDoc(docId: string) { - const doc = new Y.Doc(); - const sharedRoot = doc.getMap(YjsEditorKey.data_section) as YSharedRoot; - const document = new Y.Map(); - const blocks = new Y.Map(); - const meta = new Y.Map(); - const children_map = new Y.Map(); - const text_map = new Y.Map(); - const rootBlock = new Y.Map(); - const blockOrders = new Y.Array(); - const pageId = docId; - - sharedRoot.set(YjsEditorKey.document, document); - document.set(YjsEditorKey.page_id, pageId); - document.set(YjsEditorKey.blocks, blocks); - document.set(YjsEditorKey.meta, meta); - meta.set(YjsEditorKey.children_map, children_map); - meta.set(YjsEditorKey.text_map, text_map); - children_map.set(pageId, blockOrders); - blocks.set(pageId, rootBlock); - rootBlock.set(YjsEditorKey.block_id, pageId); - rootBlock.set(YjsEditorKey.block_children, pageId); - rootBlock.set(YjsEditorKey.block_type, 'page'); - rootBlock.set(YjsEditorKey.block_data, '{}'); - rootBlock.set(YjsEditorKey.block_external_id, ''); - return doc; -} diff --git a/frontend/appflowy_web_app/src/application/slate-yjs/utils/convert.ts b/frontend/appflowy_web_app/src/application/slate-yjs/utils/convert.ts index 0cc5f372e9..67defd6acc 100644 --- a/frontend/appflowy_web_app/src/application/slate-yjs/utils/convert.ts +++ b/frontend/appflowy_web_app/src/application/slate-yjs/utils/convert.ts @@ -11,21 +11,19 @@ import { BlockType, } from '@/application/collab.type'; import { BlockJson } from '@/application/slate-yjs/utils/types'; -import { getFontFamily } from '@/utils/font'; -import { uniq } from 'lodash-es'; import { Element, Text } from 'slate'; -export function yDocToSlateContent(doc: YDoc): Element | undefined { - const sharedRoot = doc.getMap(YjsEditorKey.data_section) as YSharedRoot; - - const document = sharedRoot.get(YjsEditorKey.document); - const pageId = document.get(YjsEditorKey.page_id) as string; - const blocks = document.get(YjsEditorKey.blocks) as YBlocks; - const meta = document.get(YjsEditorKey.meta) as YMeta; - const childrenMap = meta.get(YjsEditorKey.children_map) as YChildrenMap; - const textMap = meta.get(YjsEditorKey.text_map) as YTextMap; - const fontFamilys: string[] = []; - +export function yDataToSlateContent({ + blocks, + rootId, + childrenMap, + textMap, +}: { + blocks: YBlocks; + childrenMap: YChildrenMap; + textMap: YTextMap; + rootId: string; +}): Element | undefined { function traverse(id: string) { const block = blocks.get(id).toJSON() as BlockJson; const childrenId = block.children as string; @@ -44,7 +42,9 @@ export function yDocToSlateContent(doc: YDoc): Element | undefined { let delta; - if (!textId) { + const yText = textId ? textMap.get(textId) : undefined; + + if (!yText) { if (children.length === 0) { children.push({ text: '', @@ -64,18 +64,12 @@ export function yDocToSlateContent(doc: YDoc): Element | undefined { } } } else { - delta = textMap.get(textId)?.toDelta(); + delta = yText.toDelta(); } try { const slateDelta = delta.flatMap(deltaInsertToSlateNode); - // collect font family - slateDelta.forEach((node: Text) => { - if (node.font_family) { - fontFamilys.push(getFontFamily(node.font_family)); - } - }); const textNode: Element = { textId, type: YjsEditorKey.text, @@ -85,30 +79,39 @@ export function yDocToSlateContent(doc: YDoc): Element | undefined { children.unshift(textNode); return slateNode; } catch (e) { - console.error(e); return; } } - const root = blocks.get(pageId); + const root = blocks.get(rootId); if (!root) return; - const result = traverse(pageId); + const result = traverse(rootId); if (!result) return; - if (fontFamilys.length > 0) { - window.WebFont?.load({ - google: { - families: uniq(fontFamilys), - }, - }); - } - return result; } +export function yDocToSlateContent(doc: YDoc): Element | undefined { + const sharedRoot = doc.getMap(YjsEditorKey.data_section) as YSharedRoot; + + const document = sharedRoot.get(YjsEditorKey.document); + const pageId = document.get(YjsEditorKey.page_id) as string; + const blocks = document.get(YjsEditorKey.blocks) as YBlocks; + const meta = document.get(YjsEditorKey.meta) as YMeta; + const childrenMap = meta.get(YjsEditorKey.children_map) as YChildrenMap; + const textMap = meta.get(YjsEditorKey.text_map) as YTextMap; + + return yDataToSlateContent({ + blocks, + rootId: pageId, + childrenMap, + textMap, + }); +} + export function blockToSlateNode(block: BlockJson): Element { const data = block.data; let blockData; @@ -116,7 +119,7 @@ export function blockToSlateNode(block: BlockJson): Element { try { blockData = data ? JSON.parse(data) : {}; } catch (e) { - blockData = {}; + // do nothing } return { @@ -128,13 +131,12 @@ export function blockToSlateNode(block: BlockJson): Element { }; } -export function deltaInsertToSlateNode({ - attributes, - insert, -}: { +export interface YDelta { insert: string; - attributes: Record; -}): Element | Text | Element[] { + attributes?: Record; +} + +export function deltaInsertToSlateNode({ attributes, insert }: YDelta): Element | Text | Element[] { const matchInlines = transformToInlineElement({ insert, attributes, @@ -145,17 +147,7 @@ export function deltaInsertToSlateNode({ } if (attributes) { - if ('font_color' in attributes && attributes['font_color'] === '') { - delete attributes['font_color']; - } - - if ('bg_color' in attributes && attributes['bg_color'] === '') { - delete attributes['bg_color']; - } - - if ('code' in attributes && !attributes['code']) { - delete attributes['code']; - } + dealWithEmptyAttribute(attributes); } return { @@ -164,10 +156,15 @@ export function deltaInsertToSlateNode({ }; } -export function transformToInlineElement(op: { - insert: string; - attributes: Record; -}): Element[] { +function dealWithEmptyAttribute(attributes: Record) { + for (const key in attributes) { + if (!attributes[key]) { + delete attributes[key]; + } + } +} + +export function transformToInlineElement(op: YDelta): Element[] { const attributes = op.attributes; if (!attributes) return []; diff --git a/frontend/appflowy_web_app/src/components/database/components/calendar/event/EventPaperTitle.tsx b/frontend/appflowy_web_app/src/components/database/components/calendar/event/EventPaperTitle.tsx index 6ede73fd99..0ab976c13e 100644 --- a/frontend/appflowy_web_app/src/components/database/components/calendar/event/EventPaperTitle.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/calendar/event/EventPaperTitle.tsx @@ -1,5 +1,5 @@ import { useCellSelector } from '@/application/database-yjs'; -import { TextCell } from '@/components/database/components/cell/cell.type'; +import { TextCell } from '@/application/database-yjs/cell.type'; import { TextProperty } from '@/components/database/components/property/text'; import React from 'react'; diff --git a/frontend/appflowy_web_app/src/components/database/components/cell/Cell.tsx b/frontend/appflowy_web_app/src/components/database/components/cell/Cell.tsx index d234397606..3835db12ff 100644 --- a/frontend/appflowy_web_app/src/components/database/components/cell/Cell.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/cell/Cell.tsx @@ -10,7 +10,7 @@ import { CheckboxCell } from '@/components/database/components/cell/checkbox'; import { SelectOptionCell } from '@/components/database/components/cell/select-option'; import { DateTimeCell } from '@/components/database/components/cell/date'; import { ChecklistCell } from '@/components/database/components/cell/checklist'; -import { CellProps, Cell as CellType } from '@/components/database/components/cell/cell.type'; +import { CellProps, Cell as CellType } from '@/application/database-yjs/cell.type'; import { RelationCell } from '@/components/database/components/cell/relation'; export function Cell(props: CellProps) { diff --git a/frontend/appflowy_web_app/src/components/database/components/cell/cell.const.ts b/frontend/appflowy_web_app/src/components/database/components/cell/cell.const.ts index d9e3564096..b358ed6e49 100644 --- a/frontend/appflowy_web_app/src/components/database/components/cell/cell.const.ts +++ b/frontend/appflowy_web_app/src/components/database/components/cell/cell.const.ts @@ -11,15 +11,3 @@ export const SelectOptionColorMap = { [SelectOptionColor.Aqua]: '--tint-aqua', [SelectOptionColor.Blue]: '--tint-blue', }; - -export const SelectOptionColorTextMap = { - [SelectOptionColor.Purple]: 'purpleColor', - [SelectOptionColor.Pink]: 'pinkColor', - [SelectOptionColor.LightPink]: 'lightPinkColor', - [SelectOptionColor.Orange]: 'orangeColor', - [SelectOptionColor.Yellow]: 'yellowColor', - [SelectOptionColor.Lime]: 'limeColor', - [SelectOptionColor.Green]: 'greenColor', - [SelectOptionColor.Aqua]: 'aquaColor', - [SelectOptionColor.Blue]: 'blueColor', -} as const; diff --git a/frontend/appflowy_web_app/src/components/database/components/cell/checkbox/CheckboxCell.tsx b/frontend/appflowy_web_app/src/components/database/components/cell/checkbox/CheckboxCell.tsx index c2b3e7ac68..3b480f946a 100644 --- a/frontend/appflowy_web_app/src/components/database/components/cell/checkbox/CheckboxCell.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/cell/checkbox/CheckboxCell.tsx @@ -1,7 +1,7 @@ import { ReactComponent as CheckboxCheckSvg } from '$icons/16x/check_filled.svg'; import { ReactComponent as CheckboxUncheckSvg } from '$icons/16x/uncheck.svg'; import { FieldType } from '@/application/database-yjs'; -import { CellProps, CheckboxCell as CheckboxCellType } from '@/components/database/components/cell/cell.type'; +import { CellProps, CheckboxCell as CheckboxCellType } from '@/application/database-yjs/cell.type'; export function CheckboxCell({ cell, style }: CellProps) { const checked = cell?.data; diff --git a/frontend/appflowy_web_app/src/components/database/components/cell/checklist/ChecklistCell.tsx b/frontend/appflowy_web_app/src/components/database/components/cell/checklist/ChecklistCell.tsx index 618562b373..e3c927a607 100644 --- a/frontend/appflowy_web_app/src/components/database/components/cell/checklist/ChecklistCell.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/cell/checklist/ChecklistCell.tsx @@ -1,5 +1,5 @@ import { FieldType, parseChecklistData } from '@/application/database-yjs'; -import { CellProps, ChecklistCell as ChecklistCellType } from '@/components/database/components/cell/cell.type'; +import { CellProps, ChecklistCell as ChecklistCellType } from '@/application/database-yjs/cell.type'; import LinearProgressWithLabel from '@/components/_shared/progress/LinearProgressWithLabel'; import React, { useMemo } from 'react'; diff --git a/frontend/appflowy_web_app/src/components/database/components/cell/date/DateTimeCell.tsx b/frontend/appflowy_web_app/src/components/database/components/cell/date/DateTimeCell.tsx index c64c0f2d01..ca3ab41957 100644 --- a/frontend/appflowy_web_app/src/components/database/components/cell/date/DateTimeCell.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/cell/date/DateTimeCell.tsx @@ -1,6 +1,6 @@ import { FieldType } from '@/application/database-yjs'; import { useDateTypeCellDispatcher } from '@/components/database/components/cell/Cell.hooks'; -import { CellProps, DateTimeCell as DateTimeCellType } from '@/components/database/components/cell/cell.type'; +import { CellProps, DateTimeCell as DateTimeCellType } from '@/application/database-yjs/cell.type'; import React, { useMemo } from 'react'; import { ReactComponent as ReminderSvg } from '$icons/16x/clock_alarm.svg'; diff --git a/frontend/appflowy_web_app/src/components/database/components/cell/number/NumberCell.tsx b/frontend/appflowy_web_app/src/components/database/components/cell/number/NumberCell.tsx index f7312bfbd8..4217c880c4 100644 --- a/frontend/appflowy_web_app/src/components/database/components/cell/number/NumberCell.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/cell/number/NumberCell.tsx @@ -5,7 +5,7 @@ import { parseNumberTypeOptions, FieldType, } from '@/application/database-yjs'; -import { CellProps, NumberCell as NumberCellType } from '@/components/database/components/cell/cell.type'; +import { CellProps, NumberCell as NumberCellType } from '@/application/database-yjs/cell.type'; import React, { useMemo } from 'react'; import Decimal from 'decimal.js'; diff --git a/frontend/appflowy_web_app/src/components/database/components/cell/primary/PrimaryCell.tsx b/frontend/appflowy_web_app/src/components/database/components/cell/primary/PrimaryCell.tsx index 09287d48b5..7c2eb6c648 100644 --- a/frontend/appflowy_web_app/src/components/database/components/cell/primary/PrimaryCell.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/cell/primary/PrimaryCell.tsx @@ -1,5 +1,5 @@ import { useNavigateToRow, useRowMetaSelector } from '@/application/database-yjs'; -import { TextCell as CellType, CellProps } from '@/components/database/components/cell/cell.type'; +import { TextCell as CellType, CellProps } from '@/application/database-yjs/cell.type'; import { TextCell } from '@/components/database/components/cell/text'; import OpenAction from '@/components/database/components/database-row/OpenAction'; import { getPlatform } from '@/utils/platform'; diff --git a/frontend/appflowy_web_app/src/components/database/components/cell/relation/RelationCell.tsx b/frontend/appflowy_web_app/src/components/database/components/cell/relation/RelationCell.tsx index 47ac405966..90beed4732 100644 --- a/frontend/appflowy_web_app/src/components/database/components/cell/relation/RelationCell.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/cell/relation/RelationCell.tsx @@ -1,5 +1,5 @@ import { FieldType } from '@/application/database-yjs'; -import { CellProps, RelationCell as RelationCellType } from '@/components/database/components/cell/cell.type'; +import { CellProps, RelationCell as RelationCellType } from '@/application/database-yjs/cell.type'; import RelationItems from '@/components/database/components/cell/relation/RelationItems'; import React from 'react'; diff --git a/frontend/appflowy_web_app/src/components/database/components/cell/relation/RelationItems.tsx b/frontend/appflowy_web_app/src/components/database/components/cell/relation/RelationItems.tsx index fd63c28196..259447e0ae 100644 --- a/frontend/appflowy_web_app/src/components/database/components/cell/relation/RelationItems.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/cell/relation/RelationItems.tsx @@ -6,7 +6,7 @@ import { useFieldSelector, useNavigateToRow, } from '@/application/database-yjs'; -import { RelationCell, RelationCellData } from '@/components/database/components/cell/cell.type'; +import { RelationCell, RelationCellData } from '@/application/database-yjs/cell.type'; import { RelationPrimaryValue } from '@/components/database/components/cell/relation/RelationPrimaryValue'; import { useGetDatabaseDispatch } from '@/components/database/Database.hooks'; import React, { useEffect, useMemo, useState } from 'react'; diff --git a/frontend/appflowy_web_app/src/components/database/components/cell/relation/RelationPrimaryValue.tsx b/frontend/appflowy_web_app/src/components/database/components/cell/relation/RelationPrimaryValue.tsx index 0c33397eb8..a6ae613dd5 100644 --- a/frontend/appflowy_web_app/src/components/database/components/cell/relation/RelationPrimaryValue.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/cell/relation/RelationPrimaryValue.tsx @@ -1,5 +1,5 @@ import { FieldId, YDatabaseRow, YDoc, YjsDatabaseKey, YjsEditorKey } from '@/application/collab.type'; -import { parseYDatabaseCellToCell } from '@/components/database/components/cell/cell.parse'; +import { parseYDatabaseCellToCell } from '@/application/database-yjs/cell.parse'; import React, { useEffect, useState } from 'react'; export function RelationPrimaryValue({ rowDoc, fieldId }: { rowDoc: YDoc; fieldId: FieldId }) { diff --git a/frontend/appflowy_web_app/src/components/database/components/cell/select-option/SelectOptionCell.tsx b/frontend/appflowy_web_app/src/components/database/components/cell/select-option/SelectOptionCell.tsx index 4d3318297f..9538582f11 100644 --- a/frontend/appflowy_web_app/src/components/database/components/cell/select-option/SelectOptionCell.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/cell/select-option/SelectOptionCell.tsx @@ -1,7 +1,7 @@ import { useFieldSelector, parseSelectOptionTypeOptions } from '@/application/database-yjs'; import { Tag } from '@/components/_shared/tag'; import { SelectOptionColorMap } from '@/components/database/components/cell/cell.const'; -import { CellProps, SelectOptionCell as SelectOptionCellType } from '@/components/database/components/cell/cell.type'; +import { CellProps, SelectOptionCell as SelectOptionCellType } from '@/application/database-yjs/cell.type'; import React, { useCallback, useMemo } from 'react'; export function SelectOptionCell({ cell, fieldId, style, placeholder }: CellProps) { diff --git a/frontend/appflowy_web_app/src/components/database/components/cell/text/TextCell.tsx b/frontend/appflowy_web_app/src/components/database/components/cell/text/TextCell.tsx index b4d048b14f..4e78093c08 100644 --- a/frontend/appflowy_web_app/src/components/database/components/cell/text/TextCell.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/cell/text/TextCell.tsx @@ -1,5 +1,5 @@ import { useReadOnly } from '@/application/database-yjs'; -import { CellProps, TextCell as TextCellType } from '@/components/database/components/cell/cell.type'; +import { CellProps, TextCell as TextCellType } from '@/application/database-yjs/cell.type'; import React from 'react'; export function TextCell({ cell, style, placeholder }: CellProps) { diff --git a/frontend/appflowy_web_app/src/components/database/components/cell/url/UrlCell.tsx b/frontend/appflowy_web_app/src/components/database/components/cell/url/UrlCell.tsx index 0ee2c1d5bf..6a30c4c9d2 100644 --- a/frontend/appflowy_web_app/src/components/database/components/cell/url/UrlCell.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/cell/url/UrlCell.tsx @@ -1,5 +1,5 @@ import { useReadOnly } from '@/application/database-yjs'; -import { CellProps, UrlCell as UrlCellType } from '@/components/database/components/cell/cell.type'; +import { CellProps, UrlCell as UrlCellType } from '@/application/database-yjs/cell.type'; import { openUrl, processUrl } from '@/utils/url'; import React, { useMemo } from 'react'; diff --git a/frontend/appflowy_web_app/src/components/database/components/grid/grid-cell/GridCell.tsx b/frontend/appflowy_web_app/src/components/database/components/grid/grid-cell/GridCell.tsx index 0d3c7dfc11..5840109be7 100644 --- a/frontend/appflowy_web_app/src/components/database/components/grid/grid-cell/GridCell.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/grid/grid-cell/GridCell.tsx @@ -2,7 +2,7 @@ import { FieldId, YjsDatabaseKey } from '@/application/collab.type'; import { useCellSelector } from '@/application/database-yjs'; import { useFieldSelector } from '@/application/database-yjs/selector'; import { Cell } from '@/components/database/components/cell'; -import { CellProps, Cell as CellType } from '@/components/database/components/cell/cell.type'; +import { CellProps, Cell as CellType } from '@/application/database-yjs/cell.type'; import { PrimaryCell } from '@/components/database/components/cell/primary'; import React, { useEffect, useMemo, useRef } from 'react'; diff --git a/frontend/appflowy_web_app/src/components/database/components/grid/grid-row/useRenderRows.tsx b/frontend/appflowy_web_app/src/components/database/components/grid/grid-row/useRenderRows.tsx index 8b2e6597b8..b1de9ea0de 100644 --- a/frontend/appflowy_web_app/src/components/database/components/grid/grid-row/useRenderRows.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/grid/grid-row/useRenderRows.tsx @@ -1,4 +1,4 @@ -import { DEFAULT_ROW_HEIGHT, useReadOnly, useRowsSelector } from '@/application/database-yjs'; +import { DEFAULT_ROW_HEIGHT, useReadOnly, useRowOrdersSelector } from '@/application/database-yjs'; import { useMemo } from 'react'; @@ -15,16 +15,19 @@ export type RenderRow = { }; export function useRenderRows() { - const rows = useRowsSelector(); + const rows = useRowOrdersSelector(); const readOnly = useReadOnly(); const renderRows = useMemo(() => { - return [ - ...rows.map((row) => ({ + const rowItems = + rows?.map((row) => ({ type: RenderRowType.Row, rowId: row.id, height: row.height, - })), + })) ?? []; + + return [ + ...rowItems, !readOnly && { type: RenderRowType.NewRow, diff --git a/frontend/appflowy_web_app/src/components/database/components/property/Property.tsx b/frontend/appflowy_web_app/src/components/database/components/property/Property.tsx index b1e4662b2d..c8e5f34a43 100644 --- a/frontend/appflowy_web_app/src/components/database/components/property/Property.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/property/Property.tsx @@ -1,6 +1,6 @@ import { YjsDatabaseKey } from '@/application/collab.type'; import { FieldType, useCellSelector, useFieldSelector } from '@/application/database-yjs'; -import { Cell as CellType, CellProps } from '@/components/database/components/cell/cell.type'; +import { Cell as CellType, CellProps } from '@/application/database-yjs/cell.type'; import { CheckboxCell } from '@/components/database/components/cell/checkbox'; import { RowCreateModifiedTime } from '@/components/database/components/cell/created-modified'; import { DateTimeCell } from '@/components/database/components/cell/date'; diff --git a/frontend/appflowy_web_app/src/components/database/components/property/cheklist/ChecklistProperty.tsx b/frontend/appflowy_web_app/src/components/database/components/property/cheklist/ChecklistProperty.tsx index fabe862659..a8ed3ae2e7 100644 --- a/frontend/appflowy_web_app/src/components/database/components/property/cheklist/ChecklistProperty.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/property/cheklist/ChecklistProperty.tsx @@ -1,5 +1,5 @@ import { parseChecklistData } from '@/application/database-yjs'; -import { CellProps, ChecklistCell as CellType } from '@/components/database/components/cell/cell.type'; +import { CellProps, ChecklistCell as CellType } from '@/application/database-yjs/cell.type'; import { ChecklistCell } from '@/components/database/components/cell/checklist'; import React, { useMemo } from 'react'; import { ReactComponent as CheckboxCheckSvg } from '$icons/16x/check_filled.svg'; diff --git a/frontend/appflowy_web_app/src/components/database/components/property/text/TextProperty.tsx b/frontend/appflowy_web_app/src/components/database/components/property/text/TextProperty.tsx index 64589c0ea3..99b54b08a7 100644 --- a/frontend/appflowy_web_app/src/components/database/components/property/text/TextProperty.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/property/text/TextProperty.tsx @@ -1,4 +1,4 @@ -import { CellProps, TextCell } from '@/components/database/components/cell/cell.type'; +import { CellProps, TextCell } from '@/application/database-yjs/cell.type'; import { TextField } from '@mui/material'; import React from 'react'; diff --git a/frontend/appflowy_web_app/src/components/database/grid/Grid.tsx b/frontend/appflowy_web_app/src/components/database/grid/Grid.tsx index 521fa1cac0..15aaa23e51 100644 --- a/frontend/appflowy_web_app/src/components/database/grid/Grid.tsx +++ b/frontend/appflowy_web_app/src/components/database/grid/Grid.tsx @@ -1,4 +1,4 @@ -import { RowsContext, useDatabase, useRowOrdersSelector, useViewId } from '@/application/database-yjs'; +import { useDatabase, useViewId } from '@/application/database-yjs'; import { useRenderFields, GridHeader, GridTable } from '@/components/database/components/grid'; import { CircularProgress } from '@mui/material'; import React, { useEffect, useState } from 'react'; @@ -9,13 +9,12 @@ export function Grid() { const [scrollLeft, setScrollLeft] = useState(0); const { fields, columnWidth } = useRenderFields(); - const rowOrders = useRowOrdersSelector(); useEffect(() => { setScrollLeft(0); }, [viewId]); - if (!database || !rowOrders) { + if (!database) { return (
@@ -24,24 +23,18 @@ export function Grid() { } return ( - -
- -
- -
+
+ +
+
- +
); } diff --git a/frontend/appflowy_web_app/src/utils/font.ts b/frontend/appflowy_web_app/src/utils/font.ts index 765ebf5f00..645340d958 100644 --- a/frontend/appflowy_web_app/src/utils/font.ts +++ b/frontend/appflowy_web_app/src/utils/font.ts @@ -1,3 +1,16 @@ +const hasLoadedFonts: Set = new Set(); + export function getFontFamily(attribute: string) { - return attribute.split('_')[0]; + const fontFamily = attribute.split('_')[0]; + + if (hasLoadedFonts.has(fontFamily)) { + return fontFamily; + } + + window.WebFont?.load({ + google: { + families: [fontFamily], + }, + }); + return fontFamily; } diff --git a/frontend/appflowy_web_app/vite.config.ts b/frontend/appflowy_web_app/vite.config.ts index aeadc4e8fa..bc69405ca3 100644 --- a/frontend/appflowy_web_app/vite.config.ts +++ b/frontend/appflowy_web_app/vite.config.ts @@ -44,6 +44,13 @@ export default defineConfig({ istanbul({ cypress: true, requireEnv: false, + include: ['src/**/*'], + exclude: [ + '**/__tests__/**/*', + 'cypress/**/*', + 'node_modules/**/*', + 'src/application/services/tauri-services/**/*', + ], }), usePluginImport({ libraryName: '@mui/icons-material', @@ -130,6 +137,12 @@ export default defineConfig({ }, optimizeDeps: { - include: ['react', 'react-dom', '@mui/icons-material/ErrorOutline', '@mui/icons-material/CheckCircleOutline'], + include: [ + 'react', + 'react-dom', + '@mui/icons-material/ErrorOutline', + '@mui/icons-material/CheckCircleOutline', + '@mui/icons-material/FunctionsOutlined', + ], }, }); From b794f3894ef14de6a5298bc7948b828a5d60d1b3 Mon Sep 17 00:00:00 2001 From: "Kilu.He" <108015703+qinluhe@users.noreply.github.com> Date: Thu, 6 Jun 2024 19:47:14 +0800 Subject: [PATCH 10/16] chore: improve coverage of cypress (#5483) --- .../87bc006e-c1eb-47fd-9ac6-e39b17956369.json | 1 + .../cypress/fixtures/database/databases.json | 81 +++++++++++- .../87bc006e-c1eb-47fd-9ac6-e39b17956369.json | 1 + .../cypress/fixtures/folder.json | 2 +- .../cypress/support/component.ts | 24 ++++ .../src/application/folder-yjs/context.ts | 13 +- .../services/js-services/storage/collab.ts | 1 + .../src/components/database/Database.cy.tsx | 123 ------------------ .../database/__tests__/Database.cy.tsx | 40 ++++++ .../{ => __tests__}/DatabaseRow.cy.tsx | 4 +- .../__tests__/DatabaseWithFilter.cy.tsx | 99 ++++++++++++++ .../__tests__/withTestingDatabase.tsx | 106 +++++++++++++++ .../components/conditions/DatabaseActions.tsx | 2 + .../field/select-option/SelectOptionList.tsx | 9 +- .../database/components/filters/Filter.tsx | 2 + .../filters/filter-menu/FieldMenuTitle.tsx | 5 +- .../filters/filter-menu/NumberFilterMenu.tsx | 1 + .../filters/filter-menu/TextFilterMenu.tsx | 3 +- .../database/components/sorts/Sort.tsx | 2 +- .../database/components/sorts/Sorts.tsx | 1 + .../src/components/layout/Layout.hooks.ts | 2 +- .../src/components/layout/breadcrumb/Item.tsx | 27 +++- frontend/appflowy_web_app/vite.config.ts | 6 +- 23 files changed, 408 insertions(+), 147 deletions(-) create mode 100644 frontend/appflowy_web_app/cypress/fixtures/database/87bc006e-c1eb-47fd-9ac6-e39b17956369.json create mode 100644 frontend/appflowy_web_app/cypress/fixtures/database/rows/87bc006e-c1eb-47fd-9ac6-e39b17956369.json delete mode 100644 frontend/appflowy_web_app/src/components/database/Database.cy.tsx create mode 100644 frontend/appflowy_web_app/src/components/database/__tests__/Database.cy.tsx rename frontend/appflowy_web_app/src/components/database/{ => __tests__}/DatabaseRow.cy.tsx (95%) create mode 100644 frontend/appflowy_web_app/src/components/database/__tests__/DatabaseWithFilter.cy.tsx create mode 100644 frontend/appflowy_web_app/src/components/database/__tests__/withTestingDatabase.tsx diff --git a/frontend/appflowy_web_app/cypress/fixtures/database/87bc006e-c1eb-47fd-9ac6-e39b17956369.json b/frontend/appflowy_web_app/cypress/fixtures/database/87bc006e-c1eb-47fd-9ac6-e39b17956369.json new file mode 100644 index 0000000000..474a10765c --- /dev/null +++ b/frontend/appflowy_web_app/cypress/fixtures/database/87bc006e-c1eb-47fd-9ac6-e39b17956369.json @@ -0,0 +1 @@ +{"data":{"state_vector":[2,144,224,143,199,14,16,201,175,140,129,8,161,6],"doc_state":[2,2,144,224,143,199,14,0,33,1,4,109,101,116,97,12,108,97,115,116,95,115,121,110,99,95,97,116,15,168,144,224,143,199,14,14,1,122,0,0,0,0,102,97,139,106,230,3,201,175,140,129,8,0,39,1,4,100,97,116,97,8,100,97,116,97,98,97,115,101,1,40,0,201,175,140,129,8,0,2,105,100,1,119,36,56,55,98,99,48,48,54,101,45,99,49,101,98,45,52,55,102,100,45,57,97,99,54,45,101,51,57,98,49,55,57,53,54,51,54,57,39,0,201,175,140,129,8,0,6,102,105,101,108,100,115,1,39,0,201,175,140,129,8,0,5,118,105,101,119,115,1,39,0,201,175,140,129,8,0,5,109,101,116,97,115,1,40,0,201,175,140,129,8,4,3,105,105,100,1,119,36,55,102,50,51,51,98,101,52,45,49,98,52,100,45,52,54,98,50,45,98,99,102,99,45,102,51,52,49,98,56,100,55,53,50,54,55,39,0,201,175,140,129,8,2,6,77,67,57,90,97,69,1,40,0,201,175,140,129,8,6,2,105,100,1,119,6,77,67,57,90,97,69,40,0,201,175,140,129,8,6,4,110,97,109,101,1,119,4,78,97,109,101,40,0,201,175,140,129,8,6,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,115,63,40,0,201,175,140,129,8,6,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,122,0,0,0,0,102,97,115,63,40,0,201,175,140,129,8,6,10,105,115,95,112,114,105,109,97,114,121,1,120,40,0,201,175,140,129,8,6,2,116,121,1,122,0,0,0,0,0,0,0,0,39,0,201,175,140,129,8,6,11,116,121,112,101,95,111,112,116,105,111,110,1,39,0,201,175,140,129,8,13,1,48,1,40,0,201,175,140,129,8,14,4,100,97,116,97,1,119,0,39,0,201,175,140,129,8,2,6,53,69,90,81,65,87,1,40,0,201,175,140,129,8,16,2,105,100,1,119,6,53,69,90,81,65,87,40,0,201,175,140,129,8,16,4,110,97,109,101,1,119,4,84,121,112,101,40,0,201,175,140,129,8,16,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,115,63,33,0,201,175,140,129,8,16,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,40,0,201,175,140,129,8,16,10,105,115,95,112,114,105,109,97,114,121,1,121,40,0,201,175,140,129,8,16,2,116,121,1,122,0,0,0,0,0,0,0,3,39,0,201,175,140,129,8,16,11,116,121,112,101,95,111,112,116,105,111,110,1,39,0,201,175,140,129,8,23,1,51,1,33,0,201,175,140,129,8,24,7,99,111,110,116,101,110,116,1,39,0,201,175,140,129,8,2,6,108,73,72,113,101,57,1,40,0,201,175,140,129,8,26,2,105,100,1,119,6,108,73,72,113,101,57,40,0,201,175,140,129,8,26,4,110,97,109,101,1,119,4,68,111,110,101,40,0,201,175,140,129,8,26,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,115,63,40,0,201,175,140,129,8,26,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,122,0,0,0,0,102,97,115,63,40,0,201,175,140,129,8,26,10,105,115,95,112,114,105,109,97,114,121,1,121,40,0,201,175,140,129,8,26,2,116,121,1,122,0,0,0,0,0,0,0,5,39,0,201,175,140,129,8,26,11,116,121,112,101,95,111,112,116,105,111,110,1,39,0,201,175,140,129,8,33,1,53,1,39,0,201,175,140,129,8,3,36,55,102,50,51,51,98,101,52,45,49,98,52,100,45,52,54,98,50,45,98,99,102,99,45,102,51,52,49,98,56,100,55,53,50,54,55,1,40,0,201,175,140,129,8,35,2,105,100,1,119,36,55,102,50,51,51,98,101,52,45,49,98,52,100,45,52,54,98,50,45,98,99,102,99,45,102,51,52,49,98,56,100,55,53,50,54,55,40,0,201,175,140,129,8,35,11,100,97,116,97,98,97,115,101,95,105,100,1,119,36,56,55,98,99,48,48,54,101,45,99,49,101,98,45,52,55,102,100,45,57,97,99,54,45,101,51,57,98,49,55,57,53,54,51,54,57,40,0,201,175,140,129,8,35,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,201,175,140,129,8,35,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,115,63,33,0,201,175,140,129,8,35,11,109,111,100,105,102,105,101,100,95,97,116,1,39,0,201,175,140,129,8,35,15,108,97,121,111,117,116,95,115,101,116,116,105,110,103,115,1,40,0,201,175,140,129,8,35,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,39,0,201,175,140,129,8,35,14,102,105,101,108,100,95,115,101,116,116,105,110,103,115,1,39,0,201,175,140,129,8,43,6,108,73,72,113,101,57,1,40,0,201,175,140,129,8,44,4,119,114,97,112,1,120,40,0,201,175,140,129,8,44,10,118,105,115,105,98,105,108,105,116,121,1,122,0,0,0,0,0,0,0,0,40,0,201,175,140,129,8,44,5,119,105,100,116,104,1,122,0,0,0,0,0,0,0,150,39,0,201,175,140,129,8,43,6,77,67,57,90,97,69,1,40,0,201,175,140,129,8,48,5,119,105,100,116,104,1,122,0,0,0,0,0,0,0,150,40,0,201,175,140,129,8,48,4,119,114,97,112,1,120,40,0,201,175,140,129,8,48,10,118,105,115,105,98,105,108,105,116,121,1,122,0,0,0,0,0,0,0,0,39,0,201,175,140,129,8,43,6,53,69,90,81,65,87,1,40,0,201,175,140,129,8,52,4,119,114,97,112,1,120,40,0,201,175,140,129,8,52,5,119,105,100,116,104,1,122,0,0,0,0,0,0,0,150,40,0,201,175,140,129,8,52,10,118,105,115,105,98,105,108,105,116,121,1,122,0,0,0,0,0,0,0,0,39,0,201,175,140,129,8,35,7,102,105,108,116,101,114,115,0,39,0,201,175,140,129,8,35,6,103,114,111,117,112,115,0,39,0,201,175,140,129,8,35,5,115,111,114,116,115,0,39,0,201,175,140,129,8,35,12,102,105,101,108,100,95,111,114,100,101,114,115,0,8,0,201,175,140,129,8,59,3,118,1,2,105,100,119,6,77,67,57,90,97,69,118,1,2,105,100,119,6,53,69,90,81,65,87,118,1,2,105,100,119,6,108,73,72,113,101,57,39,0,201,175,140,129,8,35,10,114,111,119,95,111,114,100,101,114,115,0,8,0,201,175,140,129,8,63,3,118,2,2,105,100,119,36,49,49,49,49,98,49,52,54,45,52,99,54,99,45,52,102,99,54,45,57,53,101,49,45,55,48,99,50,52,54,49,52,55,102,56,102,6,104,101,105,103,104,116,125,60,118,2,2,105,100,119,36,51,101,99,55,98,55,54,99,45,54,56,99,57,45,52,50,55,57,45,57,98,51,51,45,50,51,54,53,51,50,49,101,97,102,52,49,6,104,101,105,103,104,116,125,60,118,2,6,104,101,105,103,104,116,125,60,2,105,100,119,36,57,99,100,101,55,99,49,53,45,51,52,55,99,45,52,52,55,97,45,57,101,97,49,45,55,54,98,99,51,97,56,100,52,101,57,54,161,201,175,140,129,8,40,1,136,201,175,140,129,8,62,1,118,1,2,105,100,119,6,111,121,80,121,97,117,39,0,201,175,140,129,8,43,6,111,121,80,121,97,117,1,40,0,201,175,140,129,8,69,10,118,105,115,105,98,105,108,105,116,121,1,122,0,0,0,0,0,0,0,0,39,0,201,175,140,129,8,2,6,111,121,80,121,97,117,1,40,0,201,175,140,129,8,71,2,105,100,1,119,6,111,121,80,121,97,117,33,0,201,175,140,129,8,71,4,110,97,109,101,1,40,0,201,175,140,129,8,71,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,115,77,33,0,201,175,140,129,8,71,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,40,0,201,175,140,129,8,71,10,105,115,95,112,114,105,109,97,114,121,1,121,33,0,201,175,140,129,8,71,2,116,121,1,39,0,201,175,140,129,8,71,11,116,121,112,101,95,111,112,116,105,111,110,1,39,0,201,175,140,129,8,78,1,48,1,40,0,201,175,140,129,8,79,4,100,97,116,97,1,119,0,161,201,175,140,129,8,75,1,168,201,175,140,129,8,77,1,122,0,0,0,0,0,0,0,1,39,0,201,175,140,129,8,78,1,49,1,40,0,201,175,140,129,8,83,6,115,121,109,98,111,108,1,119,3,82,85,66,40,0,201,175,140,129,8,83,6,102,111,114,109,97,116,1,122,0,0,0,0,0,0,0,0,40,0,201,175,140,129,8,83,5,115,99,97,108,101,1,122,0,0,0,0,0,0,0,0,40,0,201,175,140,129,8,83,4,110,97,109,101,1,119,6,78,117,109,98,101,114,161,201,175,140,129,8,81,1,40,0,201,175,140,129,8,79,6,102,111,114,109,97,116,1,122,0,0,0,0,0,0,0,0,40,0,201,175,140,129,8,79,5,115,99,97,108,101,1,122,0,0,0,0,0,0,0,0,40,0,201,175,140,129,8,79,6,115,121,109,98,111,108,1,119,3,82,85,66,40,0,201,175,140,129,8,79,4,110,97,109,101,1,119,6,78,117,109,98,101,114,161,201,175,140,129,8,67,2,136,201,175,140,129,8,68,1,118,1,2,105,100,119,6,102,116,73,53,52,121,39,0,201,175,140,129,8,43,6,102,116,73,53,52,121,1,40,0,201,175,140,129,8,96,10,118,105,115,105,98,105,108,105,116,121,1,122,0,0,0,0,0,0,0,0,39,0,201,175,140,129,8,2,6,102,116,73,53,52,121,1,40,0,201,175,140,129,8,98,2,105,100,1,119,6,102,116,73,53,52,121,33,0,201,175,140,129,8,98,4,110,97,109,101,1,40,0,201,175,140,129,8,98,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,115,82,33,0,201,175,140,129,8,98,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,40,0,201,175,140,129,8,98,10,105,115,95,112,114,105,109,97,114,121,1,121,33,0,201,175,140,129,8,98,2,116,121,1,39,0,201,175,140,129,8,98,11,116,121,112,101,95,111,112,116,105,111,110,1,39,0,201,175,140,129,8,105,1,48,1,40,0,201,175,140,129,8,106,4,100,97,116,97,1,119,0,161,201,175,140,129,8,102,1,168,201,175,140,129,8,104,1,122,0,0,0,0,0,0,0,4,39,0,201,175,140,129,8,105,1,52,1,33,0,201,175,140,129,8,110,7,99,111,110,116,101,110,116,1,161,201,175,140,129,8,108,1,40,0,201,175,140,129,8,106,7,99,111,110,116,101,110,116,1,119,36,123,34,111,112,116,105,111,110,115,34,58,91,93,44,34,100,105,115,97,98,108,101,95,99,111,108,111,114,34,58,102,97,108,115,101,125,161,201,175,140,129,8,94,1,161,201,175,140,129,8,112,1,161,201,175,140,129,8,111,1,161,201,175,140,129,8,115,1,168,201,175,140,129,8,116,1,119,131,1,123,34,111,112,116,105,111,110,115,34,58,91,123,34,105,100,34,58,34,104,57,106,100,34,44,34,110,97,109,101,34,58,34,111,112,116,105,111,110,45,50,34,44,34,99,111,108,111,114,34,58,34,80,105,110,107,34,125,44,123,34,105,100,34,58,34,111,95,66,104,34,44,34,110,97,109,101,34,58,34,111,112,116,105,111,110,45,49,34,44,34,99,111,108,111,114,34,58,34,80,117,114,112,108,101,34,125,93,44,34,100,105,115,97,98,108,101,95,99,111,108,111,114,34,58,102,97,108,115,101,125,161,201,175,140,129,8,20,1,161,201,175,140,129,8,25,1,168,201,175,140,129,8,119,1,122,0,0,0,0,102,97,115,111,168,201,175,140,129,8,120,1,119,145,1,123,34,111,112,116,105,111,110,115,34,58,91,123,34,105,100,34,58,34,71,102,87,50,34,44,34,110,97,109,101,34,58,34,115,105,110,103,108,101,45,111,112,116,105,111,110,45,50,34,44,34,99,111,108,111,114,34,58,34,80,105,110,107,34,125,44,123,34,105,100,34,58,34,111,102,70,102,34,44,34,110,97,109,101,34,58,34,115,105,110,103,108,101,45,111,112,116,105,111,110,45,49,34,44,34,99,111,108,111,114,34,58,34,80,117,114,112,108,101,34,125,93,44,34,100,105,115,97,98,108,101,95,99,111,108,111,114,34,58,102,97,108,115,101,125,161,201,175,140,129,8,88,1,161,201,175,140,129,8,73,1,161,201,175,140,129,8,123,1,161,201,175,140,129,8,124,1,161,201,175,140,129,8,125,1,161,201,175,140,129,8,126,1,161,201,175,140,129,8,127,1,161,201,175,140,129,8,128,1,1,161,201,175,140,129,8,129,1,1,161,201,175,140,129,8,130,1,1,168,201,175,140,129,8,131,1,1,122,0,0,0,0,102,97,115,117,168,201,175,140,129,8,132,1,1,119,6,110,117,109,98,101,114,161,201,175,140,129,8,117,1,161,201,175,140,129,8,100,1,161,201,175,140,129,8,135,1,1,161,201,175,140,129,8,136,1,1,161,201,175,140,129,8,137,1,1,161,201,175,140,129,8,138,1,1,161,201,175,140,129,8,139,1,1,161,201,175,140,129,8,140,1,1,161,201,175,140,129,8,141,1,1,161,201,175,140,129,8,142,1,1,161,201,175,140,129,8,143,1,1,161,201,175,140,129,8,144,1,1,161,201,175,140,129,8,145,1,1,161,201,175,140,129,8,146,1,1,161,201,175,140,129,8,147,1,1,161,201,175,140,129,8,148,1,1,161,201,175,140,129,8,149,1,1,161,201,175,140,129,8,150,1,1,168,201,175,140,129,8,151,1,1,122,0,0,0,0,102,97,115,124,168,201,175,140,129,8,152,1,1,119,10,109,117,108,116,105,32,116,121,112,101,161,201,175,140,129,8,114,1,136,201,175,140,129,8,95,1,118,1,2,105,100,119,6,87,120,110,102,109,110,39,0,201,175,140,129,8,43,6,87,120,110,102,109,110,1,40,0,201,175,140,129,8,157,1,10,118,105,115,105,98,105,108,105,116,121,1,122,0,0,0,0,0,0,0,0,39,0,201,175,140,129,8,2,6,87,120,110,102,109,110,1,40,0,201,175,140,129,8,159,1,2,105,100,1,119,6,87,120,110,102,109,110,33,0,201,175,140,129,8,159,1,4,110,97,109,101,1,40,0,201,175,140,129,8,159,1,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,115,126,33,0,201,175,140,129,8,159,1,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,40,0,201,175,140,129,8,159,1,10,105,115,95,112,114,105,109,97,114,121,1,121,33,0,201,175,140,129,8,159,1,2,116,121,1,39,0,201,175,140,129,8,159,1,11,116,121,112,101,95,111,112,116,105,111,110,1,39,0,201,175,140,129,8,166,1,1,48,1,40,0,201,175,140,129,8,167,1,4,100,97,116,97,1,119,0,161,201,175,140,129,8,163,1,1,168,201,175,140,129,8,165,1,1,122,0,0,0,0,0,0,0,2,39,0,201,175,140,129,8,166,1,1,50,1,40,0,201,175,140,129,8,171,1,11,116,105,109,101,122,111,110,101,95,105,100,1,119,0,40,0,201,175,140,129,8,171,1,11,100,97,116,101,95,102,111,114,109,97,116,1,122,0,0,0,0,0,0,0,3,40,0,201,175,140,129,8,171,1,11,116,105,109,101,95,102,111,114,109,97,116,1,122,0,0,0,0,0,0,0,1,161,201,175,140,129,8,169,1,1,40,0,201,175,140,129,8,167,1,11,116,105,109,101,95,102,111,114,109,97,116,1,122,0,0,0,0,0,0,0,1,40,0,201,175,140,129,8,167,1,11,100,97,116,101,95,102,111,114,109,97,116,1,122,0,0,0,0,0,0,0,3,40,0,201,175,140,129,8,167,1,11,116,105,109,101,122,111,110,101,95,105,100,1,119,0,161,201,175,140,129,8,155,1,1,161,201,175,140,129,8,175,1,1,161,201,175,140,129,8,161,1,1,161,201,175,140,129,8,180,1,1,161,201,175,140,129,8,181,1,1,161,201,175,140,129,8,182,1,1,161,201,175,140,129,8,183,1,1,161,201,175,140,129,8,184,1,1,161,201,175,140,129,8,185,1,1,161,201,175,140,129,8,186,1,1,161,201,175,140,129,8,187,1,1,161,201,175,140,129,8,188,1,1,161,201,175,140,129,8,189,1,1,161,201,175,140,129,8,190,1,1,161,201,175,140,129,8,191,1,1,168,201,175,140,129,8,192,1,1,122,0,0,0,0,102,97,115,132,168,201,175,140,129,8,193,1,1,119,4,68,97,116,101,161,201,175,140,129,8,179,1,1,129,201,175,140,129,8,156,1,1,33,0,201,175,140,129,8,43,6,67,108,105,104,117,89,1,0,1,33,0,201,175,140,129,8,2,6,67,108,105,104,117,89,1,0,36,161,201,175,140,129,8,196,1,1,136,201,175,140,129,8,197,1,1,118,1,2,105,100,119,6,84,79,87,83,70,104,39,0,201,175,140,129,8,43,6,84,79,87,83,70,104,1,40,0,201,175,140,129,8,239,1,10,118,105,115,105,98,105,108,105,116,121,1,122,0,0,0,0,0,0,0,0,39,0,201,175,140,129,8,2,6,84,79,87,83,70,104,1,40,0,201,175,140,129,8,241,1,2,105,100,1,119,6,84,79,87,83,70,104,33,0,201,175,140,129,8,241,1,4,110,97,109,101,1,40,0,201,175,140,129,8,241,1,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,115,147,33,0,201,175,140,129,8,241,1,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,40,0,201,175,140,129,8,241,1,10,105,115,95,112,114,105,109,97,114,121,1,121,33,0,201,175,140,129,8,241,1,2,116,121,1,39,0,201,175,140,129,8,241,1,11,116,121,112,101,95,111,112,116,105,111,110,1,39,0,201,175,140,129,8,248,1,1,48,1,40,0,201,175,140,129,8,249,1,4,100,97,116,97,1,119,0,161,201,175,140,129,8,245,1,1,168,201,175,140,129,8,247,1,1,122,0,0,0,0,0,0,0,7,39,0,201,175,140,129,8,248,1,1,55,1,161,201,175,140,129,8,237,1,1,136,201,175,140,129,8,238,1,1,118,1,2,105,100,119,6,45,81,77,51,70,50,39,0,201,175,140,129,8,43,6,45,81,77,51,70,50,1,40,0,201,175,140,129,8,128,2,10,118,105,115,105,98,105,108,105,116,121,1,122,0,0,0,0,0,0,0,0,39,0,201,175,140,129,8,2,6,45,81,77,51,70,50,1,40,0,201,175,140,129,8,130,2,2,105,100,1,119,6,45,81,77,51,70,50,33,0,201,175,140,129,8,130,2,4,110,97,109,101,1,40,0,201,175,140,129,8,130,2,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,115,154,33,0,201,175,140,129,8,130,2,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,40,0,201,175,140,129,8,130,2,10,105,115,95,112,114,105,109,97,114,121,1,121,33,0,201,175,140,129,8,130,2,2,116,121,1,39,0,201,175,140,129,8,130,2,11,116,121,112,101,95,111,112,116,105,111,110,1,39,0,201,175,140,129,8,137,2,1,48,1,40,0,201,175,140,129,8,138,2,4,100,97,116,97,1,119,0,161,201,175,140,129,8,134,2,1,168,201,175,140,129,8,136,2,1,122,0,0,0,0,0,0,0,6,39,0,201,175,140,129,8,137,2,1,54,1,40,0,201,175,140,129,8,142,2,7,99,111,110,116,101,110,116,1,119,0,40,0,201,175,140,129,8,142,2,3,117,114,108,1,119,0,161,201,175,140,129,8,140,2,1,40,0,201,175,140,129,8,138,2,3,117,114,108,1,119,0,40,0,201,175,140,129,8,138,2,7,99,111,110,116,101,110,116,1,119,0,161,201,175,140,129,8,254,1,1,161,201,175,140,129,8,145,2,1,161,201,175,140,129,8,132,2,1,161,201,175,140,129,8,149,2,1,161,201,175,140,129,8,150,2,1,161,201,175,140,129,8,151,2,1,161,201,175,140,129,8,152,2,1,161,201,175,140,129,8,153,2,1,161,201,175,140,129,8,154,2,1,161,201,175,140,129,8,155,2,1,161,201,175,140,129,8,156,2,1,161,201,175,140,129,8,157,2,1,161,201,175,140,129,8,158,2,1,168,201,175,140,129,8,159,2,1,122,0,0,0,0,102,97,115,160,168,201,175,140,129,8,160,2,1,119,3,117,114,108,161,201,175,140,129,8,251,1,1,161,201,175,140,129,8,243,1,1,161,201,175,140,129,8,163,2,1,161,201,175,140,129,8,164,2,1,161,201,175,140,129,8,165,2,1,161,201,175,140,129,8,166,2,1,161,201,175,140,129,8,167,2,1,161,201,175,140,129,8,168,2,1,161,201,175,140,129,8,169,2,1,161,201,175,140,129,8,170,2,1,161,201,175,140,129,8,171,2,1,161,201,175,140,129,8,172,2,1,161,201,175,140,129,8,173,2,1,161,201,175,140,129,8,174,2,1,161,201,175,140,129,8,175,2,1,161,201,175,140,129,8,176,2,1,168,201,175,140,129,8,177,2,1,122,0,0,0,0,102,97,115,164,168,201,175,140,129,8,178,2,1,119,9,67,104,101,99,107,108,105,115,116,161,201,175,140,129,8,148,2,1,129,201,175,140,129,8,255,1,1,33,0,201,175,140,129,8,43,6,121,53,95,75,84,100,1,0,1,33,0,201,175,140,129,8,2,6,121,53,95,75,84,100,1,0,9,161,201,175,140,129,8,181,2,3,1,0,201,175,140,129,8,56,1,0,6,161,201,175,140,129,8,197,2,1,129,201,175,140,129,8,198,2,1,0,6,161,201,175,140,129,8,205,2,1,129,201,175,140,129,8,206,2,1,0,6,161,201,175,140,129,8,213,2,1,129,201,175,140,129,8,214,2,1,0,6,129,201,175,140,129,8,222,2,1,0,6,161,201,175,140,129,8,221,2,1,129,201,175,140,129,8,229,2,1,0,6,129,201,175,140,129,8,237,2,1,0,6,161,201,175,140,129,8,236,2,1,129,201,175,140,129,8,244,2,1,0,6,129,201,175,140,129,8,252,2,1,0,6,129,201,175,140,129,8,131,3,1,0,6,161,201,175,140,129,8,251,2,2,129,201,175,140,129,8,138,3,1,0,6,129,201,175,140,129,8,147,3,1,0,6,129,201,175,140,129,8,154,3,1,0,6,161,201,175,140,129,8,146,3,1,129,201,175,140,129,8,161,3,1,0,6,129,201,175,140,129,8,169,3,1,0,6,129,201,175,140,129,8,176,3,1,0,6,129,201,175,140,129,8,183,3,1,0,6,161,201,175,140,129,8,168,3,1,129,201,175,140,129,8,190,3,1,0,6,129,201,175,140,129,8,198,3,1,0,6,129,201,175,140,129,8,205,3,1,0,6,129,201,175,140,129,8,212,3,1,0,6,161,201,175,140,129,8,197,3,1,129,201,175,140,129,8,219,3,1,0,6,129,201,175,140,129,8,227,3,1,0,6,129,201,175,140,129,8,234,3,1,0,6,129,201,175,140,129,8,241,3,1,0,6,161,201,175,140,129,8,226,3,1,129,201,175,140,129,8,248,3,1,0,6,129,201,175,140,129,8,128,4,1,0,6,129,201,175,140,129,8,135,4,1,0,6,129,201,175,140,129,8,142,4,1,0,6,161,201,175,140,129,8,255,3,1,129,201,175,140,129,8,149,4,1,0,6,129,201,175,140,129,8,157,4,1,0,6,129,201,175,140,129,8,164,4,1,0,6,129,201,175,140,129,8,171,4,1,0,6,129,201,175,140,129,8,178,4,1,0,6,161,201,175,140,129,8,156,4,1,129,201,175,140,129,8,185,4,1,0,6,129,201,175,140,129,8,193,4,1,0,6,129,201,175,140,129,8,200,4,1,0,6,129,201,175,140,129,8,207,4,1,0,6,129,201,175,140,129,8,214,4,1,0,6,161,201,175,140,129,8,192,4,1,129,201,175,140,129,8,221,4,1,0,6,129,201,175,140,129,8,229,4,1,0,6,129,201,175,140,129,8,236,4,1,0,6,129,201,175,140,129,8,243,4,1,0,6,129,201,175,140,129,8,250,4,1,0,6,161,201,175,140,129,8,228,4,1,129,201,175,140,129,8,129,5,1,0,6,129,201,175,140,129,8,137,5,1,0,6,129,201,175,140,129,8,144,5,1,0,6,129,201,175,140,129,8,151,5,1,0,6,129,201,175,140,129,8,158,5,1,0,6,129,201,175,140,129,8,165,5,1,0,6,161,201,175,140,129,8,136,5,1,135,201,175,140,129,8,172,5,1,40,0,201,175,140,129,8,180,5,2,105,100,1,119,6,112,85,95,77,67,70,40,0,201,175,140,129,8,180,5,7,99,111,110,116,101,110,116,1,119,3,49,50,51,40,0,201,175,140,129,8,180,5,8,102,105,101,108,100,95,105,100,1,119,6,77,67,57,90,97,69,40,0,201,175,140,129,8,180,5,2,116,121,1,122,0,0,0,0,0,0,0,0,40,0,201,175,140,129,8,180,5,11,102,105,108,116,101,114,95,116,121,112,101,1,122,0,0,0,0,0,0,0,2,40,0,201,175,140,129,8,180,5,9,99,111,110,100,105,116,105,111,110,1,122,0,0,0,0,0,0,0,2,135,201,175,140,129,8,180,5,1,40,0,201,175,140,129,8,187,5,2,105,100,1,119,6,115,120,80,56,104,79,40,0,201,175,140,129,8,187,5,11,102,105,108,116,101,114,95,116,121,112,101,1,122,0,0,0,0,0,0,0,2,40,0,201,175,140,129,8,187,5,2,116,121,1,122,0,0,0,0,0,0,0,3,40,0,201,175,140,129,8,187,5,9,99,111,110,100,105,116,105,111,110,1,122,0,0,0,0,0,0,0,5,40,0,201,175,140,129,8,187,5,8,102,105,101,108,100,95,105,100,1,119,6,53,69,90,81,65,87,40,0,201,175,140,129,8,187,5,7,99,111,110,116,101,110,116,1,119,0,135,201,175,140,129,8,187,5,1,40,0,201,175,140,129,8,194,5,2,105,100,1,119,6,90,76,109,68,81,87,40,0,201,175,140,129,8,194,5,8,102,105,101,108,100,95,105,100,1,119,6,108,73,72,113,101,57,40,0,201,175,140,129,8,194,5,11,102,105,108,116,101,114,95,116,121,112,101,1,122,0,0,0,0,0,0,0,2,40,0,201,175,140,129,8,194,5,2,116,121,1,122,0,0,0,0,0,0,0,5,40,0,201,175,140,129,8,194,5,9,99,111,110,100,105,116,105,111,110,1,122,0,0,0,0,0,0,0,0,40,0,201,175,140,129,8,194,5,7,99,111,110,116,101,110,116,1,119,0,135,201,175,140,129,8,194,5,1,40,0,201,175,140,129,8,201,5,7,99,111,110,116,101,110,116,1,119,3,54,48,48,40,0,201,175,140,129,8,201,5,2,105,100,1,119,6,108,52,83,54,119,71,40,0,201,175,140,129,8,201,5,11,102,105,108,116,101,114,95,116,121,112,101,1,122,0,0,0,0,0,0,0,2,40,0,201,175,140,129,8,201,5,8,102,105,101,108,100,95,105,100,1,119,6,111,121,80,121,97,117,40,0,201,175,140,129,8,201,5,9,99,111,110,100,105,116,105,111,110,1,122,0,0,0,0,0,0,0,2,40,0,201,175,140,129,8,201,5,2,116,121,1,122,0,0,0,0,0,0,0,1,135,201,175,140,129,8,201,5,1,40,0,201,175,140,129,8,208,5,11,102,105,108,116,101,114,95,116,121,112,101,1,122,0,0,0,0,0,0,0,2,40,0,201,175,140,129,8,208,5,9,99,111,110,100,105,116,105,111,110,1,122,0,0,0,0,0,0,0,3,40,0,201,175,140,129,8,208,5,2,116,121,1,122,0,0,0,0,0,0,0,4,40,0,201,175,140,129,8,208,5,7,99,111,110,116,101,110,116,1,119,4,111,95,66,104,40,0,201,175,140,129,8,208,5,2,105,100,1,119,6,103,108,89,79,49,55,40,0,201,175,140,129,8,208,5,8,102,105,101,108,100,95,105,100,1,119,6,102,116,73,53,52,121,135,201,175,140,129,8,208,5,1,40,0,201,175,140,129,8,215,5,11,102,105,108,116,101,114,95,116,121,112,101,1,122,0,0,0,0,0,0,0,2,40,0,201,175,140,129,8,215,5,8,102,105,101,108,100,95,105,100,1,119,6,84,79,87,83,70,104,40,0,201,175,140,129,8,215,5,2,116,121,1,122,0,0,0,0,0,0,0,7,40,0,201,175,140,129,8,215,5,9,99,111,110,100,105,116,105,111,110,1,122,0,0,0,0,0,0,0,0,40,0,201,175,140,129,8,215,5,7,99,111,110,116,101,110,116,1,119,0,40,0,201,175,140,129,8,215,5,2,105,100,1,119,6,122,109,79,103,122,80,161,201,175,140,129,8,179,5,1,136,201,175,140,129,8,66,1,118,2,6,104,101,105,103,104,116,125,60,2,105,100,119,36,49,54,100,97,48,102,54,56,45,102,52,49,52,45,52,99,53,57,45,57,53,101,98,45,51,98,52,53,98,52,98,54,49,100,99,51,161,201,175,140,129,8,222,5,1,136,201,175,140,129,8,223,5,1,118,2,6,104,101,105,103,104,116,125,60,2,105,100,119,36,51,98,53,101,102,56,50,52,45,52,55,53,99,45,52,56,52,56,45,97,99,102,102,45,52,49,56,101,50,53,57,97,51,100,53,51,161,201,175,140,129,8,224,5,1,136,201,175,140,129,8,225,5,1,118,2,2,105,100,119,36,57,101,53,101,102,101,100,48,45,54,50,50,48,45,52,56,98,101,45,56,55,48,52,45,100,56,101,99,48,49,54,54,55,57,54,99,6,104,101,105,103,104,116,125,60,161,201,175,140,129,8,226,5,1,129,201,175,140,129,8,227,5,1,161,201,175,140,129,8,228,5,1,129,201,175,140,129,8,229,5,1,161,201,175,140,129,8,230,5,1,129,201,175,140,129,8,231,5,1,39,0,201,175,140,129,8,3,36,97,55,51,52,97,48,54,56,45,101,55,51,100,45,52,98,52,98,45,56,53,51,99,45,52,100,97,102,102,101,97,51,56,57,99,48,1,40,0,201,175,140,129,8,234,5,2,105,100,1,119,36,97,55,51,52,97,48,54,56,45,101,55,51,100,45,52,98,52,98,45,56,53,51,99,45,52,100,97,102,102,101,97,51,56,57,99,48,40,0,201,175,140,129,8,234,5,11,100,97,116,97,98,97,115,101,95,105,100,1,119,36,56,55,98,99,48,48,54,101,45,99,49,101,98,45,52,55,102,100,45,57,97,99,54,45,101,51,57,98,49,55,57,53,54,51,54,57,40,0,201,175,140,129,8,234,5,4,110,97,109,101,1,119,4,71,114,105,100,40,0,201,175,140,129,8,234,5,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,0,0,0,0,33,0,201,175,140,129,8,234,5,11,109,111,100,105,102,105,101,100,95,97,116,1,39,0,201,175,140,129,8,234,5,15,108,97,121,111,117,116,95,115,101,116,116,105,110,103,115,1,40,0,201,175,140,129,8,234,5,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,39,0,201,175,140,129,8,234,5,14,102,105,101,108,100,95,115,101,116,116,105,110,103,115,1,39,0,201,175,140,129,8,234,5,7,102,105,108,116,101,114,115,0,39,0,201,175,140,129,8,234,5,6,103,114,111,117,112,115,0,39,0,201,175,140,129,8,234,5,5,115,111,114,116,115,0,39,0,201,175,140,129,8,234,5,12,102,105,101,108,100,95,111,114,100,101,114,115,0,8,0,201,175,140,129,8,246,5,8,118,1,2,105,100,119,6,77,67,57,90,97,69,118,1,2,105,100,119,6,53,69,90,81,65,87,118,1,2,105,100,119,6,108,73,72,113,101,57,118,1,2,105,100,119,6,111,121,80,121,97,117,118,1,2,105,100,119,6,102,116,73,53,52,121,118,1,2,105,100,119,6,87,120,110,102,109,110,118,1,2,105,100,119,6,84,79,87,83,70,104,118,1,2,105,100,119,6,45,81,77,51,70,50,39,0,201,175,140,129,8,234,5,10,114,111,119,95,111,114,100,101,114,115,0,8,0,201,175,140,129,8,255,5,6,118,2,6,104,101,105,103,104,116,125,60,2,105,100,119,36,49,49,49,49,98,49,52,54,45,52,99,54,99,45,52,102,99,54,45,57,53,101,49,45,55,48,99,50,52,54,49,52,55,102,56,102,118,2,6,104,101,105,103,104,116,125,60,2,105,100,119,36,51,101,99,55,98,55,54,99,45,54,56,99,57,45,52,50,55,57,45,57,98,51,51,45,50,51,54,53,51,50,49,101,97,102,52,49,118,2,2,105,100,119,36,57,99,100,101,55,99,49,53,45,51,52,55,99,45,52,52,55,97,45,57,101,97,49,45,55,54,98,99,51,97,56,100,52,101,57,54,6,104,101,105,103,104,116,125,60,118,2,2,105,100,119,36,49,54,100,97,48,102,54,56,45,102,52,49,52,45,52,99,53,57,45,57,53,101,98,45,51,98,52,53,98,52,98,54,49,100,99,51,6,104,101,105,103,104,116,125,60,118,2,2,105,100,119,36,51,98,53,101,102,56,50,52,45,52,55,53,99,45,52,56,52,56,45,97,99,102,102,45,52,49,56,101,50,53,57,97,51,100,53,51,6,104,101,105,103,104,116,125,60,118,2,2,105,100,119,36,57,101,53,101,102,101,100,48,45,54,50,50,48,45,52,56,98,101,45,56,55,48,52,45,100,56,101,99,48,49,54,54,55,57,54,99,6,104,101,105,103,104,116,125,60,129,201,175,140,129,8,133,6,3,161,201,175,140,129,8,232,5,1,161,201,175,140,129,8,239,5,1,161,201,175,140,129,8,137,6,1,161,201,175,140,129,8,138,6,1,161,201,175,140,129,8,139,6,1,161,201,175,140,129,8,140,6,1,161,201,175,140,129,8,141,6,1,7,0,201,175,140,129,8,58,1,40,0,201,175,140,129,8,144,6,2,105,100,1,119,8,115,58,57,78,84,103,95,117,40,0,201,175,140,129,8,144,6,9,99,111,110,100,105,116,105,111,110,1,122,0,0,0,0,0,0,0,0,40,0,201,175,140,129,8,144,6,8,102,105,101,108,100,95,105,100,1,119,6,111,121,80,121,97,117,161,201,175,140,129,8,143,6,1,136,201,175,140,129,8,233,5,1,118,2,2,105,100,119,36,50,52,50,52,57,54,56,57,45,99,97,100,52,45,52,101,53,51,45,56,99,53,101,45,102,57,101,97,101,99,57,98,102,53,53,56,6,104,101,105,103,104,116,125,60,168,201,175,140,129,8,142,6,1,122,0,0,0,0,102,97,116,208,136,201,175,140,129,8,136,6,1,118,2,6,104,101,105,103,104,116,125,60,2,105,100,119,36,50,52,50,52,57,54,56,57,45,99,97,100,52,45,52,101,53,51,45,56,99,53,101,45,102,57,101,97,101,99,57,98,102,53,53,56,161,201,175,140,129,8,148,6,1,135,201,175,140,129,8,144,6,1,33,0,201,175,140,129,8,153,6,2,105,100,1,33,0,201,175,140,129,8,153,6,8,102,105,101,108,100,95,105,100,1,33,0,201,175,140,129,8,153,6,9,99,111,110,100,105,116,105,111,110,1,168,201,175,140,129,8,152,6,1,122,0,0,0,0,102,97,139,96,168,201,175,140,129,8,154,6,1,119,8,115,58,105,108,55,118,85,50,168,201,175,140,129,8,155,6,1,119,6,77,67,57,90,97,69,168,201,175,140,129,8,156,6,1,122,0,0,0,0,0,0,0,1,2,144,224,143,199,14,1,0,15,201,175,140,129,8,49,20,1,25,1,40,1,67,1,73,1,75,1,77,1,81,1,88,1,93,2,100,1,102,1,104,1,108,1,111,2,114,4,119,2,123,10,135,1,18,155,1,1,161,1,1,163,1,1,165,1,1,169,1,1,175,1,1,179,1,15,196,1,42,243,1,1,245,1,1,247,1,1,251,1,1,254,1,1,132,2,1,134,2,1,136,2,1,140,2,1,145,2,1,148,2,13,163,2,16,181,2,255,2,222,5,1,224,5,1,226,5,1,228,5,6,239,5,1,134,6,10,148,6,1,152,6,1,154,6,3],"version":0,"object_id":"87bc006e-c1eb-47fd-9ac6-e39b17956369"},"code":0,"message":"Operation completed successfully."} \ No newline at end of file diff --git a/frontend/appflowy_web_app/cypress/fixtures/database/databases.json b/frontend/appflowy_web_app/cypress/fixtures/database/databases.json index 7c06ca35ab..675bb0b42a 100644 --- a/frontend/appflowy_web_app/cypress/fixtures/database/databases.json +++ b/frontend/appflowy_web_app/cypress/fixtures/database/databases.json @@ -1 +1,80 @@ -[{"database_id":"037a985f-f369-4c4a-8011-620012850a68","created_at":"1713429700","views":["48c52cf7-bf98-43fa-96ad-b31aade9b071"]},{"database_id":"daea6aee-9365-4703-a8e2-a2fa6a07b214","created_at":"1714449533","views":["b6347acb-3174-4f0e-98e9-dcce07e5dbf7"]},{"database_id":"4c658817-20db-4f56-b7f9-0637a22dfeb6","created_at":"0","views":["7d2148fc-cace-4452-9c5c-96e52e6bf8b5","e410747b-5f2f-45a0-b2f7-890ad3001355","2143e95d-5dcb-4e0f-bb2c-50944e6e019f","a5566e49-f156-4168-9b2d-17926c5da329","135615fa-66f7-4451-9b54-d7e99445fca4","b4e77203-5c8b-48df-bbc5-2e1143eb0e61","a6af311f-cbc8-42c2-b801-7115619c3776"]},{"database_id":"4c658817-20db-4f56-b7f9-0637a22dfeb6","created_at":"0","views":["7d2148fc-cace-4452-9c5c-96e52e6bf8b5","e97877f5-c365-4025-9e6a-e590c4b19dbb","f0c59921-04ee-4971-995c-79b7fd8c00e2","7eb697cd-6a55-40bb-96ac-0d4a3bc924b2"]},{"database_id":"ee63da2b-aa2a-4d0b-aab0-59008635363a","created_at":"0","views":["2c1ee95a-1b09-4a1f-8d5e-501bc4861a9d","91ea7c08-f6b3-4b81-aa1e-d3664686186f"]},{"database_id":"e788f014-d0d3-4dfe-81ef-aa1ebb4d6366","created_at":"0","views":["1b0e322d-4909-4c63-914a-d034fc363097","350f425b-b671-4e2d-8182-5998a6e62924"]},{"database_id":"ad7dc45b-44b5-498f-bfa2-0f43bf05cc0d","created_at":"0","views":["0ce13415-6cce-4497-94c6-475ad96c249e","e4c89421-12b2-4d02-863d-20949eec9271"]},{"database_id":"ce267d12-3b61-4ebb-bb03-d65272f5f817","created_at":"0","views":["ee3ae8ce-959a-4df3-8734-40b535ff88e3","66a6f3bc-c78f-4f74-a09e-08d4717bf1fd","2bf50c03-f41f-4363-b5b1-101216a6c5cc"]}] \ No newline at end of file +[ + { + "database_id": "037a985f-f369-4c4a-8011-620012850a68", + "created_at": "1713429700", + "views": [ + "48c52cf7-bf98-43fa-96ad-b31aade9b071" + ] + }, + { + "database_id": "daea6aee-9365-4703-a8e2-a2fa6a07b214", + "created_at": "1714449533", + "views": [ + "b6347acb-3174-4f0e-98e9-dcce07e5dbf7" + ] + }, + { + "database_id": "4c658817-20db-4f56-b7f9-0637a22dfeb6", + "created_at": "0", + "views": [ + "7d2148fc-cace-4452-9c5c-96e52e6bf8b5", + "e410747b-5f2f-45a0-b2f7-890ad3001355", + "2143e95d-5dcb-4e0f-bb2c-50944e6e019f", + "a5566e49-f156-4168-9b2d-17926c5da329", + "135615fa-66f7-4451-9b54-d7e99445fca4", + "b4e77203-5c8b-48df-bbc5-2e1143eb0e61", + "a6af311f-cbc8-42c2-b801-7115619c3776" + ] + }, + { + "database_id": "4c658817-20db-4f56-b7f9-0637a22dfeb6", + "created_at": "0", + "views": [ + "7d2148fc-cace-4452-9c5c-96e52e6bf8b5", + "e97877f5-c365-4025-9e6a-e590c4b19dbb", + "f0c59921-04ee-4971-995c-79b7fd8c00e2", + "7eb697cd-6a55-40bb-96ac-0d4a3bc924b2" + ] + }, + { + "database_id": "ee63da2b-aa2a-4d0b-aab0-59008635363a", + "created_at": "0", + "views": [ + "2c1ee95a-1b09-4a1f-8d5e-501bc4861a9d", + "91ea7c08-f6b3-4b81-aa1e-d3664686186f" + ] + }, + { + "database_id": "e788f014-d0d3-4dfe-81ef-aa1ebb4d6366", + "created_at": "0", + "views": [ + "1b0e322d-4909-4c63-914a-d034fc363097", + "350f425b-b671-4e2d-8182-5998a6e62924" + ] + }, + { + "database_id": "ad7dc45b-44b5-498f-bfa2-0f43bf05cc0d", + "created_at": "0", + "views": [ + "0ce13415-6cce-4497-94c6-475ad96c249e", + "e4c89421-12b2-4d02-863d-20949eec9271" + ] + }, + { + "database_id": "ce267d12-3b61-4ebb-bb03-d65272f5f817", + "created_at": "0", + "views": [ + "ee3ae8ce-959a-4df3-8734-40b535ff88e3", + "66a6f3bc-c78f-4f74-a09e-08d4717bf1fd", + "2bf50c03-f41f-4363-b5b1-101216a6c5cc" + ] + }, + { + "database_id": "87bc006e-c1eb-47fd-9ac6-e39b17956369", + "created_at": "0", + "views": [ + "7f233be4-1b4d-46b2-bcfc-f341b8d75267", + "a734a068-e73d-4b4b-853c-4daffea389c0" + ] + } +] \ No newline at end of file diff --git a/frontend/appflowy_web_app/cypress/fixtures/database/rows/87bc006e-c1eb-47fd-9ac6-e39b17956369.json b/frontend/appflowy_web_app/cypress/fixtures/database/rows/87bc006e-c1eb-47fd-9ac6-e39b17956369.json new file mode 100644 index 0000000000..4eefa98010 --- /dev/null +++ b/frontend/appflowy_web_app/cypress/fixtures/database/rows/87bc006e-c1eb-47fd-9ac6-e39b17956369.json @@ -0,0 +1 @@ +{"9cde7c15-347c-447a-9ea1-76bc3a8d4e96":[2,10,179,237,201,251,15,0,39,1,4,100,97,116,97,4,100,97,116,97,1,39,1,4,100,97,116,97,4,109,101,116,97,1,39,1,4,100,97,116,97,7,99,111,109,109,101,110,116,0,40,0,179,237,201,251,15,0,2,105,100,1,119,36,57,99,100,101,55,99,49,53,45,51,52,55,99,45,52,52,55,97,45,57,101,97,49,45,55,54,98,99,51,97,56,100,52,101,57,54,40,0,179,237,201,251,15,0,11,100,97,116,97,98,97,115,101,95,105,100,1,119,36,56,55,98,99,48,48,54,101,45,99,49,101,98,45,52,55,102,100,45,57,97,99,54,45,101,51,57,98,49,55,57,53,54,51,54,57,40,0,179,237,201,251,15,0,6,104,101,105,103,104,116,1,122,0,0,0,0,0,0,0,60,40,0,179,237,201,251,15,0,10,118,105,115,105,98,105,108,105,116,121,1,120,40,0,179,237,201,251,15,0,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,115,63,40,0,179,237,201,251,15,0,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,122,0,0,0,0,102,97,115,63,39,0,179,237,201,251,15,0,5,99,101,108,108,115,1,2,181,140,221,245,11,0,33,1,4,109,101,116,97,12,108,97,115,116,95,115,121,110,99,95,97,116,5,168,181,140,221,245,11,4,1,122,0,0,0,0,102,97,116,211,1,181,140,221,245,11,1,0,5],"16da0f68-f414-4c59-95eb-3b45b4b61dc3":[2,38,162,144,245,250,8,0,39,1,4,100,97,116,97,4,100,97,116,97,1,39,1,4,100,97,116,97,4,109,101,116,97,1,39,1,4,100,97,116,97,7,99,111,109,109,101,110,116,0,40,0,162,144,245,250,8,0,2,105,100,1,119,36,49,54,100,97,48,102,54,56,45,102,52,49,52,45,52,99,53,57,45,57,53,101,98,45,51,98,52,53,98,52,98,54,49,100,99,51,40,0,162,144,245,250,8,0,11,100,97,116,97,98,97,115,101,95,105,100,1,119,36,56,55,98,99,48,48,54,101,45,99,49,101,98,45,52,55,102,100,45,57,97,99,54,45,101,51,57,98,49,55,57,53,54,51,54,57,40,0,162,144,245,250,8,0,6,104,101,105,103,104,116,1,122,0,0,0,0,0,0,0,60,40,0,162,144,245,250,8,0,10,118,105,115,105,98,105,108,105,116,121,1,120,40,0,162,144,245,250,8,0,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,115,234,33,0,162,144,245,250,8,0,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,39,0,162,144,245,250,8,0,5,99,101,108,108,115,1,39,0,162,144,245,250,8,9,6,77,67,57,90,97,69,1,40,0,162,144,245,250,8,10,10,102,105,101,108,100,95,116,121,112,101,1,122,0,0,0,0,0,0,0,0,40,0,162,144,245,250,8,10,4,100,97,116,97,1,119,3,49,50,51,39,0,162,144,245,250,8,9,6,108,73,72,113,101,57,1,40,0,162,144,245,250,8,13,10,102,105,101,108,100,95,116,121,112,101,1,122,0,0,0,0,0,0,0,5,40,0,162,144,245,250,8,13,4,100,97,116,97,1,119,3,89,101,115,39,0,162,144,245,250,8,9,6,111,121,80,121,97,117,1,40,0,162,144,245,250,8,16,10,102,105,101,108,100,95,116,121,112,101,1,122,0,0,0,0,0,0,0,1,40,0,162,144,245,250,8,16,4,100,97,116,97,1,119,3,54,48,49,39,0,162,144,245,250,8,9,6,53,69,90,81,65,87,1,40,0,162,144,245,250,8,19,4,100,97,116,97,1,119,4,71,102,87,50,40,0,162,144,245,250,8,19,10,102,105,101,108,100,95,116,121,112,101,1,122,0,0,0,0,0,0,0,3,161,162,144,245,250,8,8,1,39,0,162,144,245,250,8,9,6,102,116,73,53,52,121,1,40,0,162,144,245,250,8,23,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,116,46,40,0,162,144,245,250,8,23,10,102,105,101,108,100,95,116,121,112,101,1,122,0,0,0,0,0,0,0,4,40,0,162,144,245,250,8,23,4,100,97,116,97,1,119,4,104,57,106,100,40,0,162,144,245,250,8,23,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,122,0,0,0,0,102,97,116,46,161,162,144,245,250,8,22,1,39,0,162,144,245,250,8,9,6,84,79,87,83,70,104,1,40,0,162,144,245,250,8,29,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,116,61,33,0,162,144,245,250,8,29,4,100,97,116,97,1,33,0,162,144,245,250,8,29,10,102,105,101,108,100,95,116,121,112,101,1,33,0,162,144,245,250,8,29,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,168,162,144,245,250,8,28,1,122,0,0,0,0,102,97,116,63,168,162,144,245,250,8,31,1,119,88,123,34,111,112,116,105,111,110,115,34,58,91,123,34,105,100,34,58,34,99,55,88,104,34,44,34,110,97,109,101,34,58,34,49,49,49,34,44,34,99,111,108,111,114,34,58,34,80,117,114,112,108,101,34,125,93,44,34,115,101,108,101,99,116,101,100,95,111,112,116,105,111,110,95,105,100,115,34,58,91,34,99,55,88,104,34,93,125,168,162,144,245,250,8,32,1,122,0,0,0,0,0,0,0,7,168,162,144,245,250,8,33,1,122,0,0,0,0,102,97,116,63,2,161,140,129,164,8,0,33,1,4,109,101,116,97,12,108,97,115,116,95,115,121,110,99,95,97,116,5,168,161,140,129,164,8,4,1,122,0,0,0,0,102,97,116,213,2,161,140,129,164,8,1,0,5,162,144,245,250,8,4,8,1,22,1,28,1,31,3],"9e5efed0-6220-48be-8704-d8ec0166796c":[2,2,144,209,245,144,10,0,33,1,4,109,101,116,97,12,108,97,115,116,95,115,121,110,99,95,97,116,5,168,144,209,245,144,10,4,1,122,0,0,0,0,102,97,116,215,56,246,244,204,133,9,0,39,1,4,100,97,116,97,4,100,97,116,97,1,39,1,4,100,97,116,97,4,109,101,116,97,1,39,1,4,100,97,116,97,7,99,111,109,109,101,110,116,0,40,0,246,244,204,133,9,0,2,105,100,1,119,36,57,101,53,101,102,101,100,48,45,54,50,50,48,45,52,56,98,101,45,56,55,48,52,45,100,56,101,99,48,49,54,54,55,57,54,99,40,0,246,244,204,133,9,0,11,100,97,116,97,98,97,115,101,95,105,100,1,119,36,56,55,98,99,48,48,54,101,45,99,49,101,98,45,52,55,102,100,45,57,97,99,54,45,101,51,57,98,49,55,57,53,54,51,54,57,40,0,246,244,204,133,9,0,6,104,101,105,103,104,116,1,122,0,0,0,0,0,0,0,60,40,0,246,244,204,133,9,0,10,118,105,115,105,98,105,108,105,116,121,1,120,40,0,246,244,204,133,9,0,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,115,238,33,0,246,244,204,133,9,0,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,39,0,246,244,204,133,9,0,5,99,101,108,108,115,1,39,0,246,244,204,133,9,9,6,108,73,72,113,101,57,1,40,0,246,244,204,133,9,10,4,100,97,116,97,1,119,3,89,101,115,40,0,246,244,204,133,9,10,10,102,105,101,108,100,95,116,121,112,101,1,122,0,0,0,0,0,0,0,5,39,0,246,244,204,133,9,9,6,77,67,57,90,97,69,1,33,0,246,244,204,133,9,13,10,102,105,101,108,100,95,116,121,112,101,1,33,0,246,244,204,133,9,13,4,100,97,116,97,1,39,0,246,244,204,133,9,9,6,111,121,80,121,97,117,1,33,0,246,244,204,133,9,16,10,102,105,101,108,100,95,116,121,112,101,1,33,0,246,244,204,133,9,16,4,100,97,116,97,1,39,0,246,244,204,133,9,9,6,53,69,90,81,65,87,1,40,0,246,244,204,133,9,19,10,102,105,101,108,100,95,116,121,112,101,1,122,0,0,0,0,0,0,0,3,40,0,246,244,204,133,9,19,4,100,97,116,97,1,119,4,71,102,87,50,161,246,244,204,133,9,8,1,40,0,246,244,204,133,9,16,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,116,17,168,246,244,204,133,9,18,1,119,3,54,48,51,168,246,244,204,133,9,17,1,122,0,0,0,0,0,0,0,1,40,0,246,244,204,133,9,16,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,122,0,0,0,0,102,97,116,17,161,246,244,204,133,9,22,1,40,0,246,244,204,133,9,13,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,116,39,168,246,244,204,133,9,14,1,122,0,0,0,0,0,0,0,0,168,246,244,204,133,9,15,1,119,7,49,50,51,57,57,48,48,40,0,246,244,204,133,9,13,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,122,0,0,0,0,102,97,116,39,161,246,244,204,133,9,27,1,39,0,246,244,204,133,9,9,6,102,116,73,53,52,121,1,40,0,246,244,204,133,9,33,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,116,51,40,0,246,244,204,133,9,33,10,102,105,101,108,100,95,116,121,112,101,1,122,0,0,0,0,0,0,0,4,40,0,246,244,204,133,9,33,4,100,97,116,97,1,119,4,104,57,106,100,40,0,246,244,204,133,9,33,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,122,0,0,0,0,102,97,116,51,161,246,244,204,133,9,32,1,39,0,246,244,204,133,9,9,6,84,79,87,83,70,104,1,40,0,246,244,204,133,9,39,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,116,71,33,0,246,244,204,133,9,39,4,100,97,116,97,1,33,0,246,244,204,133,9,39,10,102,105,101,108,100,95,116,121,112,101,1,33,0,246,244,204,133,9,39,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,161,246,244,204,133,9,38,1,161,246,244,204,133,9,42,1,161,246,244,204,133,9,41,1,161,246,244,204,133,9,43,1,161,246,244,204,133,9,44,1,161,246,244,204,133,9,46,1,161,246,244,204,133,9,45,1,161,246,244,204,133,9,47,1,168,246,244,204,133,9,48,1,122,0,0,0,0,102,97,116,75,168,246,244,204,133,9,50,1,122,0,0,0,0,0,0,0,7,168,246,244,204,133,9,49,1,119,135,1,123,34,111,112,116,105,111,110,115,34,58,91,123,34,105,100,34,58,34,102,104,112,70,34,44,34,110,97,109,101,34,58,34,51,34,44,34,99,111,108,111,114,34,58,34,80,117,114,112,108,101,34,125,44,123,34,105,100,34,58,34,111,105,110,85,34,44,34,110,97,109,101,34,58,34,54,34,44,34,99,111,108,111,114,34,58,34,80,117,114,112,108,101,34,125,93,44,34,115,101,108,101,99,116,101,100,95,111,112,116,105,111,110,95,105,100,115,34,58,91,34,102,104,112,70,34,44,34,111,105,110,85,34,93,125,168,246,244,204,133,9,51,1,122,0,0,0,0,102,97,116,75,2,144,209,245,144,10,1,0,5,246,244,204,133,9,8,8,1,14,2,17,2,22,1,27,1,32,1,38,1,41,11],"3b5ef824-475c-4848-acff-418e259a3d53":[2,2,219,196,219,154,10,0,33,1,4,109,101,116,97,12,108,97,115,116,95,115,121,110,99,95,97,116,5,168,219,196,219,154,10,4,1,122,0,0,0,0,102,97,116,208,60,150,233,209,1,0,39,1,4,100,97,116,97,4,100,97,116,97,1,39,1,4,100,97,116,97,4,109,101,116,97,1,39,1,4,100,97,116,97,7,99,111,109,109,101,110,116,0,40,0,150,233,209,1,0,2,105,100,1,119,36,51,98,53,101,102,56,50,52,45,52,55,53,99,45,52,56,52,56,45,97,99,102,102,45,52,49,56,101,50,53,57,97,51,100,53,51,40,0,150,233,209,1,0,11,100,97,116,97,98,97,115,101,95,105,100,1,119,36,56,55,98,99,48,48,54,101,45,99,49,101,98,45,52,55,102,100,45,57,97,99,54,45,101,51,57,98,49,55,57,53,54,51,54,57,40,0,150,233,209,1,0,6,104,101,105,103,104,116,1,122,0,0,0,0,0,0,0,60,40,0,150,233,209,1,0,10,118,105,115,105,98,105,108,105,116,121,1,120,40,0,150,233,209,1,0,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,115,237,33,0,150,233,209,1,0,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,39,0,150,233,209,1,0,5,99,101,108,108,115,1,39,0,150,233,209,1,9,6,111,121,80,121,97,117,1,33,0,150,233,209,1,10,10,102,105,101,108,100,95,116,121,112,101,1,33,0,150,233,209,1,10,4,100,97,116,97,1,39,0,150,233,209,1,9,6,53,69,90,81,65,87,1,40,0,150,233,209,1,13,4,100,97,116,97,1,119,4,71,102,87,50,40,0,150,233,209,1,13,10,102,105,101,108,100,95,116,121,112,101,1,122,0,0,0,0,0,0,0,3,39,0,150,233,209,1,9,6,77,67,57,90,97,69,1,33,0,150,233,209,1,16,10,102,105,101,108,100,95,116,121,112,101,1,33,0,150,233,209,1,16,4,100,97,116,97,1,39,0,150,233,209,1,9,6,108,73,72,113,101,57,1,40,0,150,233,209,1,19,10,102,105,101,108,100,95,116,121,112,101,1,122,0,0,0,0,0,0,0,5,40,0,150,233,209,1,19,4,100,97,116,97,1,119,3,89,101,115,161,150,233,209,1,8,1,40,0,150,233,209,1,10,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,116,15,161,150,233,209,1,12,1,161,150,233,209,1,11,1,33,0,150,233,209,1,10,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,161,150,233,209,1,22,1,40,0,150,233,209,1,16,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,116,31,168,150,233,209,1,17,1,122,0,0,0,0,0,0,0,0,168,150,233,209,1,18,1,119,6,49,50,51,53,54,55,40,0,150,233,209,1,16,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,122,0,0,0,0,102,97,116,31,161,150,233,209,1,27,1,39,0,150,233,209,1,9,6,102,116,73,53,52,121,1,40,0,150,233,209,1,33,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,116,49,40,0,150,233,209,1,33,10,102,105,101,108,100,95,116,121,112,101,1,122,0,0,0,0,0,0,0,4,40,0,150,233,209,1,33,4,100,97,116,97,1,119,4,104,57,106,100,40,0,150,233,209,1,33,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,122,0,0,0,0,102,97,116,49,161,150,233,209,1,32,1,39,0,150,233,209,1,9,6,84,79,87,83,70,104,1,40,0,150,233,209,1,39,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,116,65,33,0,150,233,209,1,39,10,102,105,101,108,100,95,116,121,112,101,1,33,0,150,233,209,1,39,4,100,97,116,97,1,33,0,150,233,209,1,39,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,161,150,233,209,1,38,1,161,150,233,209,1,42,1,161,150,233,209,1,41,1,161,150,233,209,1,43,1,161,150,233,209,1,44,1,161,150,233,209,1,46,1,161,150,233,209,1,45,1,161,150,233,209,1,47,1,161,150,233,209,1,48,1,168,150,233,209,1,49,1,122,0,0,0,0,0,0,0,7,168,150,233,209,1,50,1,119,135,1,123,34,111,112,116,105,111,110,115,34,58,91,123,34,105,100,34,58,34,45,106,68,117,34,44,34,110,97,109,101,34,58,34,50,34,44,34,99,111,108,111,114,34,58,34,80,117,114,112,108,101,34,125,44,123,34,105,100,34,58,34,76,57,87,81,34,44,34,110,97,109,101,34,58,34,51,34,44,34,99,111,108,111,114,34,58,34,80,117,114,112,108,101,34,125,93,44,34,115,101,108,101,99,116,101,100,95,111,112,116,105,111,110,95,105,100,115,34,58,91,34,45,106,68,117,34,44,34,76,57,87,81,34,93,125,168,150,233,209,1,51,1,122,0,0,0,0,102,97,116,68,168,150,233,209,1,52,1,122,0,0,0,0,102,97,116,93,168,150,233,209,1,25,1,122,0,0,0,0,0,0,0,1,168,150,233,209,1,24,1,119,3,54,48,55,168,150,233,209,1,26,1,122,0,0,0,0,102,97,116,93,2,150,233,209,1,8,8,1,11,2,17,2,22,1,24,4,32,1,38,1,41,12,219,196,219,154,10,1,0,5],"24249689-cad4-4e53-8c5e-f9eaec9bf558":[2,10,242,202,217,154,13,0,39,1,4,100,97,116,97,4,100,97,116,97,1,39,1,4,100,97,116,97,4,109,101,116,97,1,39,1,4,100,97,116,97,7,99,111,109,109,101,110,116,0,40,0,242,202,217,154,13,0,2,105,100,1,119,36,50,52,50,52,57,54,56,57,45,99,97,100,52,45,52,101,53,51,45,56,99,53,101,45,102,57,101,97,101,99,57,98,102,53,53,56,40,0,242,202,217,154,13,0,11,100,97,116,97,98,97,115,101,95,105,100,1,119,36,56,55,98,99,48,48,54,101,45,99,49,101,98,45,52,55,102,100,45,57,97,99,54,45,101,51,57,98,49,55,57,53,54,51,54,57,40,0,242,202,217,154,13,0,6,104,101,105,103,104,116,1,122,0,0,0,0,0,0,0,60,40,0,242,202,217,154,13,0,10,118,105,115,105,98,105,108,105,116,121,1,120,40,0,242,202,217,154,13,0,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,116,208,40,0,242,202,217,154,13,0,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,122,0,0,0,0,102,97,116,208,39,0,242,202,217,154,13,0,5,99,101,108,108,115,1,2,243,240,149,193,10,0,33,1,4,109,101,116,97,12,108,97,115,116,95,115,121,110,99,95,97,116,5,168,243,240,149,193,10,4,1,122,0,0,0,0,102,97,116,218,1,243,240,149,193,10,1,0,5],"1111b146-4c6c-4fc6-95e1-70c246147f8f":[2,10,165,220,194,235,14,0,39,1,4,100,97,116,97,4,100,97,116,97,1,39,1,4,100,97,116,97,4,109,101,116,97,1,39,1,4,100,97,116,97,7,99,111,109,109,101,110,116,0,40,0,165,220,194,235,14,0,2,105,100,1,119,36,49,49,49,49,98,49,52,54,45,52,99,54,99,45,52,102,99,54,45,57,53,101,49,45,55,48,99,50,52,54,49,52,55,102,56,102,40,0,165,220,194,235,14,0,11,100,97,116,97,98,97,115,101,95,105,100,1,119,36,56,55,98,99,48,48,54,101,45,99,49,101,98,45,52,55,102,100,45,57,97,99,54,45,101,51,57,98,49,55,57,53,54,51,54,57,40,0,165,220,194,235,14,0,6,104,101,105,103,104,116,1,122,0,0,0,0,0,0,0,60,40,0,165,220,194,235,14,0,10,118,105,115,105,98,105,108,105,116,121,1,120,40,0,165,220,194,235,14,0,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,115,63,40,0,165,220,194,235,14,0,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,122,0,0,0,0,102,97,115,63,39,0,165,220,194,235,14,0,5,99,101,108,108,115,1,2,250,172,218,249,7,0,33,1,4,109,101,116,97,12,108,97,115,116,95,115,121,110,99,95,97,116,5,168,250,172,218,249,7,4,1,122,0,0,0,0,102,97,116,211,1,250,172,218,249,7,1,0,5],"3ec7b76c-68c9-4279-9b33-2365321eaf41":[2,10,243,212,210,152,3,0,39,1,4,100,97,116,97,4,100,97,116,97,1,39,1,4,100,97,116,97,4,109,101,116,97,1,39,1,4,100,97,116,97,7,99,111,109,109,101,110,116,0,40,0,243,212,210,152,3,0,2,105,100,1,119,36,51,101,99,55,98,55,54,99,45,54,56,99,57,45,52,50,55,57,45,57,98,51,51,45,50,51,54,53,51,50,49,101,97,102,52,49,40,0,243,212,210,152,3,0,11,100,97,116,97,98,97,115,101,95,105,100,1,119,36,56,55,98,99,48,48,54,101,45,99,49,101,98,45,52,55,102,100,45,57,97,99,54,45,101,51,57,98,49,55,57,53,54,51,54,57,40,0,243,212,210,152,3,0,6,104,101,105,103,104,116,1,122,0,0,0,0,0,0,0,60,40,0,243,212,210,152,3,0,10,118,105,115,105,98,105,108,105,116,121,1,120,40,0,243,212,210,152,3,0,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,115,63,40,0,243,212,210,152,3,0,13,108,97,115,116,95,109,111,100,105,102,105,101,100,1,122,0,0,0,0,102,97,115,63,39,0,243,212,210,152,3,0,5,99,101,108,108,115,1,2,160,128,198,202,2,0,33,1,4,109,101,116,97,12,108,97,115,116,95,115,121,110,99,95,97,116,5,168,160,128,198,202,2,4,1,122,0,0,0,0,102,97,116,210,1,160,128,198,202,2,1,0,5]} \ No newline at end of file diff --git a/frontend/appflowy_web_app/cypress/fixtures/folder.json b/frontend/appflowy_web_app/cypress/fixtures/folder.json index 472ad9157d..2b1a53a989 100644 --- a/frontend/appflowy_web_app/cypress/fixtures/folder.json +++ b/frontend/appflowy_web_app/cypress/fixtures/folder.json @@ -1 +1 @@ -{"data":{"state_vector":[157,1,128,252,161,128,4,33,130,180,254,251,6,18,135,232,133,203,9,15,135,240,136,178,10,45,137,226,192,199,6,20,138,202,240,189,2,134,1,139,240,196,145,14,138,2,139,152,215,249,10,34,141,216,158,150,1,3,142,130,192,134,11,3,143,184,153,180,6,6,140,228,230,243,1,2,145,190,137,224,10,2,145,144,146,185,5,12,140,152,206,145,6,165,1,135,166,246,235,6,3,147,206,229,235,1,3,137,164,190,210,1,39,152,158,185,230,10,7,153,130,203,161,6,97,152,252,186,192,1,2,154,244,246,165,8,198,1,156,148,170,169,10,16,157,240,144,231,2,3,158,156,181,152,10,49,158,182,250,251,9,15,160,192,253,131,5,3,161,178,132,150,11,101,159,156,204,250,6,27,163,236,177,169,4,12,164,188,201,172,1,3,158,184,218,165,3,38,162,238,198,212,7,3,170,140,240,234,9,31,171,204,155,217,8,3,171,142,166,254,1,6,173,252,148,184,13,64,176,154,159,227,1,20,178,162,190,217,10,3,179,252,154,44,3,180,230,210,212,13,7,182,172,247,194,5,3,183,226,184,158,8,8,195,242,227,194,8,3,196,154,250,183,6,62,197,254,154,201,10,3,200,142,208,241,4,157,1,202,160,246,212,1,6,203,184,221,173,11,37,206,220,129,131,4,21,207,228,238,162,8,50,209,250,203,254,15,3,210,228,153,221,12,3,211,202,217,232,12,7,211,166,203,229,4,195,1,214,168,149,214,3,15,225,248,138,176,2,49,226,212,179,248,2,15,229,154,128,197,12,24,234,182,182,157,9,8,235,178,165,206,5,72,241,130,161,205,7,12,244,226,228,149,2,30,245,220,194,52,39,247,200,243,247,14,100,248,136,168,181,1,3,248,210,237,129,13,2,250,198,166,187,7,2,248,196,187,185,10,27,252,218,241,167,14,3,255,140,248,220,6,3,128,211,179,216,2,10,133,159,138,205,12,131,1,135,167,156,250,14,16,135,193,208,135,7,16,141,245,194,142,11,7,141,205,220,149,4,3,143,131,148,152,6,15,141,171,170,217,4,2,145,159,164,217,14,3,149,129,169,191,12,16,149,249,242,175,4,31,149,189,189,215,8,3,149,161,132,184,14,221,2,154,243,157,196,14,12,154,193,208,134,10,9,155,165,205,152,11,3,154,235,215,240,4,13,155,159,180,195,15,6,157,207,243,216,6,2,161,239,241,154,13,106,162,159,252,196,11,3,164,155,139,169,7,35,165,139,157,171,15,103,164,203,250,235,13,7,167,131,133,162,9,11,166,201,221,141,13,72,169,197,188,221,3,3,170,255,211,105,38,166,203,155,46,6,173,187,245,170,14,46,174,151,139,93,179,2,175,225,172,150,8,11,175,147,217,214,1,33,177,161,136,243,11,10,178,203,205,182,4,1,175,205,156,228,6,10,180,205,189,133,13,20,181,175,219,209,12,10,182,143,233,195,4,111,177,219,160,167,7,4,184,201,188,172,10,3,184,231,170,67,6,186,197,166,179,15,7,187,173,214,176,15,3,188,171,136,250,8,21,188,237,223,145,6,26,190,139,191,155,1,2,191,157,147,233,9,32,193,249,142,142,4,17,198,189,216,175,6,23,200,205,214,172,10,30,201,129,238,197,4,84,201,191,159,147,14,17,200,203,236,184,2,35,200,159,185,206,9,8,205,149,231,236,11,68,213,161,242,209,13,35,214,139,213,136,8,66,213,255,156,145,1,2,219,227,140,137,6,34,221,147,167,147,15,177,2,222,205,223,235,7,31,223,209,193,147,11,81,227,209,197,253,2,14,229,153,197,202,7,241,6,231,139,244,188,8,13,232,207,157,148,2,2,233,165,139,246,14,43,233,247,183,159,1,4,235,225,184,133,10,3,234,153,236,158,4,73,234,187,164,181,1,24,231,189,134,196,8,77,239,199,189,146,3,24,240,149,229,225,6,15,241,155,213,233,1,52,240,253,240,229,1,79,243,239,182,181,13,30,236,229,225,232,8,116,246,185,174,192,6,90,248,153,216,10,3,251,189,220,155,14,3,252,163,130,200,6,30,253,205,145,137,11,10,252,171,209,175,15,4,255,255,147,249,10,3],"doc_state":[157,1,3,209,250,203,254,15,0,161,226,212,179,248,2,9,1,161,226,212,179,248,2,10,1,136,174,151,139,93,249,1,1,118,2,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,246,78,2,155,159,180,195,15,0,161,198,189,216,175,6,22,1,161,253,205,145,137,11,9,5,7,186,197,166,179,15,0,161,161,178,132,150,11,98,1,161,161,178,132,150,11,99,1,129,161,178,132,150,11,100,1,161,161,178,132,150,11,97,1,161,161,178,132,150,11,94,1,161,161,178,132,150,11,95,1,129,186,197,166,179,15,2,1,3,187,173,214,176,15,0,168,244,226,228,149,2,27,1,122,4,56,115,160,190,64,16,0,168,244,226,228,149,2,28,1,122,0,0,0,0,102,32,153,171,136,248,153,216,10,2,1,118,2,2,105,100,119,36,48,53,51,51,50,98,97,52,45,97,54,57,48,45,52,50,57,51,45,57,56,54,54,45,56,52,100,97,99,55,102,101,50,97,101,97,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,32,153,171,1,252,171,209,175,15,0,161,128,211,179,216,2,9,4,103,165,139,157,171,15,0,8,0,201,129,238,197,4,52,1,118,1,2,105,100,119,36,97,53,53,54,54,101,52,57,45,102,49,53,54,45,52,49,54,56,45,57,98,50,100,45,49,55,57,50,54,99,53,100,97,51,50,57,168,201,129,238,197,4,51,1,122,0,0,0,0,102,74,244,14,161,170,140,240,234,9,22,1,39,0,203,184,221,173,11,1,36,97,53,53,54,54,101,52,57,45,102,49,53,54,45,52,49,54,56,45,57,98,50,100,45,49,55,57,50,54,99,53,100,97,51,50,57,1,40,0,165,139,157,171,15,3,2,105,100,1,119,36,97,53,53,54,54,101,52,57,45,102,49,53,54,45,52,49,54,56,45,57,98,50,100,45,49,55,57,50,54,99,53,100,97,51,50,57,40,0,165,139,157,171,15,3,4,110,97,109,101,1,119,14,66,111,97,114,100,32,99,104,101,99,107,98,111,120,40,0,165,139,157,171,15,3,3,98,105,100,1,119,36,101,52,49,48,55,52,55,98,45,53,102,50,102,45,52,53,97,48,45,98,50,102,55,45,56,57,48,97,100,51,48,48,49,51,53,53,40,0,165,139,157,171,15,3,4,100,101,115,99,1,119,0,40,0,165,139,157,171,15,3,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,2,33,0,165,139,157,171,15,3,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,97,53,53,54,54,101,52,57,45,102,49,53,54,45,52,49,54,56,45,57,98,50,100,45,49,55,57,50,54,99,53,100,97,51,50,57,0,40,0,165,139,157,171,15,3,4,105,99,111,110,1,119,0,40,0,165,139,157,171,15,3,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,165,139,157,171,15,3,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,165,139,157,171,15,3,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,170,140,240,234,9,21,1,161,165,139,157,171,15,2,1,129,159,156,204,250,6,26,1,136,225,248,138,176,2,17,1,118,1,2,105,100,119,36,49,98,48,101,51,50,50,100,45,52,57,48,57,45,52,99,54,51,45,57,49,52,97,45,100,48,51,52,102,99,51,54,51,48,57,55,161,225,248,138,176,2,18,1,161,193,249,142,142,4,8,1,39,0,203,184,221,173,11,1,36,49,98,48,101,51,50,50,100,45,52,57,48,57,45,52,99,54,51,45,57,49,52,97,45,100,48,51,52,102,99,51,54,51,48,57,55,1,40,0,165,139,157,171,15,21,2,105,100,1,119,36,49,98,48,101,51,50,50,100,45,52,57,48,57,45,52,99,54,51,45,57,49,52,97,45,100,48,51,52,102,99,51,54,51,48,57,55,40,0,165,139,157,171,15,21,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,165,139,157,171,15,21,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,165,139,157,171,15,21,4,100,101,115,99,1,119,0,40,0,165,139,157,171,15,21,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,2,33,0,165,139,157,171,15,21,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,49,98,48,101,51,50,50,100,45,52,57,48,57,45,52,99,54,51,45,57,49,52,97,45,100,48,51,52,102,99,51,54,51,48,57,55,0,40,0,165,139,157,171,15,21,4,105,99,111,110,1,119,0,40,0,165,139,157,171,15,21,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,165,139,157,171,15,21,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,165,139,157,171,15,21,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,193,249,142,142,4,13,1,161,165,139,157,171,15,32,1,161,165,139,157,171,15,31,1,129,165,139,157,171,15,17,1,8,0,165,139,157,171,15,28,1,118,1,2,105,100,119,36,51,53,48,102,52,50,53,98,45,98,54,55,49,45,52,101,50,100,45,56,49,56,50,45,53,57,57,56,97,54,101,54,50,57,50,52,168,165,139,157,171,15,27,1,122,0,0,0,0,102,74,246,67,161,165,139,157,171,15,35,1,39,0,203,184,221,173,11,1,36,51,53,48,102,52,50,53,98,45,98,54,55,49,45,52,101,50,100,45,56,49,56,50,45,53,57,57,56,97,54,101,54,50,57,50,52,1,40,0,165,139,157,171,15,40,2,105,100,1,119,36,51,53,48,102,52,50,53,98,45,98,54,55,49,45,52,101,50,100,45,56,49,56,50,45,53,57,57,56,97,54,101,54,50,57,50,52,40,0,165,139,157,171,15,40,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,165,139,157,171,15,40,3,98,105,100,1,119,36,49,98,48,101,51,50,50,100,45,52,57,48,57,45,52,99,54,51,45,57,49,52,97,45,100,48,51,52,102,99,51,54,51,48,57,55,40,0,165,139,157,171,15,40,4,100,101,115,99,1,119,0,40,0,165,139,157,171,15,40,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,40,0,165,139,157,171,15,40,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,74,246,67,39,0,203,184,221,173,11,4,36,51,53,48,102,52,50,53,98,45,98,54,55,49,45,52,101,50,100,45,56,49,56,50,45,53,57,57,56,97,54,101,54,50,57,50,52,0,40,0,165,139,157,171,15,40,4,105,99,111,110,1,119,0,40,0,165,139,157,171,15,40,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,165,139,157,171,15,40,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,102,74,246,67,40,0,165,139,157,171,15,40,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,161,165,139,157,171,15,34,1,161,165,139,157,171,15,39,1,129,165,139,157,171,15,36,1,161,176,154,159,227,1,17,1,161,176,154,159,227,1,18,1,40,0,176,154,159,227,1,4,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,161,165,139,157,171,15,55,1,161,165,139,157,171,15,56,1,129,165,139,157,171,15,54,1,161,165,139,157,171,15,52,1,161,165,139,157,171,15,53,1,129,165,139,157,171,15,60,1,161,165,139,157,171,15,61,1,161,165,139,157,171,15,62,1,129,165,139,157,171,15,63,1,161,165,139,157,171,15,64,1,161,165,139,157,171,15,65,1,129,165,139,157,171,15,66,1,8,0,225,248,138,176,2,27,1,118,1,2,105,100,119,36,57,49,101,97,55,99,48,56,45,102,54,98,51,45,52,98,56,49,45,97,97,49,101,45,100,51,54,54,52,54,56,54,49,56,54,102,168,225,248,138,176,2,26,1,122,0,0,0,0,102,74,248,249,161,225,248,138,176,2,40,1,39,0,203,184,221,173,11,1,36,57,49,101,97,55,99,48,56,45,102,54,98,51,45,52,98,56,49,45,97,97,49,101,45,100,51,54,54,52,54,56,54,49,56,54,102,1,40,0,165,139,157,171,15,73,2,105,100,1,119,36,57,49,101,97,55,99,48,56,45,102,54,98,51,45,52,98,56,49,45,97,97,49,101,45,100,51,54,54,52,54,56,54,49,56,54,102,40,0,165,139,157,171,15,73,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,165,139,157,171,15,73,3,98,105,100,1,119,36,50,99,49,101,101,57,53,97,45,49,98,48,57,45,52,97,49,102,45,56,100,53,101,45,53,48,49,98,99,52,56,54,49,97,57,100,40,0,165,139,157,171,15,73,4,100,101,115,99,1,119,0,40,0,165,139,157,171,15,73,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,2,40,0,165,139,157,171,15,73,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,74,248,249,39,0,203,184,221,173,11,4,36,57,49,101,97,55,99,48,56,45,102,54,98,51,45,52,98,56,49,45,97,97,49,101,45,100,51,54,54,52,54,56,54,49,56,54,102,0,40,0,165,139,157,171,15,73,4,105,99,111,110,1,119,0,40,0,165,139,157,171,15,73,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,165,139,157,171,15,73,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,102,74,248,249,40,0,165,139,157,171,15,73,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,161,225,248,138,176,2,39,1,161,165,139,157,171,15,72,1,129,165,139,157,171,15,69,1,161,165,139,157,171,15,67,1,161,165,139,157,171,15,68,1,129,165,139,157,171,15,87,1,161,165,139,157,171,15,85,1,161,165,139,157,171,15,86,1,129,165,139,157,171,15,90,1,161,159,156,204,250,6,24,1,161,159,156,204,250,6,25,1,129,165,139,157,171,15,93,1,161,165,139,157,171,15,15,1,161,165,139,157,171,15,16,1,129,165,139,157,171,15,96,1,161,165,139,157,171,15,97,1,161,165,139,157,171,15,98,1,129,165,139,157,171,15,99,1,1,221,147,167,147,15,0,161,139,240,196,145,14,137,2,177,2,1,135,167,156,250,14,0,161,188,237,223,145,6,21,16,100,247,200,243,247,14,0,136,140,152,206,145,6,100,1,118,1,2,105,100,119,36,55,57,100,48,54,51,50,100,45,97,53,97,56,45,52,53,52,48,45,97,100,99,100,45,54,101,101,57,50,50,100,56,54,55,101,100,168,140,152,206,145,6,101,1,122,0,0,0,0,102,86,193,79,161,245,220,194,52,7,1,39,0,203,184,221,173,11,1,36,55,57,100,48,54,51,50,100,45,97,53,97,56,45,52,53,52,48,45,97,100,99,100,45,54,101,101,57,50,50,100,56,54,55,101,100,1,40,0,247,200,243,247,14,3,2,105,100,1,119,36,55,57,100,48,54,51,50,100,45,97,53,97,56,45,52,53,52,48,45,97,100,99,100,45,54,101,101,57,50,50,100,56,54,55,101,100,33,0,247,200,243,247,14,3,4,110,97,109,101,1,40,0,247,200,243,247,14,3,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,247,200,243,247,14,3,4,100,101,115,99,1,119,0,40,0,247,200,243,247,14,3,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,247,200,243,247,14,3,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,86,193,79,39,0,203,184,221,173,11,4,36,55,57,100,48,54,51,50,100,45,97,53,97,56,45,52,53,52,48,45,97,100,99,100,45,54,101,101,57,50,50,100,56,54,55,101,100,0,40,0,247,200,243,247,14,3,4,105,99,111,110,1,119,0,40,0,247,200,243,247,14,3,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,247,200,243,247,14,3,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,247,200,243,247,14,3,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,170,255,211,105,34,1,161,247,200,243,247,14,14,1,161,247,200,243,247,14,13,1,129,135,166,246,235,6,2,1,161,247,200,243,247,14,16,1,161,247,200,243,247,14,17,1,40,0,247,200,243,247,14,3,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,161,247,200,243,247,14,19,1,161,247,200,243,247,14,20,1,161,247,200,243,247,14,5,1,161,247,200,243,247,14,22,1,161,247,200,243,247,14,23,1,161,247,200,243,247,14,24,1,161,247,200,243,247,14,25,1,161,247,200,243,247,14,26,1,161,247,200,243,247,14,27,1,161,247,200,243,247,14,28,1,161,247,200,243,247,14,29,1,161,247,200,243,247,14,30,1,161,247,200,243,247,14,31,1,161,247,200,243,247,14,32,1,161,247,200,243,247,14,33,1,161,247,200,243,247,14,34,1,161,247,200,243,247,14,35,1,161,247,200,243,247,14,36,1,161,247,200,243,247,14,37,1,161,247,200,243,247,14,38,1,161,247,200,243,247,14,39,1,161,247,200,243,247,14,40,1,161,247,200,243,247,14,41,1,161,247,200,243,247,14,42,1,161,247,200,243,247,14,43,1,161,247,200,243,247,14,44,1,161,247,200,243,247,14,45,1,161,247,200,243,247,14,46,1,161,247,200,243,247,14,47,1,161,247,200,243,247,14,48,1,161,247,200,243,247,14,49,1,161,247,200,243,247,14,50,1,168,247,200,243,247,14,51,1,119,10,116,101,115,116,32,101,118,101,110,116,168,247,200,243,247,14,52,1,122,4,56,115,160,190,64,16,0,168,247,200,243,247,14,53,1,122,0,0,0,0,102,87,4,29,136,247,200,243,247,14,18,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,87,4,29,2,105,100,119,36,55,57,100,48,54,51,50,100,45,97,53,97,56,45,52,53,52,48,45,97,100,99,100,45,54,101,101,57,50,50,100,56,54,55,101,100,161,166,201,221,141,13,41,1,161,166,201,221,141,13,42,1,161,166,201,221,141,13,43,1,161,247,200,243,247,14,58,1,161,247,200,243,247,14,59,1,161,247,200,243,247,14,60,1,161,247,200,243,247,14,61,1,161,247,200,243,247,14,62,1,161,247,200,243,247,14,63,1,161,247,200,243,247,14,64,1,161,247,200,243,247,14,65,1,161,247,200,243,247,14,66,1,161,247,200,243,247,14,67,1,161,247,200,243,247,14,68,1,161,247,200,243,247,14,69,1,161,247,200,243,247,14,70,1,161,247,200,243,247,14,71,1,161,247,200,243,247,14,72,1,161,247,200,243,247,14,73,1,161,247,200,243,247,14,74,1,161,247,200,243,247,14,75,1,161,247,200,243,247,14,76,1,161,247,200,243,247,14,77,1,161,247,200,243,247,14,78,1,161,247,200,243,247,14,79,1,161,247,200,243,247,14,80,1,161,247,200,243,247,14,81,1,161,247,200,243,247,14,82,1,161,247,200,243,247,14,83,1,161,247,200,243,247,14,84,1,161,247,200,243,247,14,85,1,161,247,200,243,247,14,86,1,161,247,200,243,247,14,87,1,161,247,200,243,247,14,88,1,161,247,200,243,247,14,89,1,161,247,200,243,247,14,90,1,161,247,200,243,247,14,91,1,161,247,200,243,247,14,92,1,161,247,200,243,247,14,93,1,168,247,200,243,247,14,94,1,122,4,56,115,160,190,64,16,0,168,247,200,243,247,14,95,1,122,0,0,0,0,102,87,4,247,168,247,200,243,247,14,96,1,119,145,1,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,103,114,97,100,105,101,110,116,34,44,34,118,97,108,117,101,34,58,34,97,112,112,102,108,111,119,121,95,116,104,101,109,95,99,111,108,111,114,95,103,114,97,100,105,101,110,116,55,34,125,44,34,102,111,110,116,95,108,97,121,111,117,116,34,58,34,110,111,114,109,97,108,34,44,34,108,105,110,101,95,104,101,105,103,104,116,95,108,97,121,111,117,116,34,58,34,110,111,114,109,97,108,34,44,34,102,111,110,116,34,58,34,65,68,76,97,77,32,68,105,115,112,108,97,121,34,125,42,233,165,139,246,14,0,161,203,184,221,173,11,34,1,161,203,184,221,173,11,33,1,39,0,203,184,221,173,11,6,18,51,48,52,49,50,48,49,48,57,48,55,49,51,51,57,53,50,48,0,1,0,233,165,139,246,14,2,1,161,233,165,139,246,14,0,1,161,233,165,139,246,14,1,1,129,233,165,139,246,14,3,1,72,203,184,221,173,11,16,1,118,1,2,105,100,119,36,99,97,49,50,50,99,48,52,45,100,55,98,51,45,52,102,55,48,45,57,57,53,49,45,57,54,98,102,100,97,57,98,54,98,50,52,161,203,184,221,173,11,21,1,161,203,184,221,173,11,22,1,39,0,203,184,221,173,11,1,36,99,97,49,50,50,99,48,52,45,100,55,98,51,45,52,102,55,48,45,57,57,53,49,45,57,54,98,102,100,97,57,98,54,98,50,52,1,40,0,233,165,139,246,14,10,2,105,100,1,119,36,99,97,49,50,50,99,48,52,45,100,55,98,51,45,52,102,55,48,45,57,57,53,49,45,57,54,98,102,100,97,57,98,54,98,50,52,40,0,233,165,139,246,14,10,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,233,165,139,246,14,10,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,233,165,139,246,14,10,4,100,101,115,99,1,119,0,40,0,233,165,139,246,14,10,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,233,165,139,246,14,10,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,241,120,204,39,0,203,184,221,173,11,4,36,99,97,49,50,50,99,48,52,45,100,55,98,51,45,52,102,55,48,45,57,57,53,49,45,57,54,98,102,100,97,57,98,54,98,50,52,0,40,0,233,165,139,246,14,10,4,105,99,111,110,1,119,0,40,0,233,165,139,246,14,10,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,233,165,139,246,14,10,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,233,165,139,246,14,10,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,2,161,233,165,139,246,14,20,1,129,233,165,139,246,14,6,1,161,233,165,139,246,14,22,1,161,233,165,139,246,14,23,1,129,233,165,139,246,14,24,1,161,233,165,139,246,14,25,1,161,233,165,139,246,14,26,1,129,233,165,139,246,14,27,1,161,233,165,139,246,14,28,1,161,233,165,139,246,14,29,1,129,233,165,139,246,14,30,1,161,233,165,139,246,14,31,1,161,233,165,139,246,14,32,1,129,233,165,139,246,14,33,1,161,233,165,139,246,14,34,1,161,233,165,139,246,14,35,1,129,233,165,139,246,14,36,1,161,233,165,139,246,14,37,1,161,233,165,139,246,14,38,1,129,233,165,139,246,14,39,1,3,145,159,164,217,14,0,161,135,232,133,203,9,12,1,161,135,232,133,203,9,13,1,129,135,232,133,203,9,14,1,12,154,243,157,196,14,0,161,145,159,164,217,14,0,1,161,145,159,164,217,14,1,1,129,145,159,164,217,14,2,1,161,154,243,157,196,14,0,1,161,154,243,157,196,14,1,1,129,154,243,157,196,14,2,1,161,154,243,157,196,14,3,1,161,154,243,157,196,14,4,1,129,154,243,157,196,14,5,1,161,154,243,157,196,14,6,1,161,154,243,157,196,14,7,1,129,154,243,157,196,14,8,1,2,149,161,132,184,14,0,161,235,178,165,206,5,68,219,2,161,149,161,132,184,14,218,2,2,1,173,187,245,170,14,0,161,164,203,250,235,13,6,46,3,252,218,241,167,14,0,161,251,189,220,155,14,0,1,161,251,189,220,155,14,1,1,168,251,189,220,155,14,2,1,119,9,231,186,170,229,191,181,231,137,136,3,251,189,220,155,14,0,161,210,228,153,221,12,0,1,161,210,228,153,221,12,1,1,161,210,228,153,221,12,2,1,17,201,191,159,147,14,0,161,149,189,189,215,8,0,1,161,149,189,189,215,8,1,1,129,149,189,189,215,8,2,1,161,213,161,242,209,13,31,1,161,133,159,138,205,12,124,1,161,133,159,138,205,12,125,1,129,201,191,159,147,14,2,1,161,201,191,159,147,14,4,1,161,201,191,159,147,14,5,1,129,201,191,159,147,14,6,1,161,201,191,159,147,14,0,1,161,201,191,159,147,14,1,1,129,201,191,159,147,14,9,1,161,201,191,159,147,14,3,1,161,201,191,159,147,14,10,1,161,201,191,159,147,14,11,1,129,201,191,159,147,14,12,1,1,139,240,196,145,14,0,161,200,203,236,184,2,34,138,2,1,164,203,250,235,13,0,33,1,4,109,101,116,97,12,108,97,115,116,95,115,121,110,99,95,97,116,7,7,180,230,210,212,13,0,161,175,225,172,150,8,8,1,161,175,225,172,150,8,9,1,136,175,225,172,150,8,10,1,118,2,2,105,100,119,36,100,48,52,57,54,51,50,52,45,53,53,55,48,45,52,48,48,54,45,98,52,101,97,45,100,98,55,53,49,54,100,50,49,50,102,100,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,41,200,235,161,175,225,172,150,8,7,1,161,175,225,172,150,8,4,1,161,175,225,172,150,8,5,1,129,180,230,210,212,13,2,1,34,213,161,242,209,13,0,161,133,159,138,205,12,128,1,1,161,133,159,138,205,12,129,1,1,129,133,159,138,205,12,130,1,1,136,133,159,138,205,12,108,1,118,1,2,105,100,119,36,55,101,98,54,57,55,99,100,45,54,97,53,53,45,52,48,98,98,45,57,54,97,99,45,48,100,52,97,51,98,99,57,50,52,98,50,161,133,159,138,205,12,109,1,161,213,161,242,209,13,1,1,39,0,203,184,221,173,11,1,36,55,101,98,54,57,55,99,100,45,54,97,53,53,45,52,48,98,98,45,57,54,97,99,45,48,100,52,97,51,98,99,57,50,52,98,50,1,40,0,213,161,242,209,13,6,2,105,100,1,119,36,55,101,98,54,57,55,99,100,45,54,97,53,53,45,52,48,98,98,45,57,54,97,99,45,48,100,52,97,51,98,99,57,50,52,98,50,33,0,213,161,242,209,13,6,4,110,97,109,101,1,40,0,213,161,242,209,13,6,3,98,105,100,1,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,40,0,213,161,242,209,13,6,4,100,101,115,99,1,119,0,40,0,213,161,242,209,13,6,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,40,0,213,161,242,209,13,6,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,48,178,5,39,0,203,184,221,173,11,4,36,55,101,98,54,57,55,99,100,45,54,97,53,53,45,52,48,98,98,45,57,54,97,99,45,48,100,52,97,51,98,99,57,50,52,98,50,0,40,0,213,161,242,209,13,6,4,105,99,111,110,1,119,0,40,0,213,161,242,209,13,6,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,213,161,242,209,13,6,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,213,161,242,209,13,6,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,2,161,213,161,242,209,13,16,1,161,213,161,242,209,13,8,1,161,213,161,242,209,13,18,1,161,213,161,242,209,13,19,1,168,213,161,242,209,13,20,1,119,4,71,114,105,100,168,213,161,242,209,13,21,1,122,4,56,115,160,190,64,16,0,168,213,161,242,209,13,22,1,122,0,0,0,0,102,48,178,16,136,152,158,185,230,10,6,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,48,178,16,2,105,100,119,36,55,101,98,54,57,55,99,100,45,54,97,53,53,45,52,48,98,98,45,57,54,97,99,45,48,100,52,97,51,98,99,57,50,52,98,50,161,133,159,138,205,12,127,1,161,133,159,138,205,12,53,1,161,133,159,138,205,12,58,1,129,213,161,242,209,13,2,1,161,213,161,242,209,13,27,1,161,213,161,242,209,13,0,1,161,213,161,242,209,13,5,1,129,213,161,242,209,13,30,1,64,173,252,148,184,13,0,161,156,148,170,169,10,12,1,161,156,148,170,169,10,9,1,161,156,148,170,169,10,10,1,129,156,148,170,169,10,15,1,161,173,252,148,184,13,0,1,161,164,155,139,169,7,0,1,161,164,155,139,169,7,1,1,129,164,155,139,169,7,34,1,161,173,252,148,184,13,4,1,161,161,178,132,150,11,58,1,161,161,178,132,150,11,59,1,129,173,252,148,184,13,7,1,161,173,252,148,184,13,8,1,161,164,155,139,169,7,32,1,161,164,155,139,169,7,33,1,129,173,252,148,184,13,11,1,161,173,252,148,184,13,12,1,161,164,155,139,169,7,8,1,161,164,155,139,169,7,9,1,129,173,252,148,184,13,15,1,161,173,252,148,184,13,16,1,161,173,252,148,184,13,13,1,161,173,252,148,184,13,14,1,129,173,252,148,184,13,19,1,161,173,252,148,184,13,20,1,161,173,252,148,184,13,9,1,161,173,252,148,184,13,10,1,129,173,252,148,184,13,23,1,161,173,252,148,184,13,24,1,161,173,252,148,184,13,21,1,161,173,252,148,184,13,22,1,129,173,252,148,184,13,27,1,161,173,252,148,184,13,28,1,161,164,155,139,169,7,28,1,161,164,155,139,169,7,29,1,129,173,252,148,184,13,31,1,161,173,252,148,184,13,32,1,161,173,252,148,184,13,29,1,161,173,252,148,184,13,30,1,129,173,252,148,184,13,35,1,136,207,228,238,162,8,22,1,118,1,2,105,100,119,36,100,100,98,57,51,98,97,55,45,48,54,99,55,45,52,49,55,54,45,57,56,50,97,45,100,55,52,50,51,101,48,57,98,52,52,49,161,173,252,148,184,13,33,1,161,173,252,148,184,13,34,1,168,130,180,254,251,6,6,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,161,173,252,148,184,13,36,1,161,173,252,148,184,13,41,1,161,173,252,148,184,13,42,1,129,173,252,148,184,13,39,1,161,173,252,148,184,13,44,1,161,173,252,148,184,13,37,1,161,173,252,148,184,13,38,1,129,173,252,148,184,13,47,1,161,173,252,148,184,13,48,1,161,173,252,148,184,13,25,1,161,173,252,148,184,13,26,1,129,173,252,148,184,13,51,1,161,173,252,148,184,13,52,1,161,173,252,148,184,13,49,1,161,173,252,148,184,13,50,1,129,173,252,148,184,13,55,1,161,173,252,148,184,13,56,1,161,173,252,148,184,13,5,1,161,173,252,148,184,13,6,1,129,173,252,148,184,13,59,1,30,243,239,182,181,13,0,136,240,149,229,225,6,0,1,118,1,2,105,100,119,36,53,54,54,56,57,101,52,50,45,49,102,101,56,45,52,97,97,102,45,56,50,99,53,45,99,51,100,99,98,102,99,51,98,50,53,52,161,240,149,229,225,6,1,1,161,240,149,229,225,6,2,1,39,0,203,184,221,173,11,1,36,53,54,54,56,57,101,52,50,45,49,102,101,56,45,52,97,97,102,45,56,50,99,53,45,99,51,100,99,98,102,99,51,98,50,53,52,1,40,0,243,239,182,181,13,3,2,105,100,1,119,36,53,54,54,56,57,101,52,50,45,49,102,101,56,45,52,97,97,102,45,56,50,99,53,45,99,51,100,99,98,102,99,51,98,50,53,52,40,0,243,239,182,181,13,3,4,110,97,109,101,1,119,0,40,0,243,239,182,181,13,3,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,243,239,182,181,13,3,4,100,101,115,99,1,119,0,40,0,243,239,182,181,13,3,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,243,239,182,181,13,3,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,241,141,103,39,0,203,184,221,173,11,4,36,53,54,54,56,57,101,52,50,45,49,102,101,56,45,52,97,97,102,45,56,50,99,53,45,99,51,100,99,98,102,99,51,98,50,53,52,0,40,0,243,239,182,181,13,3,4,105,99,111,110,1,119,0,40,0,243,239,182,181,13,3,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,243,239,182,181,13,3,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,101,241,141,103,40,0,243,239,182,181,13,3,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,136,243,239,182,181,13,0,1,118,1,2,105,100,119,36,51,53,100,51,57,57,98,57,45,49,57,55,101,45,52,57,99,54,45,97,98,102,56,45,101,51,57,51,49,101,48,97,55,51,49,51,161,243,239,182,181,13,1,1,161,243,239,182,181,13,2,1,39,0,203,184,221,173,11,1,36,51,53,100,51,57,57,98,57,45,49,57,55,101,45,52,57,99,54,45,97,98,102,56,45,101,51,57,51,49,101,48,97,55,51,49,51,1,40,0,243,239,182,181,13,18,2,105,100,1,119,36,51,53,100,51,57,57,98,57,45,49,57,55,101,45,52,57,99,54,45,97,98,102,56,45,101,51,57,51,49,101,48,97,55,51,49,51,40,0,243,239,182,181,13,18,4,110,97,109,101,1,119,0,40,0,243,239,182,181,13,18,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,243,239,182,181,13,18,4,100,101,115,99,1,119,0,40,0,243,239,182,181,13,18,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,243,239,182,181,13,18,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,241,141,156,39,0,203,184,221,173,11,4,36,51,53,100,51,57,57,98,57,45,49,57,55,101,45,52,57,99,54,45,97,98,102,56,45,101,51,57,51,49,101,48,97,55,51,49,51,0,40,0,243,239,182,181,13,18,4,105,99,111,110,1,119,0,40,0,243,239,182,181,13,18,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,243,239,182,181,13,18,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,101,241,141,156,40,0,243,239,182,181,13,18,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,1,161,239,241,154,13,0,161,158,184,218,165,3,37,106,72,166,201,221,141,13,0,161,182,172,247,194,5,0,1,161,182,172,247,194,5,1,1,129,182,172,247,194,5,2,1,161,170,255,211,105,34,1,161,245,220,194,52,9,1,161,245,220,194,52,10,1,136,166,201,221,141,13,2,1,118,2,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,85,132,208,161,166,201,221,141,13,4,1,161,166,201,221,141,13,5,1,136,166,201,221,141,13,6,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,85,132,209,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,161,166,201,221,141,13,7,1,161,166,201,221,141,13,8,1,136,166,201,221,141,13,9,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,85,134,151,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,161,166,201,221,141,13,10,1,161,166,201,221,141,13,11,1,136,166,201,221,141,13,12,1,118,2,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,85,134,152,39,0,203,184,221,173,11,1,36,98,98,101,55,102,100,54,99,45,99,99,56,102,45,53,48,55,57,45,98,48,52,53,45,54,49,57,55,52,99,48,57,57,98,54,100,1,40,0,166,201,221,141,13,16,2,105,100,1,119,36,98,98,101,55,102,100,54,99,45,99,99,56,102,45,53,48,55,57,45,98,48,52,53,45,54,49,57,55,52,99,48,57,57,98,54,100,40,0,166,201,221,141,13,16,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,166,201,221,141,13,16,3,98,105,100,1,119,36,98,98,101,55,102,100,54,99,45,99,99,56,102,45,53,48,55,57,45,98,48,52,53,45,54,49,57,55,52,99,48,57,57,98,54,100,40,0,166,201,221,141,13,16,4,100,101,115,99,1,119,0,40,0,166,201,221,141,13,16,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,166,201,221,141,13,16,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,85,140,82,39,0,203,184,221,173,11,4,36,98,98,101,55,102,100,54,99,45,99,99,56,102,45,53,48,55,57,45,98,48,52,53,45,54,49,57,55,52,99,48,57,57,98,54,100,0,40,0,166,201,221,141,13,16,4,105,99,111,110,1,119,0,40,0,166,201,221,141,13,16,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,166,201,221,141,13,16,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,166,201,221,141,13,16,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,168,166,201,221,141,13,27,1,122,4,56,115,160,190,64,16,0,168,166,201,221,141,13,26,1,122,0,0,0,0,102,85,140,82,40,0,166,201,221,141,13,16,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,161,166,201,221,141,13,0,1,161,166,201,221,141,13,1,1,136,166,201,221,141,13,15,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,85,167,96,2,105,100,119,36,48,101,55,99,100,101,102,50,45,49,48,99,50,45,52,52,101,99,45,56,98,54,49,45,49,97,100,101,48,98,102,53,100,51,102,102,161,166,201,221,141,13,3,1,161,166,201,221,141,13,31,1,161,166,201,221,141,13,32,1,136,166,201,221,141,13,33,1,118,2,2,105,100,119,36,48,101,55,99,100,101,102,50,45,49,48,99,50,45,52,52,101,99,45,56,98,54,49,45,49,97,100,101,48,98,102,53,100,51,102,102,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,85,167,97,161,166,201,221,141,13,35,1,161,166,201,221,141,13,36,1,161,245,220,194,52,38,1,161,166,201,221,141,13,38,1,161,166,201,221,141,13,39,1,161,166,201,221,141,13,40,1,136,140,152,206,145,6,100,1,118,1,2,105,100,119,36,50,97,54,101,53,101,50,49,45,97,57,51,56,45,52,53,97,53,45,97,52,52,53,45,100,48,98,55,49,52,57,53,98,48,55,55,161,140,152,206,145,6,101,1,161,245,220,194,52,7,1,39,0,203,184,221,173,11,1,36,50,97,54,101,53,101,50,49,45,97,57,51,56,45,52,53,97,53,45,97,52,52,53,45,100,48,98,55,49,52,57,53,98,48,55,55,1,40,0,166,201,221,141,13,47,2,105,100,1,119,36,50,97,54,101,53,101,50,49,45,97,57,51,56,45,52,53,97,53,45,97,52,52,53,45,100,48,98,55,49,52,57,53,98,48,55,55,40,0,166,201,221,141,13,47,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,166,201,221,141,13,47,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,166,201,221,141,13,47,4,100,101,115,99,1,119,0,40,0,166,201,221,141,13,47,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,166,201,221,141,13,47,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,86,193,40,39,0,203,184,221,173,11,4,36,50,97,54,101,53,101,50,49,45,97,57,51,56,45,52,53,97,53,45,97,52,52,53,45,100,48,98,55,49,52,57,53,98,48,55,55,0,40,0,166,201,221,141,13,47,4,105,99,111,110,1,119,0,40,0,166,201,221,141,13,47,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,166,201,221,141,13,47,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,166,201,221,141,13,47,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,166,201,221,141,13,34,1,161,166,201,221,141,13,58,1,161,166,201,221,141,13,57,1,129,166,201,221,141,13,37,1,161,166,201,221,141,13,60,1,161,166,201,221,141,13,61,1,129,166,201,221,141,13,62,1,161,166,201,221,141,13,63,1,161,166,201,221,141,13,64,1,40,0,166,201,221,141,13,47,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,161,166,201,221,141,13,66,1,161,166,201,221,141,13,67,1,129,166,201,221,141,13,65,1,2,180,205,189,133,13,0,161,200,142,208,241,4,152,1,16,161,180,205,189,133,13,15,4,1,248,210,237,129,13,0,161,223,209,193,147,11,80,2,7,211,202,217,232,12,0,161,141,245,194,142,11,4,1,161,141,245,194,142,11,5,1,129,141,245,194,142,11,6,1,161,141,245,194,142,11,3,1,161,141,245,194,142,11,0,1,161,141,245,194,142,11,1,1,129,211,202,217,232,12,2,1,3,210,228,153,221,12,0,161,202,160,246,212,1,3,1,161,202,160,246,212,1,4,1,161,202,160,246,212,1,5,1,1,181,175,219,209,12,0,161,200,159,185,206,9,7,10,131,1,133,159,138,205,12,0,161,255,140,248,220,6,0,1,161,255,140,248,220,6,1,1,129,255,140,248,220,6,2,1,161,180,230,210,212,13,3,1,161,161,178,132,150,11,34,1,161,161,178,132,150,11,35,1,129,133,159,138,205,12,2,1,8,0,229,154,128,197,12,16,1,118,1,2,105,100,119,36,98,54,51,52,55,97,99,98,45,51,49,55,52,45,52,102,48,101,45,57,56,101,57,45,100,99,99,101,48,55,101,53,100,98,102,55,168,229,154,128,197,12,15,1,122,0,0,0,0,102,48,108,125,161,180,230,210,212,13,1,1,39,0,203,184,221,173,11,1,36,98,54,51,52,55,97,99,98,45,51,49,55,52,45,52,102,48,101,45,57,56,101,57,45,100,99,99,101,48,55,101,53,100,98,102,55,1,40,0,133,159,138,205,12,10,2,105,100,1,119,36,98,54,51,52,55,97,99,98,45,51,49,55,52,45,52,102,48,101,45,57,56,101,57,45,100,99,99,101,48,55,101,53,100,98,102,55,40,0,133,159,138,205,12,10,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,133,159,138,205,12,10,3,98,105,100,1,119,36,100,48,52,57,54,51,50,52,45,53,53,55,48,45,52,48,48,54,45,98,52,101,97,45,100,98,55,53,49,54,100,50,49,50,102,100,40,0,133,159,138,205,12,10,4,100,101,115,99,1,119,0,40,0,133,159,138,205,12,10,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,40,0,133,159,138,205,12,10,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,48,108,125,39,0,203,184,221,173,11,4,36,98,54,51,52,55,97,99,98,45,51,49,55,52,45,52,102,48,101,45,57,56,101,57,45,100,99,99,101,48,55,101,53,100,98,102,55,0,40,0,133,159,138,205,12,10,4,105,99,111,110,1,119,0,40,0,133,159,138,205,12,10,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,133,159,138,205,12,10,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,133,159,138,205,12,10,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,133,159,138,205,12,3,1,161,133,159,138,205,12,21,1,161,133,159,138,205,12,20,1,129,133,159,138,205,12,6,1,161,133,159,138,205,12,23,1,161,133,159,138,205,12,24,1,129,133,159,138,205,12,25,1,72,229,154,128,197,12,6,1,118,1,2,105,100,119,36,102,51,53,50,55,48,99,55,45,99,54,54,99,45,52,54,99,101,45,56,101,49,97,45,51,102,54,51,57,102,55,98,48,48,48,100,168,229,154,128,197,12,7,1,122,0,0,0,0,102,48,108,128,168,229,154,128,197,12,8,1,122,0,0,0,0,102,48,108,128,39,0,203,184,221,173,11,1,36,102,51,53,50,55,48,99,55,45,99,54,54,99,45,52,54,99,101,45,56,101,49,97,45,51,102,54,51,57,102,55,98,48,48,48,100,1,40,0,133,159,138,205,12,32,2,105,100,1,119,36,102,51,53,50,55,48,99,55,45,99,54,54,99,45,52,54,99,101,45,56,101,49,97,45,51,102,54,51,57,102,55,98,48,48,48,100,40,0,133,159,138,205,12,32,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,133,159,138,205,12,32,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,133,159,138,205,12,32,4,100,101,115,99,1,119,0,40,0,133,159,138,205,12,32,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,133,159,138,205,12,32,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,48,108,128,39,0,203,184,221,173,11,4,36,102,51,53,50,55,48,99,55,45,99,54,54,99,45,52,54,99,101,45,56,101,49,97,45,51,102,54,51,57,102,55,98,48,48,48,100,0,40,0,133,159,138,205,12,32,4,105,99,111,110,1,119,0,40,0,133,159,138,205,12,32,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,133,159,138,205,12,32,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,133,159,138,205,12,32,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,133,159,138,205,12,22,1,161,133,159,138,205,12,43,1,161,133,159,138,205,12,42,1,129,133,159,138,205,12,28,1,161,133,159,138,205,12,44,1,161,133,159,138,205,12,26,1,161,133,159,138,205,12,27,1,129,133,159,138,205,12,47,1,161,133,159,138,205,12,48,1,161,133,159,138,205,12,0,1,161,133,159,138,205,12,1,1,129,133,159,138,205,12,51,1,136,173,252,148,184,13,40,1,118,1,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,161,207,228,238,162,8,23,1,161,133,159,138,205,12,54,1,39,0,203,184,221,173,11,1,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,1,40,0,133,159,138,205,12,59,2,105,100,1,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,33,0,133,159,138,205,12,59,4,110,97,109,101,1,40,0,133,159,138,205,12,59,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,133,159,138,205,12,59,4,100,101,115,99,1,119,0,40,0,133,159,138,205,12,59,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,33,0,133,159,138,205,12,59,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,0,33,0,133,159,138,205,12,59,4,105,99,111,110,1,40,0,133,159,138,205,12,59,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,133,159,138,205,12,59,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,133,159,138,205,12,59,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,133,159,138,205,12,52,1,161,133,159,138,205,12,70,1,161,133,159,138,205,12,69,1,129,133,159,138,205,12,55,1,161,133,159,138,205,12,72,1,161,133,159,138,205,12,73,1,129,133,159,138,205,12,74,1,161,133,159,138,205,12,75,1,161,133,159,138,205,12,76,1,161,133,159,138,205,12,61,1,161,133,159,138,205,12,78,1,161,133,159,138,205,12,79,1,161,133,159,138,205,12,80,1,161,201,129,238,197,4,27,1,161,201,129,238,197,4,28,1,168,133,159,138,205,12,67,1,119,23,123,34,116,121,34,58,48,44,34,118,97,108,117,101,34,58,34,240,159,141,182,34,125,161,133,159,138,205,12,84,1,161,133,159,138,205,12,85,1,161,133,159,138,205,12,83,1,161,133,159,138,205,12,87,1,161,133,159,138,205,12,88,1,161,133,159,138,205,12,89,1,8,0,133,159,138,205,12,66,1,118,1,2,105,100,119,36,101,57,55,56,55,55,102,53,45,99,51,54,53,45,52,48,50,53,45,57,101,54,97,45,101,53,57,48,99,52,98,49,57,100,98,98,161,133,159,138,205,12,65,1,161,133,159,138,205,12,91,1,39,0,203,184,221,173,11,1,36,101,57,55,56,55,55,102,53,45,99,51,54,53,45,52,48,50,53,45,57,101,54,97,45,101,53,57,48,99,52,98,49,57,100,98,98,1,40,0,133,159,138,205,12,96,2,105,100,1,119,36,101,57,55,56,55,55,102,53,45,99,51,54,53,45,52,48,50,53,45,57,101,54,97,45,101,53,57,48,99,52,98,49,57,100,98,98,40,0,133,159,138,205,12,96,4,110,97,109,101,1,119,5,66,111,97,114,100,40,0,133,159,138,205,12,96,3,98,105,100,1,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,40,0,133,159,138,205,12,96,4,100,101,115,99,1,119,0,40,0,133,159,138,205,12,96,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,2,40,0,133,159,138,205,12,96,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,48,177,159,39,0,203,184,221,173,11,4,36,101,57,55,56,55,55,102,53,45,99,51,54,53,45,52,48,50,53,45,57,101,54,97,45,101,53,57,48,99,52,98,49,57,100,98,98,0,40,0,133,159,138,205,12,96,4,105,99,111,110,1,119,0,40,0,133,159,138,205,12,96,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,133,159,138,205,12,96,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,133,159,138,205,12,96,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,136,133,159,138,205,12,93,1,118,1,2,105,100,119,36,102,48,99,53,57,57,50,49,45,48,52,101,101,45,52,57,55,49,45,57,57,53,99,45,55,57,98,55,102,100,56,99,48,48,101,50,161,133,159,138,205,12,94,1,161,133,159,138,205,12,95,1,39,0,203,184,221,173,11,1,36,102,48,99,53,57,57,50,49,45,48,52,101,101,45,52,57,55,49,45,57,57,53,99,45,55,57,98,55,102,100,56,99,48,48,101,50,1,40,0,133,159,138,205,12,111,2,105,100,1,119,36,102,48,99,53,57,57,50,49,45,48,52,101,101,45,52,57,55,49,45,57,57,53,99,45,55,57,98,55,102,100,56,99,48,48,101,50,40,0,133,159,138,205,12,111,4,110,97,109,101,1,119,8,67,97,108,101,110,100,97,114,40,0,133,159,138,205,12,111,3,98,105,100,1,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,40,0,133,159,138,205,12,111,4,100,101,115,99,1,119,0,40,0,133,159,138,205,12,111,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,3,40,0,133,159,138,205,12,111,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,48,177,162,39,0,203,184,221,173,11,4,36,102,48,99,53,57,57,50,49,45,48,52,101,101,45,52,57,55,49,45,57,57,53,99,45,55,57,98,55,102,100,56,99,48,48,101,50,0,40,0,133,159,138,205,12,111,4,105,99,111,110,1,119,0,40,0,133,159,138,205,12,111,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,133,159,138,205,12,111,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,133,159,138,205,12,111,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,133,159,138,205,12,71,1,161,133,159,138,205,12,4,1,161,133,159,138,205,12,5,1,129,201,129,238,197,4,29,1,161,133,159,138,205,12,123,1,161,133,159,138,205,12,90,1,161,133,159,138,205,12,110,1,129,133,159,138,205,12,126,1,23,229,154,128,197,12,0,161,248,153,216,10,0,1,161,248,153,216,10,1,1,129,248,153,216,10,2,1,161,229,154,128,197,12,0,1,161,229,154,128,197,12,1,1,129,229,154,128,197,12,2,1,72,158,156,181,152,10,6,1,118,1,2,105,100,119,36,100,48,52,57,54,51,50,52,45,53,53,55,48,45,52,48,48,54,45,98,52,101,97,45,100,98,55,53,49,54,100,50,49,50,102,100,161,176,154,159,227,1,2,1,161,176,154,159,227,1,3,1,39,0,203,184,221,173,11,1,36,100,48,52,57,54,51,50,52,45,53,53,55,48,45,52,48,48,54,45,98,52,101,97,45,100,98,55,53,49,54,100,50,49,50,102,100,1,40,0,229,154,128,197,12,9,2,105,100,1,119,36,100,48,52,57,54,51,50,52,45,53,53,55,48,45,52,48,48,54,45,98,52,101,97,45,100,98,55,53,49,54,100,50,49,50,102,100,40,0,229,154,128,197,12,9,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,229,154,128,197,12,9,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,229,154,128,197,12,9,4,100,101,115,99,1,119,0,40,0,229,154,128,197,12,9,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,33,0,229,154,128,197,12,9,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,100,48,52,57,54,51,50,52,45,53,53,55,48,45,52,48,48,54,45,98,52,101,97,45,100,98,55,53,49,54,100,50,49,50,102,100,0,40,0,229,154,128,197,12,9,4,105,99,111,110,1,119,0,40,0,229,154,128,197,12,9,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,229,154,128,197,12,9,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,229,154,128,197,12,9,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,2,161,229,154,128,197,12,19,1,129,229,154,128,197,12,5,1,16,149,129,169,191,12,0,161,186,197,166,179,15,3,1,161,188,171,136,250,8,0,1,161,188,171,136,250,8,1,1,129,188,171,136,250,8,2,1,161,149,129,169,191,12,0,1,161,200,205,214,172,10,27,1,161,200,205,214,172,10,28,1,129,149,129,169,191,12,3,1,161,149,129,169,191,12,4,1,161,149,129,169,191,12,1,1,161,149,129,169,191,12,2,1,129,149,129,169,191,12,7,1,161,149,129,169,191,12,8,1,161,186,197,166,179,15,0,1,161,186,197,166,179,15,1,1,129,149,129,169,191,12,11,1,10,177,161,136,243,11,0,161,241,155,213,233,1,49,1,161,241,155,213,233,1,50,1,129,214,139,213,136,8,65,1,161,214,139,213,136,8,63,1,161,214,139,213,136,8,64,1,129,177,161,136,243,11,2,1,161,241,155,213,233,1,21,1,161,177,161,136,243,11,3,1,161,177,161,136,243,11,4,1,129,177,161,136,243,11,5,1,1,205,149,231,236,11,0,161,175,147,217,214,1,32,68,3,162,159,252,196,11,0,161,233,247,183,159,1,1,1,161,233,247,183,159,1,2,1,129,233,247,183,159,1,3,1,37,203,184,221,173,11,0,39,1,4,100,97,116,97,6,102,111,108,100,101,114,1,39,0,203,184,221,173,11,0,5,118,105,101,119,115,1,39,0,203,184,221,173,11,0,7,115,101,99,116,105,111,110,1,39,0,203,184,221,173,11,0,4,109,101,116,97,1,39,0,203,184,221,173,11,0,8,114,101,108,97,116,105,111,110,1,39,0,203,184,221,173,11,2,8,102,97,118,111,114,105,116,101,1,39,0,203,184,221,173,11,2,6,114,101,99,101,110,116,1,39,0,203,184,221,173,11,2,5,116,114,97,115,104,1,39,0,203,184,221,173,11,1,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,1,40,0,203,184,221,173,11,8,2,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,203,184,221,173,11,8,4,110,97,109,101,1,119,9,87,111,114,107,115,112,97,99,101,40,0,203,184,221,173,11,8,3,98,105,100,1,119,0,40,0,203,184,221,173,11,8,4,100,101,115,99,1,119,0,40,0,203,184,221,173,11,8,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,33,0,203,184,221,173,11,8,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,0,8,0,203,184,221,173,11,15,1,118,1,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,203,184,221,173,11,8,4,105,99,111,110,1,119,0,40,0,203,184,221,173,11,8,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,203,184,221,173,11,8,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,40,0,203,184,221,173,11,8,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,161,203,184,221,173,11,14,1,161,203,184,221,173,11,19,1,39,0,203,184,221,173,11,1,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,1,40,0,203,184,221,173,11,23,2,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,203,184,221,173,11,23,4,110,97,109,101,1,119,15,71,101,116,116,105,110,103,32,115,116,97,114,116,101,100,40,0,203,184,221,173,11,23,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,203,184,221,173,11,23,4,100,101,115,99,1,119,0,40,0,203,184,221,173,11,23,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,33,0,203,184,221,173,11,23,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,0,40,0,203,184,221,173,11,23,4,105,99,111,110,1,119,25,123,34,116,121,34,58,48,44,34,118,97,108,117,101,34,58,34,226,173,144,239,184,143,34,125,40,0,203,184,221,173,11,23,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,203,184,221,173,11,23,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,203,184,221,173,11,23,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,40,0,203,184,221,173,11,3,17,99,117,114,114,101,110,116,95,119,111,114,107,115,112,97,99,101,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,33,0,203,184,221,173,11,3,12,99,117,114,114,101,110,116,95,118,105,101,119,1,3,155,165,205,152,11,0,161,179,252,154,44,0,1,161,179,252,154,44,1,1,129,179,252,154,44,2,1,101,161,178,132,150,11,0,161,167,131,133,162,9,8,1,161,167,131,133,162,9,9,1,129,167,131,133,162,9,10,1,161,167,131,133,162,9,7,1,161,252,218,241,167,14,0,1,161,252,218,241,167,14,1,1,129,161,178,132,150,11,2,1,161,161,178,132,150,11,3,1,161,161,178,132,150,11,0,1,161,161,178,132,150,11,1,1,129,161,178,132,150,11,6,1,161,161,178,132,150,11,7,1,161,130,180,254,251,6,15,1,161,130,180,254,251,6,16,1,129,161,178,132,150,11,10,1,8,0,130,180,254,251,6,10,1,118,1,2,105,100,119,36,52,56,99,53,50,99,102,55,45,98,102,57,56,45,52,51,102,97,45,57,54,97,100,45,98,51,49,97,97,100,101,57,98,48,55,49,168,130,180,254,251,6,9,1,122,0,0,0,0,102,32,220,196,161,161,178,132,150,11,13,1,39,0,203,184,221,173,11,1,36,52,56,99,53,50,99,102,55,45,98,102,57,56,45,52,51,102,97,45,57,54,97,100,45,98,51,49,97,97,100,101,57,98,48,55,49,1,40,0,161,178,132,150,11,18,2,105,100,1,119,36,52,56,99,53,50,99,102,55,45,98,102,57,56,45,52,51,102,97,45,57,54,97,100,45,98,51,49,97,97,100,101,57,98,48,55,49,40,0,161,178,132,150,11,18,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,161,178,132,150,11,18,3,98,105,100,1,119,36,100,100,98,57,51,98,97,55,45,48,54,99,55,45,52,49,55,54,45,57,56,50,97,45,100,55,52,50,51,101,48,57,98,52,52,49,40,0,161,178,132,150,11,18,4,100,101,115,99,1,119,0,40,0,161,178,132,150,11,18,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,40,0,161,178,132,150,11,18,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,32,220,196,39,0,203,184,221,173,11,4,36,52,56,99,53,50,99,102,55,45,98,102,57,56,45,52,51,102,97,45,57,54,97,100,45,98,51,49,97,97,100,101,57,98,48,55,49,0,40,0,161,178,132,150,11,18,4,105,99,111,110,1,119,0,40,0,161,178,132,150,11,18,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,161,178,132,150,11,18,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,161,178,132,150,11,18,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,161,178,132,150,11,11,1,161,161,178,132,150,11,29,1,161,161,178,132,150,11,28,1,129,161,178,132,150,11,14,1,161,161,178,132,150,11,31,1,161,161,178,132,150,11,32,1,129,161,178,132,150,11,33,1,161,161,178,132,150,11,30,1,161,161,178,132,150,11,8,1,161,161,178,132,150,11,9,1,129,161,178,132,150,11,36,1,161,161,178,132,150,11,37,1,161,167,131,133,162,9,4,1,161,167,131,133,162,9,5,1,129,161,178,132,150,11,40,1,161,161,178,132,150,11,41,1,161,161,178,132,150,11,38,1,161,161,178,132,150,11,39,1,129,161,178,132,150,11,44,1,161,161,178,132,150,11,45,1,161,161,178,132,150,11,42,1,161,161,178,132,150,11,43,1,129,161,178,132,150,11,48,1,161,161,178,132,150,11,49,1,161,161,178,132,150,11,46,1,161,161,178,132,150,11,47,1,129,161,178,132,150,11,52,1,161,161,178,132,150,11,53,1,161,161,178,132,150,11,4,1,161,161,178,132,150,11,5,1,129,161,178,132,150,11,56,1,161,161,178,132,150,11,57,1,161,161,178,132,150,11,54,1,161,161,178,132,150,11,55,1,129,161,178,132,150,11,60,1,161,161,178,132,150,11,61,1,161,161,178,132,150,11,50,1,161,161,178,132,150,11,51,1,129,161,178,132,150,11,64,1,161,161,178,132,150,11,65,1,161,161,178,132,150,11,62,1,161,161,178,132,150,11,63,1,129,161,178,132,150,11,68,1,161,161,178,132,150,11,69,1,161,161,178,132,150,11,66,1,161,161,178,132,150,11,67,1,129,161,178,132,150,11,72,1,161,161,178,132,150,11,73,1,161,161,178,132,150,11,70,1,161,161,178,132,150,11,71,1,129,161,178,132,150,11,76,1,161,161,178,132,150,11,77,1,161,161,178,132,150,11,74,1,161,161,178,132,150,11,75,1,129,161,178,132,150,11,80,1,161,161,178,132,150,11,81,1,161,161,178,132,150,11,78,1,161,161,178,132,150,11,79,1,129,161,178,132,150,11,84,1,161,161,178,132,150,11,85,1,161,161,178,132,150,11,82,1,161,161,178,132,150,11,83,1,136,161,178,132,150,11,88,1,118,2,2,105,100,119,36,99,97,49,50,50,99,48,52,45,100,55,98,51,45,52,102,55,48,45,57,57,53,49,45,57,54,98,102,100,97,57,98,54,98,50,52,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,33,243,102,161,161,178,132,150,11,89,1,161,161,178,132,150,11,86,1,161,161,178,132,150,11,87,1,129,161,178,132,150,11,92,1,161,161,178,132,150,11,93,1,161,167,131,133,162,9,0,1,161,167,131,133,162,9,1,1,129,161,178,132,150,11,96,1,1,223,209,193,147,11,0,161,213,255,156,145,1,1,81,7,141,245,194,142,11,0,161,158,182,250,251,9,12,1,161,158,182,250,251,9,13,1,129,158,182,250,251,9,14,1,161,158,182,250,251,9,11,1,161,158,182,250,251,9,8,1,161,158,182,250,251,9,9,1,129,141,245,194,142,11,2,1,3,253,205,145,137,11,0,161,180,205,189,133,13,15,1,161,180,205,189,133,13,19,5,161,253,205,145,137,11,5,4,3,142,130,192,134,11,0,161,207,228,238,162,8,47,1,161,207,228,238,162,8,48,1,161,207,228,238,162,8,46,1,1,139,152,215,249,10,0,161,231,189,134,196,8,76,34,1,255,255,147,249,10,0,161,182,143,233,195,4,110,3,2,152,158,185,230,10,0,39,0,203,184,221,173,11,7,18,51,48,52,49,50,48,49,48,57,48,55,49,51,51,57,53,50,48,0,8,0,152,158,185,230,10,0,6,118,2,2,105,100,119,36,101,48,102,101,54,56,54,55,45,50,48,56,102,45,52,51,57,57,45,97,56,56,97,45,101,57,98,97,102,52,56,97,99,48,53,101,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,101,241,153,125,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,101,241,153,129,2,105,100,119,36,53,54,54,56,57,101,52,50,45,49,102,101,56,45,52,97,97,102,45,56,50,99,53,45,99,51,100,99,98,102,99,51,98,50,53,52,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,101,241,153,131,2,105,100,119,36,51,53,100,51,57,57,98,57,45,49,57,55,101,45,52,57,99,54,45,97,98,102,56,45,101,51,57,51,49,101,48,97,55,51,49,51,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,101,241,153,133,2,105,100,119,36,50,57,55,48,52,49,52,101,45,99,99,50,48,45,52,51,50,102,45,97,100,49,54,45,52,50,101,99,55,49,55,51,54,100,53,57,118,2,2,105,100,119,36,102,57,101,48,48,54,53,49,45,49,53,48,101,45,52,50,56,56,45,56,48,55,57,45,50,50,100,48,54,97,50,55,54,97,55,49,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,101,241,153,136,118,2,2,105,100,119,36,56,54,54,57,52,102,97,100,45,54,55,52,97,45,52,54,55,52,45,56,52,100,48,45,51,50,99,52,56,54,97,55,55,48,98,52,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,101,241,153,140,1,145,190,137,224,10,0,161,155,159,180,195,15,5,2,3,178,162,190,217,10,0,161,184,201,188,172,10,0,1,161,184,201,188,172,10,1,1,161,184,201,188,172,10,2,1,3,197,254,154,201,10,0,161,244,226,228,149,2,1,1,161,244,226,228,149,2,2,1,129,244,226,228,149,2,29,1,2,248,196,187,185,10,0,161,252,171,209,175,15,3,26,168,248,196,187,185,10,25,1,122,0,0,0,0,102,88,52,95,1,135,240,136,178,10,0,161,184,231,170,67,5,45,30,200,205,214,172,10,0,161,161,178,132,150,11,12,1,161,161,178,132,150,11,17,1,129,186,197,166,179,15,6,1,161,200,205,214,172,10,0,1,161,200,205,214,172,10,1,1,129,200,205,214,172,10,2,1,161,186,197,166,179,15,4,1,161,186,197,166,179,15,5,1,129,200,205,214,172,10,5,1,161,200,205,214,172,10,3,1,161,200,205,214,172,10,4,1,129,200,205,214,172,10,8,1,161,200,205,214,172,10,9,1,161,200,205,214,172,10,10,1,129,200,205,214,172,10,11,1,161,200,205,214,172,10,6,1,161,200,205,214,172,10,7,1,129,200,205,214,172,10,14,1,161,200,205,214,172,10,12,1,161,200,205,214,172,10,13,1,129,200,205,214,172,10,17,1,161,200,205,214,172,10,15,1,161,200,205,214,172,10,16,1,129,200,205,214,172,10,20,1,161,200,205,214,172,10,18,1,161,200,205,214,172,10,19,1,129,200,205,214,172,10,23,1,161,200,205,214,172,10,21,1,161,200,205,214,172,10,22,1,129,200,205,214,172,10,26,1,3,184,201,188,172,10,0,161,142,130,192,134,11,0,1,161,142,130,192,134,11,1,1,161,142,130,192,134,11,2,1,16,156,148,170,169,10,0,161,211,202,217,232,12,3,1,161,211,202,217,232,12,0,1,161,211,202,217,232,12,1,1,129,211,202,217,232,12,6,1,161,156,148,170,169,10,0,1,161,252,218,241,167,14,0,1,161,252,218,241,167,14,1,1,129,156,148,170,169,10,3,1,161,156,148,170,169,10,4,1,161,156,148,170,169,10,1,1,161,156,148,170,169,10,2,1,129,156,148,170,169,10,7,1,161,156,148,170,169,10,8,1,161,167,131,133,162,9,0,1,161,167,131,133,162,9,1,1,129,156,148,170,169,10,11,1,48,158,156,181,152,10,0,161,206,220,129,131,4,18,1,161,206,220,129,131,4,19,1,129,206,220,129,131,4,20,1,161,206,220,129,131,4,0,1,161,206,220,129,131,4,1,1,129,158,156,181,152,10,2,1,72,206,220,129,131,4,3,1,118,1,2,105,100,119,36,100,49,52,50,51,57,101,57,45,50,98,102,55,45,52,56,50,52,45,57,51,101,99,45,52,102,51,99,99,53,54,49,54,55,50,48,161,206,220,129,131,4,4,1,161,206,220,129,131,4,5,1,39,0,203,184,221,173,11,1,36,100,49,52,50,51,57,101,57,45,50,98,102,55,45,52,56,50,52,45,57,51,101,99,45,52,102,51,99,99,53,54,49,54,55,50,48,1,40,0,158,156,181,152,10,9,2,105,100,1,119,36,100,49,52,50,51,57,101,57,45,50,98,102,55,45,52,56,50,52,45,57,51,101,99,45,52,102,51,99,99,53,54,49,54,55,50,48,40,0,158,156,181,152,10,9,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,158,156,181,152,10,9,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,158,156,181,152,10,9,4,100,101,115,99,1,119,0,40,0,158,156,181,152,10,9,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,33,0,158,156,181,152,10,9,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,100,49,52,50,51,57,101,57,45,50,98,102,55,45,52,56,50,52,45,57,51,101,99,45,52,102,51,99,99,53,54,49,54,55,50,48,0,40,0,158,156,181,152,10,9,4,105,99,111,110,1,119,0,40,0,158,156,181,152,10,9,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,158,156,181,152,10,9,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,158,156,181,152,10,9,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,2,161,158,156,181,152,10,19,1,129,158,156,181,152,10,5,1,161,233,165,139,246,14,4,1,161,233,165,139,246,14,5,1,129,158,156,181,152,10,23,1,8,0,203,184,221,173,11,30,1,118,1,2,105,100,119,36,98,53,56,48,55,51,52,53,45,53,100,97,55,45,52,53,98,100,45,97,56,97,101,45,101,97,53,54,56,99,55,99,57,49,49,97,161,203,184,221,173,11,29,1,161,158,156,181,152,10,25,1,39,0,203,184,221,173,11,1,36,98,53,56,48,55,51,52,53,45,53,100,97,55,45,52,53,98,100,45,97,56,97,101,45,101,97,53,54,56,99,55,99,57,49,49,97,1,40,0,158,156,181,152,10,30,2,105,100,1,119,36,98,53,56,48,55,51,52,53,45,53,100,97,55,45,52,53,98,100,45,97,56,97,101,45,101,97,53,54,56,99,55,99,57,49,49,97,33,0,158,156,181,152,10,30,4,110,97,109,101,1,40,0,158,156,181,152,10,30,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,158,156,181,152,10,30,4,100,101,115,99,1,119,0,40,0,158,156,181,152,10,30,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,158,156,181,152,10,30,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,241,129,30,39,0,203,184,221,173,11,4,36,98,53,56,48,55,51,52,53,45,53,100,97,55,45,52,53,98,100,45,97,56,97,101,45,101,97,53,54,56,99,55,99,57,49,49,97,0,40,0,158,156,181,152,10,30,4,105,99,111,110,1,119,0,40,0,158,156,181,152,10,30,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,158,156,181,152,10,30,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,158,156,181,152,10,30,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,203,184,221,173,11,36,1,161,158,156,181,152,10,41,1,161,158,156,181,152,10,40,1,129,158,156,181,152,10,26,1,161,158,156,181,152,10,43,1,161,158,156,181,152,10,44,1,129,158,156,181,152,10,45,1,9,154,193,208,134,10,0,161,229,154,128,197,12,3,1,161,229,154,128,197,12,4,1,129,162,159,252,196,11,2,1,161,154,193,208,134,10,0,1,161,154,193,208,134,10,1,1,129,154,193,208,134,10,2,1,161,154,193,208,134,10,3,1,161,154,193,208,134,10,4,1,129,154,193,208,134,10,5,1,3,235,225,184,133,10,0,161,233,165,139,246,14,40,1,161,233,165,139,246,14,41,1,129,233,165,139,246,14,42,1,15,158,182,250,251,9,0,161,229,154,128,197,12,3,1,161,229,154,128,197,12,4,1,129,162,159,252,196,11,2,1,161,233,247,183,159,1,0,1,161,158,156,181,152,10,3,1,161,158,156,181,152,10,4,1,129,158,182,250,251,9,2,1,161,158,182,250,251,9,3,1,161,158,182,250,251,9,0,1,161,158,182,250,251,9,1,1,129,158,182,250,251,9,6,1,161,158,182,250,251,9,7,1,161,171,204,155,217,8,0,1,161,171,204,155,217,8,1,1,129,158,182,250,251,9,10,1,31,170,140,240,234,9,0,161,201,191,159,147,14,14,1,161,201,191,159,147,14,15,1,129,201,191,159,147,14,16,1,161,201,191,159,147,14,13,1,161,201,191,159,147,14,7,1,161,201,191,159,147,14,8,1,129,170,140,240,234,9,2,1,161,170,140,240,234,9,4,1,161,170,140,240,234,9,5,1,129,170,140,240,234,9,6,1,161,170,140,240,234,9,0,1,161,170,140,240,234,9,1,1,129,170,140,240,234,9,9,1,161,170,140,240,234,9,3,1,161,170,140,240,234,9,10,1,161,170,140,240,234,9,11,1,129,170,140,240,234,9,12,1,161,201,129,238,197,4,56,1,161,201,129,238,197,4,55,1,129,170,140,240,234,9,16,1,161,170,140,240,234,9,13,1,161,170,140,240,234,9,17,1,161,170,140,240,234,9,18,1,129,170,140,240,234,9,19,1,161,170,140,240,234,9,14,1,161,170,140,240,234,9,15,1,129,170,140,240,234,9,23,1,161,170,140,240,234,9,20,1,161,170,140,240,234,9,24,1,161,170,140,240,234,9,25,1,129,170,140,240,234,9,26,1,1,191,157,147,233,9,0,161,190,139,191,155,1,1,32,1,200,159,185,206,9,0,161,231,139,244,188,8,12,8,15,135,232,133,203,9,0,161,248,136,168,181,1,0,1,161,248,136,168,181,1,1,1,129,248,136,168,181,1,2,1,161,135,232,133,203,9,0,1,161,135,232,133,203,9,1,1,129,135,232,133,203,9,2,1,161,135,232,133,203,9,3,1,161,135,232,133,203,9,4,1,129,135,232,133,203,9,5,1,161,135,232,133,203,9,6,1,161,135,232,133,203,9,7,1,129,135,232,133,203,9,8,1,161,135,232,133,203,9,9,1,161,135,232,133,203,9,10,1,129,135,232,133,203,9,11,1,11,167,131,133,162,9,0,161,211,202,217,232,12,4,1,161,211,202,217,232,12,5,1,129,141,205,220,149,4,2,1,161,211,202,217,232,12,3,1,161,158,182,250,251,9,4,1,161,158,182,250,251,9,5,1,129,167,131,133,162,9,2,1,161,167,131,133,162,9,3,1,161,214,168,149,214,3,8,1,161,214,168,149,214,3,9,1,129,167,131,133,162,9,6,1,1,234,182,182,157,9,0,161,161,239,241,154,13,105,8,21,188,171,136,250,8,0,161,200,205,214,172,10,24,1,161,200,205,214,172,10,25,1,129,200,205,214,172,10,29,1,161,188,171,136,250,8,0,1,161,188,171,136,250,8,1,1,129,188,171,136,250,8,2,1,161,164,155,139,169,7,4,1,161,164,155,139,169,7,5,1,129,164,155,139,169,7,6,1,161,164,155,139,169,7,12,1,161,164,155,139,169,7,13,1,129,164,155,139,169,7,14,1,161,188,171,136,250,8,9,1,161,188,171,136,250,8,10,1,129,188,171,136,250,8,11,1,161,188,171,136,250,8,12,1,161,188,171,136,250,8,13,1,129,188,171,136,250,8,14,1,161,164,155,139,169,7,16,1,161,164,155,139,169,7,17,1,129,164,155,139,169,7,18,1,1,236,229,225,232,8,0,161,219,227,140,137,6,33,116,3,171,204,155,217,8,0,161,229,154,128,197,12,21,1,161,229,154,128,197,12,22,1,129,229,154,128,197,12,23,1,3,149,189,189,215,8,0,161,160,192,253,131,5,0,1,161,160,192,253,131,5,1,1,129,160,192,253,131,5,2,1,1,231,189,134,196,8,0,161,153,130,203,161,6,96,77,3,195,242,227,194,8,0,161,155,165,205,152,11,0,1,161,155,165,205,152,11,1,1,129,155,165,205,152,11,2,1,1,231,139,244,188,8,0,161,128,252,161,128,4,32,13,198,1,154,244,246,165,8,0,161,174,151,139,93,176,2,1,161,174,151,139,93,177,2,1,129,174,151,139,93,178,2,1,161,174,151,139,93,140,2,1,161,174,151,139,93,141,2,1,129,154,244,246,165,8,2,1,161,174,151,139,93,175,2,1,161,154,244,246,165,8,3,1,161,154,244,246,165,8,4,1,129,154,244,246,165,8,5,1,161,154,244,246,165,8,0,1,161,154,244,246,165,8,1,1,129,154,244,246,165,8,9,1,161,154,244,246,165,8,6,1,161,154,244,246,165,8,10,1,161,154,244,246,165,8,11,1,129,154,244,246,165,8,12,1,161,154,244,246,165,8,7,1,161,154,244,246,165,8,8,1,129,154,244,246,165,8,16,1,161,154,244,246,165,8,13,1,161,154,244,246,165,8,17,1,161,154,244,246,165,8,18,1,129,154,244,246,165,8,19,1,136,213,161,242,209,13,3,1,118,1,2,105,100,119,36,49,51,53,54,49,53,102,97,45,54,54,102,55,45,52,52,53,49,45,57,98,53,52,45,100,55,101,57,57,52,52,53,102,99,97,52,168,213,161,242,209,13,4,1,122,0,0,0,0,102,79,7,13,161,154,244,246,165,8,15,1,39,0,203,184,221,173,11,1,36,49,51,53,54,49,53,102,97,45,54,54,102,55,45,52,52,53,49,45,57,98,53,52,45,100,55,101,57,57,52,52,53,102,99,97,52,1,40,0,154,244,246,165,8,27,2,105,100,1,119,36,49,51,53,54,49,53,102,97,45,54,54,102,55,45,52,52,53,49,45,57,98,53,52,45,100,55,101,57,57,52,52,53,102,99,97,52,40,0,154,244,246,165,8,27,4,110,97,109,101,1,119,12,86,105,101,119,32,111,102,32,71,114,105,100,40,0,154,244,246,165,8,27,3,98,105,100,1,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,40,0,154,244,246,165,8,27,4,100,101,115,99,1,119,0,40,0,154,244,246,165,8,27,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,40,0,154,244,246,165,8,27,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,79,7,13,39,0,203,184,221,173,11,4,36,49,51,53,54,49,53,102,97,45,54,54,102,55,45,52,52,53,49,45,57,98,53,52,45,100,55,101,57,57,52,52,53,102,99,97,52,0,40,0,154,244,246,165,8,27,4,105,99,111,110,1,119,0,40,0,154,244,246,165,8,27,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,154,244,246,165,8,27,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,154,244,246,165,8,27,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,8,0,165,139,157,171,15,10,1,118,1,2,105,100,119,36,98,52,101,55,55,50,48,51,45,53,99,56,98,45,52,56,100,102,45,98,98,99,53,45,50,101,49,49,52,51,101,98,48,101,54,49,168,165,139,157,171,15,9,1,122,0,0,0,0,102,79,7,25,168,174,151,139,93,170,2,1,122,0,0,0,0,102,79,7,25,39,0,203,184,221,173,11,1,36,98,52,101,55,55,50,48,51,45,53,99,56,98,45,52,56,100,102,45,98,98,99,53,45,50,101,49,49,52,51,101,98,48,101,54,49,1,40,0,154,244,246,165,8,42,2,105,100,1,119,36,98,52,101,55,55,50,48,51,45,53,99,56,98,45,52,56,100,102,45,98,98,99,53,45,50,101,49,49,52,51,101,98,48,101,54,49,40,0,154,244,246,165,8,42,4,110,97,109,101,1,119,22,86,105,101,119,32,111,102,32,66,111,97,114,100,32,99,104,101,99,107,98,111,120,40,0,154,244,246,165,8,42,3,98,105,100,1,119,36,97,53,53,54,54,101,52,57,45,102,49,53,54,45,52,49,54,56,45,57,98,50,100,45,49,55,57,50,54,99,53,100,97,51,50,57,40,0,154,244,246,165,8,42,4,100,101,115,99,1,119,0,40,0,154,244,246,165,8,42,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,2,40,0,154,244,246,165,8,42,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,79,7,25,39,0,203,184,221,173,11,4,36,98,52,101,55,55,50,48,51,45,53,99,56,98,45,52,56,100,102,45,98,98,99,53,45,50,101,49,49,52,51,101,98,48,101,54,49,0,40,0,154,244,246,165,8,42,4,105,99,111,110,1,119,0,40,0,154,244,246,165,8,42,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,154,244,246,165,8,42,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,102,79,7,25,40,0,154,244,246,165,8,42,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,8,0,201,129,238,197,4,67,1,118,1,2,105,100,119,36,97,54,97,102,51,49,49,102,45,99,98,99,56,45,52,50,99,50,45,98,56,48,49,45,55,49,49,53,54,49,57,99,51,55,55,54,168,201,129,238,197,4,66,1,122,0,0,0,0,102,79,7,32,161,174,151,139,93,106,1,39,0,203,184,221,173,11,1,36,97,54,97,102,51,49,49,102,45,99,98,99,56,45,52,50,99,50,45,98,56,48,49,45,55,49,49,53,54,49,57,99,51,55,55,54,1,40,0,154,244,246,165,8,57,2,105,100,1,119,36,97,54,97,102,51,49,49,102,45,99,98,99,56,45,52,50,99,50,45,98,56,48,49,45,55,49,49,53,54,49,57,99,51,55,55,54,40,0,154,244,246,165,8,57,4,110,97,109,101,1,119,16,86,105,101,119,32,111,102,32,67,97,108,101,110,100,97,114,40,0,154,244,246,165,8,57,3,98,105,100,1,119,36,50,49,52,51,101,57,53,100,45,53,100,99,98,45,52,101,48,102,45,98,98,50,99,45,53,48,57,52,52,101,54,101,48,49,57,102,40,0,154,244,246,165,8,57,4,100,101,115,99,1,119,0,40,0,154,244,246,165,8,57,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,3,40,0,154,244,246,165,8,57,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,79,7,32,39,0,203,184,221,173,11,4,36,97,54,97,102,51,49,49,102,45,99,98,99,56,45,52,50,99,50,45,98,56,48,49,45,55,49,49,53,54,49,57,99,51,55,55,54,0,40,0,154,244,246,165,8,57,4,105,99,111,110,1,119,0,40,0,154,244,246,165,8,57,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,154,244,246,165,8,57,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,102,79,7,32,40,0,154,244,246,165,8,57,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,136,174,151,139,93,177,1,1,118,1,2,105,100,119,36,50,98,102,53,48,99,48,51,45,102,52,49,102,45,52,51,54,51,45,98,53,98,49,45,49,48,49,50,49,54,97,54,99,53,99,99,168,174,151,139,93,178,1,1,122,0,0,0,0,102,79,7,50,161,174,151,139,93,179,1,1,39,0,203,184,221,173,11,1,36,50,98,102,53,48,99,48,51,45,102,52,49,102,45,52,51,54,51,45,98,53,98,49,45,49,48,49,50,49,54,97,54,99,53,99,99,1,40,0,154,244,246,165,8,72,2,105,100,1,119,36,50,98,102,53,48,99,48,51,45,102,52,49,102,45,52,51,54,51,45,98,53,98,49,45,49,48,49,50,49,54,97,54,99,53,99,99,40,0,154,244,246,165,8,72,4,110,97,109,101,1,119,16,86,105,101,119,32,111,102,32,67,97,108,101,110,100,97,114,40,0,154,244,246,165,8,72,3,98,105,100,1,119,36,101,101,51,97,101,56,99,101,45,57,53,57,97,45,52,100,102,51,45,56,55,51,52,45,52,48,98,53,51,53,102,102,56,56,101,51,40,0,154,244,246,165,8,72,4,100,101,115,99,1,119,0,40,0,154,244,246,165,8,72,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,3,40,0,154,244,246,165,8,72,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,79,7,50,39,0,203,184,221,173,11,4,36,50,98,102,53,48,99,48,51,45,102,52,49,102,45,52,51,54,51,45,98,53,98,49,45,49,48,49,50,49,54,97,54,99,53,99,99,0,40,0,154,244,246,165,8,72,4,105,99,111,110,1,119,0,40,0,154,244,246,165,8,72,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,154,244,246,165,8,72,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,154,244,246,165,8,72,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,154,244,246,165,8,20,1,168,154,244,246,165,8,83,1,122,4,56,115,160,190,64,16,0,168,154,244,246,165,8,82,1,122,0,0,0,0,102,79,23,79,136,154,244,246,165,8,23,1,118,2,2,105,100,119,36,50,98,102,53,48,99,48,51,45,102,52,49,102,45,52,51,54,51,45,98,53,98,49,45,49,48,49,50,49,54,97,54,99,53,99,99,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,79,23,79,161,154,244,246,165,8,84,1,161,174,151,139,93,174,1,1,161,154,244,246,165,8,71,1,129,154,244,246,165,8,87,1,161,154,244,246,165,8,89,1,161,154,244,246,165,8,90,1,129,154,244,246,165,8,91,1,161,154,244,246,165,8,21,1,161,154,244,246,165,8,22,1,129,154,244,246,165,8,94,1,161,154,244,246,165,8,88,1,161,154,244,246,165,8,95,1,161,154,244,246,165,8,96,1,129,154,244,246,165,8,97,1,161,154,244,246,165,8,98,1,161,154,244,246,165,8,38,1,161,154,244,246,165,8,37,1,129,154,244,246,165,8,101,1,161,154,244,246,165,8,14,1,161,154,244,246,165,8,26,1,129,154,244,246,165,8,105,1,161,154,244,246,165,8,102,1,161,154,244,246,165,8,106,1,161,154,244,246,165,8,107,1,129,154,244,246,165,8,108,1,161,154,244,246,165,8,99,1,161,154,244,246,165,8,100,1,129,154,244,246,165,8,112,1,161,154,244,246,165,8,109,1,161,154,244,246,165,8,113,1,161,154,244,246,165,8,114,1,129,154,244,246,165,8,115,1,161,154,244,246,165,8,103,1,161,154,244,246,165,8,104,1,129,154,244,246,165,8,119,1,161,154,244,246,165,8,116,1,168,154,244,246,165,8,120,1,122,4,56,115,160,190,64,16,0,168,154,244,246,165,8,121,1,122,0,0,0,0,102,79,28,199,136,154,244,246,165,8,122,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,79,28,199,2,105,100,119,36,49,51,53,54,49,53,102,97,45,54,54,102,55,45,52,52,53,49,45,57,98,53,52,45,100,55,101,57,57,52,52,53,102,99,97,52,161,154,244,246,165,8,123,1,161,174,151,139,93,105,1,161,154,244,246,165,8,56,1,129,154,244,246,165,8,126,1,161,154,244,246,165,8,128,1,1,161,154,244,246,165,8,129,1,1,129,154,244,246,165,8,130,1,1,161,154,244,246,165,8,92,1,161,154,244,246,165,8,93,1,129,154,244,246,165,8,133,1,1,161,154,244,246,165,8,127,1,161,154,244,246,165,8,134,1,1,161,154,244,246,165,8,135,1,1,129,154,244,246,165,8,136,1,1,161,154,244,246,165,8,131,1,1,161,154,244,246,165,8,132,1,1,129,154,244,246,165,8,140,1,1,161,154,244,246,165,8,137,1,1,168,154,244,246,165,8,141,1,1,122,4,56,115,160,190,64,16,0,168,154,244,246,165,8,142,1,1,122,0,0,0,0,102,80,7,127,136,154,244,246,165,8,143,1,1,118,2,2,105,100,119,36,50,49,52,51,101,57,53,100,45,53,100,99,98,45,52,101,48,102,45,98,98,50,99,45,53,48,57,52,52,101,54,101,48,49,57,102,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,80,7,127,161,154,244,246,165,8,138,1,1,161,154,244,246,165,8,139,1,1,129,154,244,246,165,8,147,1,1,161,154,244,246,165,8,144,1,1,161,154,244,246,165,8,148,1,1,161,154,244,246,165,8,149,1,1,129,154,244,246,165,8,150,1,1,161,154,244,246,165,8,110,1,161,154,244,246,165,8,111,1,129,154,244,246,165,8,154,1,1,161,154,244,246,165,8,151,1,1,161,154,244,246,165,8,155,1,1,161,154,244,246,165,8,156,1,1,129,154,244,246,165,8,157,1,1,161,174,151,139,93,153,1,1,161,174,151,139,93,154,1,1,129,154,244,246,165,8,161,1,1,161,154,244,246,165,8,158,1,1,161,154,244,246,165,8,162,1,1,161,154,244,246,165,8,163,1,1,129,154,244,246,165,8,164,1,1,161,154,244,246,165,8,152,1,1,161,154,244,246,165,8,153,1,1,129,154,244,246,165,8,168,1,1,161,154,244,246,165,8,165,1,1,161,154,244,246,165,8,169,1,1,161,154,244,246,165,8,170,1,1,129,154,244,246,165,8,171,1,1,161,154,244,246,165,8,117,1,161,154,244,246,165,8,118,1,129,154,244,246,165,8,175,1,1,161,154,244,246,165,8,172,1,1,161,154,244,246,165,8,176,1,1,161,154,244,246,165,8,177,1,1,129,154,244,246,165,8,178,1,1,39,0,203,184,221,173,11,1,36,53,55,98,56,49,55,55,100,45,57,100,52,50,45,53,49,55,56,45,56,99,98,50,45,102,99,53,101,54,57,51,48,102,51,48,97,1,40,0,154,244,246,165,8,183,1,2,105,100,1,119,36,53,55,98,56,49,55,55,100,45,57,100,52,50,45,53,49,55,56,45,56,99,98,50,45,102,99,53,101,54,57,51,48,102,51,48,97,40,0,154,244,246,165,8,183,1,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,154,244,246,165,8,183,1,3,98,105,100,1,119,36,53,55,98,56,49,55,55,100,45,57,100,52,50,45,53,49,55,56,45,56,99,98,50,45,102,99,53,101,54,57,51,48,102,51,48,97,40,0,154,244,246,165,8,183,1,4,100,101,115,99,1,119,0,40,0,154,244,246,165,8,183,1,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,154,244,246,165,8,183,1,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,80,7,153,39,0,203,184,221,173,11,4,36,53,55,98,56,49,55,55,100,45,57,100,52,50,45,53,49,55,56,45,56,99,98,50,45,102,99,53,101,54,57,51,48,102,51,48,97,0,40,0,154,244,246,165,8,183,1,4,105,99,111,110,1,119,0,40,0,154,244,246,165,8,183,1,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,154,244,246,165,8,183,1,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,154,244,246,165,8,183,1,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,168,154,244,246,165,8,194,1,1,122,4,56,115,160,190,64,16,0,168,154,244,246,165,8,193,1,1,122,0,0,0,0,102,80,7,153,40,0,154,244,246,165,8,183,1,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,50,207,228,238,162,8,0,136,158,156,181,152,10,27,1,118,1,2,105,100,119,36,100,97,53,54,102,102,97,48,45,53,51,53,54,45,52,50,56,99,45,98,54,49,98,45,53,55,52,97,49,49,57,99,54,57,57,101,161,158,156,181,152,10,28,1,161,158,156,181,152,10,29,1,39,0,203,184,221,173,11,1,36,100,97,53,54,102,102,97,48,45,53,51,53,54,45,52,50,56,99,45,98,54,49,98,45,53,55,52,97,49,49,57,99,54,57,57,101,1,40,0,207,228,238,162,8,3,2,105,100,1,119,36,100,97,53,54,102,102,97,48,45,53,51,53,54,45,52,50,56,99,45,98,54,49,98,45,53,55,52,97,49,49,57,99,54,57,57,101,40,0,207,228,238,162,8,3,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,207,228,238,162,8,3,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,207,228,238,162,8,3,4,100,101,115,99,1,119,0,40,0,207,228,238,162,8,3,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,207,228,238,162,8,3,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,242,129,194,39,0,203,184,221,173,11,4,36,100,97,53,54,102,102,97,48,45,53,51,53,54,45,52,50,56,99,45,98,54,49,98,45,53,55,52,97,49,49,57,99,54,57,57,101,0,40,0,207,228,238,162,8,3,4,105,99,111,110,1,119,0,40,0,207,228,238,162,8,3,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,207,228,238,162,8,3,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,207,228,238,162,8,3,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,158,156,181,152,10,42,1,161,207,228,238,162,8,14,1,161,207,228,238,162,8,13,1,129,158,156,181,152,10,48,1,161,207,228,238,162,8,16,1,161,207,228,238,162,8,17,1,129,207,228,238,162,8,18,1,136,207,228,238,162,8,0,1,118,1,2,105,100,119,36,52,52,51,53,101,53,55,98,45,99,50,54,51,45,52,101,55,102,45,97,52,51,53,45,50,48,56,55,57,97,54,50,101,54,100,97,161,207,228,238,162,8,1,1,161,207,228,238,162,8,2,1,39,0,203,184,221,173,11,1,36,52,52,51,53,101,53,55,98,45,99,50,54,51,45,52,101,55,102,45,97,52,51,53,45,50,48,56,55,57,97,54,50,101,54,100,97,1,40,0,207,228,238,162,8,25,2,105,100,1,119,36,52,52,51,53,101,53,55,98,45,99,50,54,51,45,52,101,55,102,45,97,52,51,53,45,50,48,56,55,57,97,54,50,101,54,100,97,40,0,207,228,238,162,8,25,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,207,228,238,162,8,25,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,207,228,238,162,8,25,4,100,101,115,99,1,119,0,40,0,207,228,238,162,8,25,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,207,228,238,162,8,25,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,242,129,219,39,0,203,184,221,173,11,4,36,52,52,51,53,101,53,55,98,45,99,50,54,51,45,52,101,55,102,45,97,52,51,53,45,50,48,56,55,57,97,54,50,101,54,100,97,0,40,0,207,228,238,162,8,25,4,105,99,111,110,1,119,0,40,0,207,228,238,162,8,25,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,207,228,238,162,8,25,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,207,228,238,162,8,25,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,207,228,238,162,8,15,1,161,207,228,238,162,8,36,1,161,207,228,238,162,8,35,1,129,207,228,238,162,8,21,1,161,207,228,238,162,8,38,1,161,207,228,238,162,8,39,1,129,207,228,238,162,8,40,1,161,158,156,181,152,10,46,1,161,158,156,181,152,10,47,1,161,158,156,181,152,10,32,1,161,207,228,238,162,8,44,1,161,207,228,238,162,8,45,1,129,207,228,238,162,8,43,1,1,183,226,184,158,8,0,161,240,253,240,229,1,78,8,11,175,225,172,150,8,0,161,173,252,148,184,13,61,1,161,173,252,148,184,13,62,1,129,173,252,148,184,13,63,1,161,173,252,148,184,13,60,1,161,173,252,148,184,13,57,1,161,173,252,148,184,13,58,1,129,175,225,172,150,8,2,1,161,175,225,172,150,8,3,1,161,175,225,172,150,8,0,1,161,175,225,172,150,8,1,1,136,175,225,172,150,8,6,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,41,200,233,2,105,100,119,36,100,48,52,57,54,51,50,52,45,53,53,55,48,45,52,48,48,54,45,98,52,101,97,45,100,98,55,53,49,54,100,50,49,50,102,100,66,214,139,213,136,8,0,161,201,129,238,197,4,9,1,161,201,129,238,197,4,10,1,136,149,249,242,175,4,13,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,7,2,105,100,119,36,102,51,53,50,55,48,99,55,45,99,54,54,99,45,52,54,99,101,45,56,101,49,97,45,51,102,54,51,57,102,55,98,48,48,48,100,168,214,139,213,136,8,0,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,1,1,122,0,0,0,0,102,77,78,7,161,180,230,210,212,13,0,1,161,133,159,138,205,12,9,1,136,214,139,213,136,8,2,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,9,2,105,100,119,36,100,48,52,57,54,51,50,52,45,53,53,55,48,45,52,48,48,54,45,98,52,101,97,45,100,98,55,53,49,54,100,50,49,50,102,100,168,214,139,213,136,8,5,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,6,1,122,0,0,0,0,102,77,78,9,161,201,129,238,197,4,12,1,161,201,129,238,197,4,13,1,136,214,139,213,136,8,7,1,118,2,2,105,100,119,36,100,49,52,50,51,57,101,57,45,50,98,102,55,45,52,56,50,52,45,57,51,101,99,45,52,102,51,99,99,53,54,49,54,55,50,48,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,10,168,214,139,213,136,8,10,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,11,1,122,0,0,0,0,102,77,78,10,161,158,156,181,152,10,0,1,161,158,156,181,152,10,1,1,136,214,139,213,136,8,12,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,11,2,105,100,119,36,99,55,52,55,53,49,50,51,45,56,50,51,57,45,52,98,98,49,45,56,100,102,53,45,54,56,49,52,56,48,102,101,57,53,52,99,168,214,139,213,136,8,15,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,16,1,122,0,0,0,0,102,77,78,12,161,161,178,132,150,11,90,1,161,161,178,132,150,11,91,1,136,214,139,213,136,8,17,1,118,2,2,105,100,119,36,99,97,49,50,50,99,48,52,45,100,55,98,51,45,52,102,55,48,45,57,57,53,49,45,57,54,98,102,100,97,57,98,54,98,50,52,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,12,168,214,139,213,136,8,20,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,21,1,122,0,0,0,0,102,77,78,12,161,222,205,223,235,7,7,1,161,222,205,223,235,7,8,1,136,214,139,213,136,8,22,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,29,2,105,100,119,36,98,53,56,48,55,51,52,53,45,53,100,97,55,45,52,53,98,100,45,97,56,97,101,45,101,97,53,54,56,99,55,99,57,49,49,97,168,214,139,213,136,8,25,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,26,1,122,0,0,0,0,102,77,78,30,161,207,228,238,162,8,19,1,161,207,228,238,162,8,20,1,136,214,139,213,136,8,27,1,118,2,2,105,100,119,36,100,97,53,54,102,102,97,48,45,53,51,53,54,45,52,50,56,99,45,98,54,49,98,45,53,55,52,97,49,49,57,99,54,57,57,101,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,30,168,214,139,213,136,8,30,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,31,1,122,0,0,0,0,102,77,78,30,161,173,252,148,184,13,17,1,161,173,252,148,184,13,18,1,136,214,139,213,136,8,32,1,118,2,2,105,100,119,36,52,52,51,53,101,53,55,98,45,99,50,54,51,45,52,101,55,102,45,97,52,51,53,45,50,48,56,55,57,97,54,50,101,54,100,97,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,31,168,214,139,213,136,8,35,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,36,1,122,0,0,0,0,102,77,78,31,161,225,248,138,176,2,7,1,161,225,248,138,176,2,8,1,136,214,139,213,136,8,37,1,118,2,2,105,100,119,36,100,100,98,57,51,98,97,55,45,48,54,99,55,45,52,49,55,54,45,57,56,50,97,45,100,55,52,50,51,101,48,57,98,52,52,49,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,41,168,214,139,213,136,8,40,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,41,1,122,0,0,0,0,102,77,78,41,161,165,139,157,171,15,91,1,161,165,139,157,171,15,92,1,136,214,139,213,136,8,42,1,118,2,2,105,100,119,36,50,99,49,101,101,57,53,97,45,49,98,48,57,45,52,97,49,102,45,56,100,53,101,45,53,48,49,98,99,52,56,54,49,97,57,100,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,44,168,214,139,213,136,8,45,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,46,1,122,0,0,0,0,102,77,78,44,161,234,153,236,158,4,3,1,161,234,153,236,158,4,4,1,136,214,139,213,136,8,47,1,118,2,2,105,100,119,36,49,98,48,101,51,50,50,100,45,52,57,48,57,45,52,99,54,51,45,57,49,52,97,45,100,48,51,52,102,99,51,54,51,48,57,55,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,45,168,214,139,213,136,8,50,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,51,1,122,0,0,0,0,102,77,78,45,161,165,139,157,171,15,58,1,161,165,139,157,171,15,59,1,136,214,139,213,136,8,52,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,49,2,105,100,119,36,54,53,98,48,54,100,98,56,45,55,48,54,49,45,52,98,102,54,45,98,51,49,53,45,55,53,56,99,48,100,100,50,53,99,100,102,168,214,139,213,136,8,55,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,56,1,122,0,0,0,0,102,77,78,49,161,241,155,213,233,1,0,1,161,241,155,213,233,1,1,1,129,241,155,213,233,1,24,1,161,214,139,213,136,8,60,1,161,214,139,213,136,8,61,1,129,214,139,213,136,8,62,1,31,222,205,223,235,7,0,161,137,226,192,199,6,17,1,161,137,226,192,199,6,18,1,129,137,226,192,199,6,19,1,161,201,129,238,197,4,39,1,161,201,129,238,197,4,40,1,129,222,205,223,235,7,2,1,161,137,226,192,199,6,13,1,161,222,205,223,235,7,3,1,161,222,205,223,235,7,4,1,136,222,205,223,235,7,5,1,118,2,2,105,100,119,36,98,53,56,48,55,51,52,53,45,53,100,97,55,45,52,53,98,100,45,97,56,97,101,45,101,97,53,54,56,99,55,99,57,49,49,97,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,67,55,119,161,222,205,223,235,7,0,1,161,222,205,223,235,7,1,1,129,222,205,223,235,7,9,1,161,222,205,223,235,7,6,1,161,222,205,223,235,7,10,1,161,222,205,223,235,7,11,1,129,222,205,223,235,7,12,1,161,137,226,192,199,6,7,1,161,137,226,192,199,6,8,1,129,222,205,223,235,7,16,1,161,222,205,223,235,7,13,1,161,222,205,223,235,7,17,1,161,222,205,223,235,7,18,1,129,222,205,223,235,7,19,1,161,222,205,223,235,7,14,1,161,222,205,223,235,7,15,1,129,222,205,223,235,7,23,1,161,222,205,223,235,7,20,1,161,222,205,223,235,7,24,1,161,222,205,223,235,7,25,1,129,222,205,223,235,7,26,1,3,162,238,198,212,7,0,161,245,220,194,52,6,1,161,247,200,243,247,14,2,1,136,247,200,243,247,14,57,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,87,58,53,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,12,241,130,161,205,7,0,161,226,212,179,248,2,12,1,161,226,212,179,248,2,13,1,129,226,212,179,248,2,14,1,161,234,153,236,158,4,61,1,161,234,153,236,158,4,62,1,129,241,130,161,205,7,2,1,161,241,130,161,205,7,0,1,161,241,130,161,205,7,1,1,129,241,130,161,205,7,5,1,168,234,153,236,158,4,39,1,122,4,56,115,160,190,64,16,0,168,234,153,236,158,4,38,1,122,0,0,0,0,102,78,192,25,136,174,151,139,93,243,1,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,78,192,25,2,105,100,119,36,101,52,99,56,57,52,50,49,45,49,50,98,50,45,52,100,48,50,45,56,54,51,100,45,50,48,57,52,57,101,101,99,57,50,55,49,1,229,153,197,202,7,0,161,239,199,189,146,3,23,241,6,1,250,198,166,187,7,0,161,152,252,186,192,1,1,2,35,164,155,139,169,7,0,161,149,129,169,191,12,13,1,161,149,129,169,191,12,14,1,129,149,129,169,191,12,15,1,161,149,129,169,191,12,12,1,161,149,129,169,191,12,9,1,161,149,129,169,191,12,10,1,129,164,155,139,169,7,2,1,161,164,155,139,169,7,3,1,161,207,228,238,162,8,41,1,161,207,228,238,162,8,42,1,129,188,171,136,250,8,8,1,161,164,155,139,169,7,7,1,161,188,171,136,250,8,6,1,161,188,171,136,250,8,7,1,129,164,155,139,169,7,10,1,161,164,155,139,169,7,11,1,161,149,129,169,191,12,5,1,161,149,129,169,191,12,6,1,129,188,171,136,250,8,17,1,161,164,155,139,169,7,15,1,161,188,171,136,250,8,15,1,161,188,171,136,250,8,16,1,129,164,155,139,169,7,18,1,161,164,155,139,169,7,19,1,161,164,155,139,169,7,16,1,161,164,155,139,169,7,17,1,129,164,155,139,169,7,22,1,161,164,155,139,169,7,23,1,161,164,155,139,169,7,20,1,161,164,155,139,169,7,21,1,129,188,171,136,250,8,20,1,161,164,155,139,169,7,27,1,161,188,171,136,250,8,18,1,161,188,171,136,250,8,19,1,129,164,155,139,169,7,30,1,1,177,219,160,167,7,0,161,135,240,136,178,10,44,4,2,135,193,208,135,7,0,161,135,167,156,250,14,15,12,161,135,193,208,135,7,11,4,17,130,180,254,251,6,0,129,252,163,130,200,6,15,1,161,252,163,130,200,6,16,1,161,252,163,130,200,6,17,1,39,0,203,184,221,173,11,1,36,100,100,98,57,51,98,97,55,45,48,54,99,55,45,52,49,55,54,45,57,56,50,97,45,100,55,52,50,51,101,48,57,98,52,52,49,1,40,0,130,180,254,251,6,3,2,105,100,1,119,36,100,100,98,57,51,98,97,55,45,48,54,99,55,45,52,49,55,54,45,57,56,50,97,45,100,55,52,50,51,101,48,57,98,52,52,49,33,0,130,180,254,251,6,3,4,110,97,109,101,1,33,0,130,180,254,251,6,3,3,98,105,100,1,40,0,130,180,254,251,6,3,4,100,101,115,99,1,119,0,40,0,130,180,254,251,6,3,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,33,0,130,180,254,251,6,3,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,100,100,98,57,51,98,97,55,45,48,54,99,55,45,52,49,55,54,45,57,56,50,97,45,100,55,52,50,51,101,48,57,98,52,52,49,0,40,0,130,180,254,251,6,3,4,105,99,111,110,1,119,0,40,0,130,180,254,251,6,3,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,130,180,254,251,6,3,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,130,180,254,251,6,3,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,2,161,130,180,254,251,6,13,1,168,130,180,254,251,6,5,1,119,5,110,105,115,104,105,27,159,156,204,250,6,0,161,149,249,242,175,4,28,1,161,149,249,242,175,4,29,1,129,149,249,242,175,4,30,1,161,159,156,204,250,6,0,1,161,159,156,204,250,6,1,1,129,159,156,204,250,6,2,1,161,143,184,153,180,6,3,1,161,143,184,153,180,6,4,1,129,143,184,153,180,6,5,1,161,159,156,204,250,6,6,1,161,159,156,204,250,6,7,1,129,159,156,204,250,6,8,1,161,159,156,204,250,6,9,1,161,159,156,204,250,6,10,1,129,159,156,204,250,6,11,1,161,159,156,204,250,6,12,1,161,159,156,204,250,6,13,1,129,159,156,204,250,6,14,1,161,159,156,204,250,6,15,1,161,159,156,204,250,6,16,1,129,159,156,204,250,6,17,1,161,159,156,204,250,6,18,1,161,159,156,204,250,6,19,1,129,159,156,204,250,6,20,1,161,159,156,204,250,6,21,1,161,159,156,204,250,6,22,1,129,159,156,204,250,6,23,1,3,135,166,246,235,6,0,161,245,220,194,52,36,1,161,245,220,194,52,37,1,136,245,220,194,52,32,1,118,2,2,105,100,119,36,48,101,55,99,100,101,102,50,45,49,48,99,50,45,52,52,101,99,45,56,98,54,49,45,49,97,100,101,48,98,102,53,100,51,102,102,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,85,170,119,1,175,205,156,228,6,0,161,183,226,184,158,8,7,10,15,240,149,229,225,6,0,136,203,184,221,173,11,16,1,118,1,2,105,100,119,36,101,48,102,101,54,56,54,55,45,50,48,56,102,45,52,51,57,57,45,97,56,56,97,45,101,57,98,97,102,52,56,97,99,48,53,101,161,158,156,181,152,10,7,1,161,158,156,181,152,10,8,1,39,0,203,184,221,173,11,1,36,101,48,102,101,54,56,54,55,45,50,48,56,102,45,52,51,57,57,45,97,56,56,97,45,101,57,98,97,102,52,56,97,99,48,53,101,1,40,0,240,149,229,225,6,3,2,105,100,1,119,36,101,48,102,101,54,56,54,55,45,50,48,56,102,45,52,51,57,57,45,97,56,56,97,45,101,57,98,97,102,52,56,97,99,48,53,101,40,0,240,149,229,225,6,3,4,110,97,109,101,1,119,0,40,0,240,149,229,225,6,3,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,240,149,229,225,6,3,4,100,101,115,99,1,119,0,40,0,240,149,229,225,6,3,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,240,149,229,225,6,3,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,241,138,214,39,0,203,184,221,173,11,4,36,101,48,102,101,54,56,54,55,45,50,48,56,102,45,52,51,57,57,45,97,56,56,97,45,101,57,98,97,102,52,56,97,99,48,53,101,0,40,0,240,149,229,225,6,3,4,105,99,111,110,1,119,0,40,0,240,149,229,225,6,3,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,240,149,229,225,6,3,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,101,241,138,214,40,0,240,149,229,225,6,3,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,3,255,140,248,220,6,0,161,180,230,210,212,13,4,1,161,180,230,210,212,13,5,1,129,180,230,210,212,13,6,1,1,157,207,243,216,6,0,161,145,190,137,224,10,1,2,30,252,163,130,200,6,0,136,143,131,148,152,6,0,1,118,1,2,105,100,119,36,102,57,101,48,48,54,53,49,45,49,53,48,101,45,52,50,56,56,45,56,48,55,57,45,50,50,100,48,54,97,50,55,54,97,55,49,161,143,131,148,152,6,1,1,161,143,131,148,152,6,2,1,39,0,203,184,221,173,11,1,36,102,57,101,48,48,54,53,49,45,49,53,48,101,45,52,50,56,56,45,56,48,55,57,45,50,50,100,48,54,97,50,55,54,97,55,49,1,40,0,252,163,130,200,6,3,2,105,100,1,119,36,102,57,101,48,48,54,53,49,45,49,53,48,101,45,52,50,56,56,45,56,48,55,57,45,50,50,100,48,54,97,50,55,54,97,55,49,40,0,252,163,130,200,6,3,4,110,97,109,101,1,119,0,40,0,252,163,130,200,6,3,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,252,163,130,200,6,3,4,100,101,115,99,1,119,0,40,0,252,163,130,200,6,3,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,252,163,130,200,6,3,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,241,149,3,39,0,203,184,221,173,11,4,36,102,57,101,48,48,54,53,49,45,49,53,48,101,45,52,50,56,56,45,56,48,55,57,45,50,50,100,48,54,97,50,55,54,97,55,49,0,40,0,252,163,130,200,6,3,4,105,99,111,110,1,119,0,40,0,252,163,130,200,6,3,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,252,163,130,200,6,3,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,101,241,149,3,40,0,252,163,130,200,6,3,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,136,252,163,130,200,6,0,1,118,1,2,105,100,119,36,56,54,54,57,52,102,97,100,45,54,55,52,97,45,52,54,55,52,45,56,52,100,48,45,51,50,99,52,56,54,97,55,55,48,98,52,161,252,163,130,200,6,1,1,161,252,163,130,200,6,2,1,39,0,203,184,221,173,11,1,36,56,54,54,57,52,102,97,100,45,54,55,52,97,45,52,54,55,52,45,56,52,100,48,45,51,50,99,52,56,54,97,55,55,48,98,52,1,40,0,252,163,130,200,6,18,2,105,100,1,119,36,56,54,54,57,52,102,97,100,45,54,55,52,97,45,52,54,55,52,45,56,52,100,48,45,51,50,99,52,56,54,97,55,55,48,98,52,40,0,252,163,130,200,6,18,4,110,97,109,101,1,119,0,40,0,252,163,130,200,6,18,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,252,163,130,200,6,18,4,100,101,115,99,1,119,0,40,0,252,163,130,200,6,18,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,252,163,130,200,6,18,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,241,149,31,39,0,203,184,221,173,11,4,36,56,54,54,57,52,102,97,100,45,54,55,52,97,45,52,54,55,52,45,56,52,100,48,45,51,50,99,52,56,54,97,55,55,48,98,52,0,40,0,252,163,130,200,6,18,4,105,99,111,110,1,119,0,40,0,252,163,130,200,6,18,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,252,163,130,200,6,18,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,101,241,149,31,40,0,252,163,130,200,6,18,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,20,137,226,192,199,6,0,161,170,140,240,234,9,28,1,161,170,140,240,234,9,29,1,129,170,140,240,234,9,30,1,161,213,161,242,209,13,28,1,161,213,161,242,209,13,29,1,129,137,226,192,199,6,2,1,161,170,140,240,234,9,27,1,161,137,226,192,199,6,3,1,161,137,226,192,199,6,4,1,129,137,226,192,199,6,5,1,161,137,226,192,199,6,0,1,161,137,226,192,199,6,1,1,129,137,226,192,199,6,9,1,161,137,226,192,199,6,6,1,161,137,226,192,199,6,10,1,161,137,226,192,199,6,11,1,129,137,226,192,199,6,12,1,161,137,226,192,199,6,14,1,161,137,226,192,199,6,15,1,129,137,226,192,199,6,16,1,3,246,185,174,192,6,0,161,135,193,208,135,7,11,1,161,135,193,208,135,7,15,87,161,246,185,174,192,6,87,2,2,196,154,250,183,6,0,161,149,161,132,184,14,218,2,1,161,149,161,132,184,14,220,2,61,6,143,184,153,180,6,0,161,164,188,201,172,1,0,1,161,164,188,201,172,1,1,1,129,164,188,201,172,1,2,1,161,143,184,153,180,6,0,1,161,143,184,153,180,6,1,1,129,143,184,153,180,6,2,1,1,198,189,216,175,6,0,161,234,187,164,181,1,23,23,1,153,130,203,161,6,0,161,248,210,237,129,13,1,97,15,143,131,148,152,6,0,136,243,239,182,181,13,15,1,118,1,2,105,100,119,36,50,57,55,48,52,49,52,101,45,99,99,50,48,45,52,51,50,102,45,97,100,49,54,45,52,50,101,99,55,49,55,51,54,100,53,57,161,243,239,182,181,13,16,1,161,243,239,182,181,13,17,1,39,0,203,184,221,173,11,1,36,50,57,55,48,52,49,52,101,45,99,99,50,48,45,52,51,50,102,45,97,100,49,54,45,52,50,101,99,55,49,55,51,54,100,53,57,1,40,0,143,131,148,152,6,3,2,105,100,1,119,36,50,57,55,48,52,49,52,101,45,99,99,50,48,45,52,51,50,102,45,97,100,49,54,45,52,50,101,99,55,49,55,51,54,100,53,57,40,0,143,131,148,152,6,3,4,110,97,109,101,1,119,0,40,0,143,131,148,152,6,3,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,143,131,148,152,6,3,4,100,101,115,99,1,119,0,40,0,143,131,148,152,6,3,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,143,131,148,152,6,3,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,241,143,252,39,0,203,184,221,173,11,4,36,50,57,55,48,52,49,52,101,45,99,99,50,48,45,52,51,50,102,45,97,100,49,54,45,52,50,101,99,55,49,55,51,54,100,53,57,0,40,0,143,131,148,152,6,3,4,105,99,111,110,1,119,0,40,0,143,131,148,152,6,3,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,143,131,148,152,6,3,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,101,241,143,252,40,0,143,131,148,152,6,3,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,1,188,237,223,145,6,0,161,221,147,167,147,15,176,2,26,165,1,140,152,206,145,6,0,161,154,244,246,165,8,180,1,1,161,154,244,246,165,8,181,1,1,129,154,244,246,165,8,182,1,1,161,140,152,206,145,6,0,1,161,140,152,206,145,6,1,1,129,140,152,206,145,6,2,1,161,140,152,206,145,6,3,1,161,140,152,206,145,6,4,1,129,140,152,206,145,6,5,1,161,154,244,246,165,8,159,1,1,161,154,244,246,165,8,160,1,1,129,140,152,206,145,6,8,1,161,154,244,246,165,8,179,1,1,161,140,152,206,145,6,9,1,161,140,152,206,145,6,10,1,129,140,152,206,145,6,11,1,161,140,152,206,145,6,12,1,161,140,152,206,145,6,6,1,161,140,152,206,145,6,7,1,129,140,152,206,145,6,15,1,161,140,152,206,145,6,17,1,161,140,152,206,145,6,18,1,129,140,152,206,145,6,19,1,161,140,152,206,145,6,20,1,161,140,152,206,145,6,21,1,129,140,152,206,145,6,22,1,161,154,244,246,165,8,166,1,1,161,154,244,246,165,8,167,1,1,129,140,152,206,145,6,25,1,161,140,152,206,145,6,16,1,161,140,152,206,145,6,26,1,161,140,152,206,145,6,27,1,129,140,152,206,145,6,28,1,161,154,244,246,165,8,173,1,1,161,154,244,246,165,8,174,1,1,129,140,152,206,145,6,32,1,161,140,152,206,145,6,29,1,161,140,152,206,145,6,33,1,161,140,152,206,145,6,34,1,129,140,152,206,145,6,35,1,161,140,152,206,145,6,13,1,161,140,152,206,145,6,14,1,129,140,152,206,145,6,39,1,161,140,152,206,145,6,36,1,161,140,152,206,145,6,40,1,161,140,152,206,145,6,41,1,136,140,152,206,145,6,42,1,118,2,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,80,85,80,161,140,152,206,145,6,43,1,161,140,152,206,145,6,23,1,161,140,152,206,145,6,24,1,129,140,152,206,145,6,46,1,161,140,152,206,145,6,48,1,161,140,152,206,145,6,49,1,129,140,152,206,145,6,50,1,161,140,152,206,145,6,44,1,161,140,152,206,145,6,45,1,136,140,152,206,145,6,53,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,230,246,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,161,140,152,206,145,6,47,1,161,140,152,206,145,6,54,1,161,140,152,206,145,6,55,1,136,140,152,206,145,6,56,1,118,2,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,230,246,161,140,152,206,145,6,51,1,161,140,152,206,145,6,52,1,129,140,152,206,145,6,60,1,161,140,152,206,145,6,57,1,161,140,152,206,145,6,61,1,161,140,152,206,145,6,62,1,129,140,152,206,145,6,63,1,161,140,152,206,145,6,65,1,161,140,152,206,145,6,66,1,161,149,249,242,175,4,2,1,161,140,152,206,145,6,68,1,161,140,152,206,145,6,69,1,161,140,152,206,145,6,70,1,161,140,152,206,145,6,71,1,161,140,152,206,145,6,72,1,161,140,152,206,145,6,73,1,161,140,152,206,145,6,74,1,161,140,152,206,145,6,75,1,161,140,152,206,145,6,76,1,161,140,152,206,145,6,77,1,161,140,152,206,145,6,78,1,161,140,152,206,145,6,79,1,161,140,152,206,145,6,58,1,161,140,152,206,145,6,59,1,136,140,152,206,145,6,67,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,241,108,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,161,140,152,206,145,6,64,1,161,140,152,206,145,6,83,1,161,140,152,206,145,6,84,1,136,140,152,206,145,6,85,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,241,109,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,161,140,152,206,145,6,86,1,161,140,152,206,145,6,80,1,161,140,152,206,145,6,81,1,136,140,152,206,145,6,89,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,241,110,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,161,140,152,206,145,6,91,1,161,140,152,206,145,6,92,1,136,140,152,206,145,6,93,1,118,2,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,241,111,161,140,152,206,145,6,94,1,161,140,152,206,145,6,95,1,161,140,152,206,145,6,82,1,136,241,155,213,233,1,6,1,118,1,2,105,100,119,36,48,101,55,99,100,101,102,50,45,49,48,99,50,45,52,52,101,99,45,56,98,54,49,45,49,97,100,101,48,98,102,53,100,51,102,102,161,241,155,213,233,1,7,1,161,140,152,206,145,6,98,1,39,0,203,184,221,173,11,1,36,48,101,55,99,100,101,102,50,45,49,48,99,50,45,52,52,101,99,45,56,98,54,49,45,49,97,100,101,48,98,102,53,100,51,102,102,1,40,0,140,152,206,145,6,103,2,105,100,1,119,36,48,101,55,99,100,101,102,50,45,49,48,99,50,45,52,52,101,99,45,56,98,54,49,45,49,97,100,101,48,98,102,53,100,51,102,102,33,0,140,152,206,145,6,103,4,110,97,109,101,1,40,0,140,152,206,145,6,103,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,140,152,206,145,6,103,4,100,101,115,99,1,119,0,40,0,140,152,206,145,6,103,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,140,152,206,145,6,103,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,83,241,173,39,0,203,184,221,173,11,4,36,48,101,55,99,100,101,102,50,45,49,48,99,50,45,52,52,101,99,45,56,98,54,49,45,49,97,100,101,48,98,102,53,100,51,102,102,0,33,0,140,152,206,145,6,103,4,105,99,111,110,1,40,0,140,152,206,145,6,103,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,140,152,206,145,6,103,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,140,152,206,145,6,103,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,140,152,206,145,6,90,1,161,140,152,206,145,6,114,1,161,140,152,206,145,6,113,1,129,140,152,206,145,6,96,1,161,140,152,206,145,6,116,1,161,140,152,206,145,6,117,1,129,140,152,206,145,6,118,1,161,140,152,206,145,6,119,1,161,140,152,206,145,6,120,1,33,0,140,152,206,145,6,103,5,101,120,116,114,97,1,161,140,152,206,145,6,122,1,161,140,152,206,145,6,123,1,129,140,152,206,145,6,121,1,161,140,152,206,145,6,125,1,161,140,152,206,145,6,126,1,161,140,152,206,145,6,105,1,161,140,152,206,145,6,128,1,1,161,140,152,206,145,6,129,1,1,168,140,152,206,145,6,130,1,1,119,2,104,105,161,140,152,206,145,6,131,1,1,161,140,152,206,145,6,132,1,1,161,140,152,206,145,6,124,1,161,140,152,206,145,6,134,1,1,161,140,152,206,145,6,135,1,1,161,140,152,206,145,6,136,1,1,161,140,152,206,145,6,137,1,1,161,140,152,206,145,6,138,1,1,161,140,152,206,145,6,139,1,1,161,140,152,206,145,6,140,1,1,161,140,152,206,145,6,141,1,1,161,140,152,206,145,6,142,1,1,161,140,152,206,145,6,143,1,1,161,140,152,206,145,6,144,1,1,161,140,152,206,145,6,145,1,1,161,140,152,206,145,6,146,1,1,161,140,152,206,145,6,147,1,1,161,140,152,206,145,6,148,1,1,161,140,152,206,145,6,149,1,1,161,140,152,206,145,6,150,1,1,168,140,152,206,145,6,111,1,119,23,123,34,116,121,34,58,48,44,34,118,97,108,117,101,34,58,34,240,159,154,184,34,125,161,140,152,206,145,6,97,1,161,140,152,206,145,6,102,1,136,140,152,206,145,6,127,1,118,2,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,244,231,161,140,152,206,145,6,115,1,161,140,152,206,145,6,155,1,1,161,140,152,206,145,6,156,1,1,136,140,152,206,145,6,157,1,1,118,2,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,244,231,161,140,152,206,145,6,159,1,1,161,140,152,206,145,6,160,1,1,168,140,152,206,145,6,99,1,119,225,1,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,117,110,115,112,108,97,115,104,34,44,34,118,97,108,117,101,34,58,34,104,116,116,112,115,58,47,47,105,109,97,103,101,115,46,117,110,115,112,108,97,115,104,46,99,111,109,47,112,104,111,116,111,45,49,55,49,52,53,48,56,56,54,50,55,56,56,45,52,52,101,52,53,99,52,51,49,53,100,48,63,99,114,111,112,61,101,110,116,114,111,112,121,38,99,115,61,116,105,110,121,115,114,103,98,38,102,105,116,61,109,97,120,38,102,109,61,106,112,103,38,105,120,105,100,61,77,51,119,49,77,84,69,49,77,122,100,56,77,72,119,120,102,72,74,104,98,109,82,118,98,88,120,56,102,72,120,56,102,72,120,56,102,68,69,51,77,84,89,51,78,122,103,121,77,84,108,56,38,105,120,108,105,98,61,114,98,45,52,46,48,46,51,38,113,61,56,48,38,119,61,49,48,56,48,34,125,125,1,219,227,140,137,6,0,161,140,228,230,243,1,1,34,1,235,178,165,206,5,0,161,255,255,147,249,10,2,72,3,182,172,247,194,5,0,161,245,220,194,52,30,1,161,245,220,194,52,31,1,129,245,220,194,52,32,1,1,145,144,146,185,5,0,161,175,205,156,228,6,9,12,3,160,192,253,131,5,0,161,195,242,227,194,8,0,1,161,195,242,227,194,8,1,1,129,195,242,227,194,8,2,1,1,200,142,208,241,4,0,161,196,154,250,183,6,61,157,1,1,154,235,215,240,4,0,161,173,187,245,170,14,45,13,1,211,166,203,229,4,0,161,234,182,182,157,9,7,195,1,1,141,171,170,217,4,0,161,191,157,147,233,9,31,2,84,201,129,238,197,4,0,161,161,178,132,150,11,34,1,161,161,178,132,150,11,35,1,129,173,252,148,184,13,51,1,161,133,159,138,205,12,49,1,161,133,159,138,205,12,50,1,129,133,159,138,205,12,77,1,168,201,129,238,197,4,3,1,122,4,56,115,160,190,64,16,0,168,201,129,238,197,4,4,1,122,0,0,0,0,102,48,111,8,136,201,129,238,197,4,5,1,118,2,2,105,100,119,36,98,54,51,52,55,97,99,98,45,51,49,55,52,45,52,102,48,101,45,57,56,101,57,45,100,99,99,101,48,55,101,53,100,98,102,55,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,48,111,8,161,133,159,138,205,12,45,1,161,133,159,138,205,12,46,1,129,201,129,238,197,4,8,1,161,158,156,181,152,10,21,1,161,244,226,228,149,2,6,1,129,201,129,238,197,4,11,1,161,133,159,138,205,12,81,1,161,133,159,138,205,12,82,1,129,201,129,238,197,4,14,1,161,201,129,238,197,4,15,1,161,201,129,238,197,4,16,1,129,201,129,238,197,4,17,1,161,201,129,238,197,4,18,1,161,201,129,238,197,4,19,1,129,201,129,238,197,4,20,1,161,201,129,238,197,4,21,1,161,201,129,238,197,4,22,1,129,201,129,238,197,4,23,1,161,201,129,238,197,4,24,1,161,201,129,238,197,4,25,1,129,201,129,238,197,4,26,1,161,201,129,238,197,4,27,1,161,201,129,238,197,4,28,1,129,201,129,238,197,4,29,1,161,133,159,138,205,12,90,1,161,133,159,138,205,12,91,1,129,201,129,238,197,4,32,1,161,201,129,238,197,4,33,1,161,201,129,238,197,4,34,1,129,201,129,238,197,4,35,1,161,173,252,148,184,13,53,1,161,173,252,148,184,13,54,1,129,201,129,238,197,4,38,1,8,0,133,159,138,205,12,66,1,118,1,2,105,100,119,36,101,52,49,48,55,52,55,98,45,53,102,50,102,45,52,53,97,48,45,98,50,102,55,45,56,57,48,97,100,51,48,48,49,51,53,53,161,133,159,138,205,12,65,1,161,201,129,238,197,4,37,1,39,0,203,184,221,173,11,1,36,101,52,49,48,55,52,55,98,45,53,102,50,102,45,52,53,97,48,45,98,50,102,55,45,56,57,48,97,100,51,48,48,49,51,53,53,1,40,0,201,129,238,197,4,45,2,105,100,1,119,36,101,52,49,48,55,52,55,98,45,53,102,50,102,45,52,53,97,48,45,98,50,102,55,45,56,57,48,97,100,51,48,48,49,51,53,53,40,0,201,129,238,197,4,45,4,110,97,109,101,1,119,5,66,111,97,114,100,40,0,201,129,238,197,4,45,3,98,105,100,1,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,40,0,201,129,238,197,4,45,4,100,101,115,99,1,119,0,40,0,201,129,238,197,4,45,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,2,33,0,201,129,238,197,4,45,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,101,52,49,48,55,52,55,98,45,53,102,50,102,45,52,53,97,48,45,98,50,102,55,45,56,57,48,97,100,51,48,48,49,51,53,53,0,40,0,201,129,238,197,4,45,4,105,99,111,110,1,119,0,40,0,201,129,238,197,4,45,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,201,129,238,197,4,45,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,201,129,238,197,4,45,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,136,201,129,238,197,4,42,1,118,1,2,105,100,119,36,50,49,52,51,101,57,53,100,45,53,100,99,98,45,52,101,48,102,45,98,98,50,99,45,53,48,57,52,52,101,54,101,48,49,57,102,161,201,129,238,197,4,43,1,161,201,129,238,197,4,44,1,39,0,203,184,221,173,11,1,36,50,49,52,51,101,57,53,100,45,53,100,99,98,45,52,101,48,102,45,98,98,50,99,45,53,48,57,52,52,101,54,101,48,49,57,102,1,40,0,201,129,238,197,4,60,2,105,100,1,119,36,50,49,52,51,101,57,53,100,45,53,100,99,98,45,52,101,48,102,45,98,98,50,99,45,53,48,57,52,52,101,54,101,48,49,57,102,40,0,201,129,238,197,4,60,4,110,97,109,101,1,119,8,67,97,108,101,110,100,97,114,40,0,201,129,238,197,4,60,3,98,105,100,1,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,40,0,201,129,238,197,4,60,4,100,101,115,99,1,119,0,40,0,201,129,238,197,4,60,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,3,33,0,201,129,238,197,4,60,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,50,49,52,51,101,57,53,100,45,53,100,99,98,45,52,101,48,102,45,98,98,50,99,45,53,48,57,52,52,101,54,101,48,49,57,102,0,40,0,201,129,238,197,4,60,4,105,99,111,110,1,119,0,40,0,201,129,238,197,4,60,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,201,129,238,197,4,60,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,201,129,238,197,4,60,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,201,129,238,197,4,36,1,161,201,129,238,197,4,59,1,161,133,159,138,205,12,92,1,161,201,129,238,197,4,72,1,161,201,129,238,197,4,73,1,161,201,129,238,197,4,74,1,161,201,129,238,197,4,75,1,161,201,129,238,197,4,76,1,161,201,129,238,197,4,77,1,161,201,129,238,197,4,78,1,161,201,129,238,197,4,79,1,168,201,129,238,197,4,80,1,119,4,71,114,105,100,1,182,143,233,195,4,0,161,205,149,231,236,11,67,111,1,178,203,205,182,4,0,161,227,209,197,253,2,13,1,31,149,249,242,175,4,0,161,213,161,242,209,13,28,1,161,213,161,242,209,13,29,1,33,0,203,184,221,173,11,23,5,101,120,116,114,97,1,161,149,249,242,175,4,0,1,161,149,249,242,175,4,1,1,129,201,191,159,147,14,2,1,161,133,159,138,205,12,122,1,161,133,159,138,205,12,121,1,136,213,161,242,209,13,26,1,118,2,2,105,100,119,36,102,48,99,53,57,57,50,49,45,48,52,101,101,45,52,57,55,49,45,57,57,53,99,45,55,57,98,55,102,100,56,99,48,48,101,50,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,60,201,181,168,149,249,242,175,4,6,1,122,4,56,115,160,190,64,16,0,168,149,249,242,175,4,7,1,122,0,0,0,0,102,60,201,181,161,133,159,138,205,12,107,1,161,133,159,138,205,12,106,1,136,149,249,242,175,4,8,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,60,201,183,2,105,100,119,36,101,57,55,56,55,55,102,53,45,99,51,54,53,45,52,48,50,53,45,57,101,54,97,45,101,53,57,48,99,52,98,49,57,100,98,98,168,149,249,242,175,4,11,1,122,4,56,115,160,190,64,16,0,168,149,249,242,175,4,12,1,122,0,0,0,0,102,60,201,183,161,201,191,159,147,14,0,1,161,201,191,159,147,14,1,1,129,149,249,242,175,4,5,1,161,149,249,242,175,4,16,1,161,149,249,242,175,4,17,1,129,149,249,242,175,4,18,1,161,149,249,242,175,4,19,1,161,149,249,242,175,4,20,1,129,149,249,242,175,4,21,1,161,149,249,242,175,4,22,1,161,149,249,242,175,4,23,1,129,149,249,242,175,4,24,1,161,149,249,242,175,4,25,1,161,149,249,242,175,4,26,1,129,149,249,242,175,4,27,1,12,163,236,177,169,4,0,161,154,243,157,196,14,9,1,161,154,243,157,196,14,10,1,129,154,243,157,196,14,11,1,161,163,236,177,169,4,0,1,161,163,236,177,169,4,1,1,129,163,236,177,169,4,2,1,161,163,236,177,169,4,3,1,161,163,236,177,169,4,4,1,129,163,236,177,169,4,5,1,161,163,236,177,169,4,6,1,161,163,236,177,169,4,7,1,129,163,236,177,169,4,8,1,73,234,153,236,158,4,0,161,165,139,157,171,15,100,1,161,165,139,157,171,15,101,1,129,165,139,157,171,15,102,1,161,165,139,157,171,15,88,1,161,165,139,157,171,15,89,1,129,234,153,236,158,4,2,1,136,165,139,157,171,15,18,1,118,1,2,105,100,119,36,48,99,101,49,51,52,49,53,45,54,99,99,101,45,52,52,57,55,45,57,52,99,54,45,52,55,53,97,100,57,54,99,50,52,57,101,161,165,139,157,171,15,19,1,161,165,139,157,171,15,20,1,39,0,203,184,221,173,11,1,36,48,99,101,49,51,52,49,53,45,54,99,99,101,45,52,52,57,55,45,57,52,99,54,45,52,55,53,97,100,57,54,99,50,52,57,101,1,40,0,234,153,236,158,4,9,2,105,100,1,119,36,48,99,101,49,51,52,49,53,45,54,99,99,101,45,52,52,57,55,45,57,52,99,54,45,52,55,53,97,100,57,54,99,50,52,57,101,33,0,234,153,236,158,4,9,4,110,97,109,101,1,40,0,234,153,236,158,4,9,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,234,153,236,158,4,9,4,100,101,115,99,1,119,0,40,0,234,153,236,158,4,9,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,2,33,0,234,153,236,158,4,9,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,48,99,101,49,51,52,49,53,45,54,99,99,101,45,52,52,57,55,45,57,52,99,54,45,52,55,53,97,100,57,54,99,50,52,57,101,0,40,0,234,153,236,158,4,9,4,105,99,111,110,1,119,0,40,0,234,153,236,158,4,9,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,234,153,236,158,4,9,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,234,153,236,158,4,9,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,165,139,157,171,15,33,1,161,234,153,236,158,4,20,1,161,234,153,236,158,4,19,1,129,234,153,236,158,4,5,1,8,0,234,153,236,158,4,16,1,118,1,2,105,100,119,36,101,52,99,56,57,52,50,49,45,49,50,98,50,45,52,100,48,50,45,56,54,51,100,45,50,48,57,52,57,101,101,99,57,50,55,49,168,234,153,236,158,4,15,1,122,0,0,0,0,102,76,39,166,161,234,153,236,158,4,23,1,39,0,203,184,221,173,11,1,36,101,52,99,56,57,52,50,49,45,49,50,98,50,45,52,100,48,50,45,56,54,51,100,45,50,48,57,52,57,101,101,99,57,50,55,49,1,40,0,234,153,236,158,4,28,2,105,100,1,119,36,101,52,99,56,57,52,50,49,45,49,50,98,50,45,52,100,48,50,45,56,54,51,100,45,50,48,57,52,57,101,101,99,57,50,55,49,40,0,234,153,236,158,4,28,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,234,153,236,158,4,28,3,98,105,100,1,119,36,48,99,101,49,51,52,49,53,45,54,99,99,101,45,52,52,57,55,45,57,52,99,54,45,52,55,53,97,100,57,54,99,50,52,57,101,40,0,234,153,236,158,4,28,4,100,101,115,99,1,119,0,40,0,234,153,236,158,4,28,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,40,0,234,153,236,158,4,28,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,76,39,166,39,0,203,184,221,173,11,4,36,101,52,99,56,57,52,50,49,45,49,50,98,50,45,52,100,48,50,45,56,54,51,100,45,50,48,57,52,57,101,101,99,57,50,55,49,0,40,0,234,153,236,158,4,28,4,105,99,111,110,1,119,0,40,0,234,153,236,158,4,28,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,234,153,236,158,4,28,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,234,153,236,158,4,28,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,234,153,236,158,4,22,1,161,234,153,236,158,4,27,1,129,234,153,236,158,4,24,1,161,234,153,236,158,4,40,1,161,234,153,236,158,4,41,1,168,234,153,236,158,4,11,1,119,14,99,104,101,99,107,98,111,120,32,98,111,97,114,100,161,234,153,236,158,4,43,1,161,234,153,236,158,4,44,1,129,234,153,236,158,4,42,1,161,234,153,236,158,4,46,1,161,234,153,236,158,4,47,1,129,234,153,236,158,4,48,1,161,234,153,236,158,4,49,1,161,234,153,236,158,4,50,1,129,234,153,236,158,4,51,1,161,165,139,157,171,15,94,1,161,165,139,157,171,15,95,1,129,234,153,236,158,4,54,1,161,234,153,236,158,4,55,1,161,234,153,236,158,4,56,1,129,234,153,236,158,4,57,1,161,234,153,236,158,4,0,1,161,234,153,236,158,4,1,1,129,234,153,236,158,4,60,1,161,234,153,236,158,4,58,1,161,234,153,236,158,4,59,1,129,234,153,236,158,4,63,1,161,234,153,236,158,4,64,1,161,234,153,236,158,4,65,1,129,234,153,236,158,4,66,1,161,234,153,236,158,4,67,1,161,234,153,236,158,4,68,1,129,234,153,236,158,4,69,1,3,141,205,220,149,4,0,161,214,168,149,214,3,12,1,161,214,168,149,214,3,13,1,129,214,168,149,214,3,14,1,17,193,249,142,142,4,0,161,141,216,158,150,1,0,1,161,141,216,158,150,1,1,1,129,141,216,158,150,1,2,1,161,225,248,138,176,2,45,1,161,222,205,223,235,7,21,1,161,225,248,138,176,2,19,1,129,193,249,142,142,4,2,1,161,193,249,142,142,4,4,1,161,193,249,142,142,4,5,1,129,193,249,142,142,4,6,1,161,193,249,142,142,4,0,1,161,193,249,142,142,4,1,1,129,193,249,142,142,4,9,1,161,193,249,142,142,4,3,1,161,193,249,142,142,4,10,1,161,193,249,142,142,4,11,1,129,193,249,142,142,4,12,1,20,206,220,129,131,4,0,161,235,225,184,133,10,0,1,161,235,225,184,133,10,1,1,129,235,225,184,133,10,2,1,72,233,165,139,246,14,7,1,118,1,2,105,100,119,36,99,55,52,55,53,49,50,51,45,56,50,51,57,45,52,98,98,49,45,56,100,102,53,45,54,56,49,52,56,48,102,101,57,53,52,99,161,233,165,139,246,14,8,1,161,233,165,139,246,14,9,1,39,0,203,184,221,173,11,1,36,99,55,52,55,53,49,50,51,45,56,50,51,57,45,52,98,98,49,45,56,100,102,53,45,54,56,49,52,56,48,102,101,57,53,52,99,1,40,0,206,220,129,131,4,6,2,105,100,1,119,36,99,55,52,55,53,49,50,51,45,56,50,51,57,45,52,98,98,49,45,56,100,102,53,45,54,56,49,52,56,48,102,101,57,53,52,99,40,0,206,220,129,131,4,6,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,206,220,129,131,4,6,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,206,220,129,131,4,6,4,100,101,115,99,1,119,0,40,0,206,220,129,131,4,6,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,206,220,129,131,4,6,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,241,122,107,39,0,203,184,221,173,11,4,36,99,55,52,55,53,49,50,51,45,56,50,51,57,45,52,98,98,49,45,56,100,102,53,45,54,56,49,52,56,48,102,101,57,53,52,99,0,40,0,206,220,129,131,4,6,4,105,99,111,110,1,119,0,40,0,206,220,129,131,4,6,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,206,220,129,131,4,6,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,206,220,129,131,4,6,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,2,161,206,220,129,131,4,16,1,129,206,220,129,131,4,2,1,1,128,252,161,128,4,0,161,232,207,157,148,2,1,33,3,169,197,188,221,3,0,161,154,193,208,134,10,3,1,161,154,193,208,134,10,4,1,129,154,193,208,134,10,5,1,15,214,168,149,214,3,0,161,169,197,188,221,3,0,1,161,169,197,188,221,3,1,1,129,169,197,188,221,3,2,1,161,233,247,183,159,1,0,1,161,158,156,181,152,10,3,1,161,158,156,181,152,10,4,1,129,154,193,208,134,10,8,1,161,214,168,149,214,3,3,1,161,154,193,208,134,10,6,1,161,154,193,208,134,10,7,1,129,214,168,149,214,3,6,1,161,214,168,149,214,3,7,1,161,171,204,155,217,8,0,1,161,171,204,155,217,8,1,1,129,214,168,149,214,3,10,1,1,158,184,218,165,3,0,161,139,152,215,249,10,33,38,1,239,199,189,146,3,0,161,154,235,215,240,4,12,24,1,227,209,197,253,2,0,161,181,175,219,209,12,9,14,15,226,212,179,248,2,0,161,214,139,213,136,8,63,1,161,214,139,213,136,8,64,1,129,214,139,213,136,8,65,1,161,226,212,179,248,2,0,1,161,226,212,179,248,2,1,1,129,226,212,179,248,2,2,1,161,226,212,179,248,2,3,1,161,226,212,179,248,2,4,1,129,226,212,179,248,2,5,1,161,193,249,142,142,4,7,1,161,241,155,213,233,1,8,1,129,226,212,179,248,2,8,1,161,226,212,179,248,2,6,1,161,226,212,179,248,2,7,1,129,226,212,179,248,2,11,1,3,157,240,144,231,2,0,161,213,161,242,209,13,32,1,161,213,161,242,209,13,33,1,129,213,161,242,209,13,34,1,1,128,211,179,216,2,0,161,236,229,225,232,8,115,10,1,138,202,240,189,2,0,161,229,153,197,202,7,240,6,134,1,1,200,203,236,184,2,0,161,138,202,240,189,2,133,1,35,49,225,248,138,176,2,0,161,171,142,166,254,1,3,1,161,171,142,166,254,1,4,1,129,171,142,166,254,1,5,1,161,222,205,223,235,7,27,1,161,173,252,148,184,13,45,1,161,173,252,148,184,13,46,1,129,225,248,138,176,2,2,1,161,225,248,138,176,2,4,1,161,225,248,138,176,2,5,1,136,225,248,138,176,2,6,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,68,43,241,2,105,100,119,36,100,100,98,57,51,98,97,55,45,48,54,99,55,45,52,49,55,54,45,57,56,50,97,45,100,55,52,50,51,101,48,57,98,52,52,49,161,170,140,240,234,9,7,1,161,170,140,240,234,9,8,1,136,225,248,138,176,2,9,1,118,2,2,105,100,119,36,52,56,99,53,50,99,102,55,45,98,102,57,56,45,52,51,102,97,45,57,54,97,100,45,98,51,49,97,97,100,101,57,98,48,55,49,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,68,43,243,161,225,248,138,176,2,3,1,168,225,248,138,176,2,10,1,122,4,56,115,160,190,64,16,0,168,225,248,138,176,2,11,1,122,0,0,0,0,102,68,43,244,136,225,248,138,176,2,12,1,118,2,2,105,100,119,36,52,56,99,53,50,99,102,55,45,98,102,57,56,45,52,51,102,97,45,57,54,97,100,45,98,51,49,97,97,100,101,57,98,48,55,49,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,68,43,244,136,133,159,138,205,12,56,1,118,1,2,105,100,119,36,50,99,49,101,101,57,53,97,45,49,98,48,57,45,52,97,49,102,45,56,100,53,101,45,53,48,49,98,99,52,56,54,49,97,57,100,161,133,159,138,205,12,57,1,161,222,205,223,235,7,22,1,39,0,203,184,221,173,11,1,36,50,99,49,101,101,57,53,97,45,49,98,48,57,45,52,97,49,102,45,56,100,53,101,45,53,48,49,98,99,52,56,54,49,97,57,100,1,40,0,225,248,138,176,2,20,2,105,100,1,119,36,50,99,49,101,101,57,53,97,45,49,98,48,57,45,52,97,49,102,45,56,100,53,101,45,53,48,49,98,99,52,56,54,49,97,57,100,40,0,225,248,138,176,2,20,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,225,248,138,176,2,20,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,225,248,138,176,2,20,4,100,101,115,99,1,119,0,40,0,225,248,138,176,2,20,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,33,0,225,248,138,176,2,20,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,50,99,49,101,101,57,53,97,45,49,98,48,57,45,52,97,49,102,45,56,100,53,101,45,53,48,49,98,99,52,56,54,49,97,57,100,0,40,0,225,248,138,176,2,20,4,105,99,111,110,1,119,0,40,0,225,248,138,176,2,20,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,225,248,138,176,2,20,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,225,248,138,176,2,20,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,225,248,138,176,2,13,1,161,225,248,138,176,2,31,1,161,225,248,138,176,2,30,1,129,225,248,138,176,2,16,1,161,225,248,138,176,2,33,1,161,225,248,138,176,2,34,1,129,225,248,138,176,2,35,1,161,225,248,138,176,2,36,1,161,225,248,138,176,2,37,1,129,225,248,138,176,2,38,1,161,225,248,138,176,2,0,1,161,225,248,138,176,2,1,1,129,225,248,138,176,2,41,1,161,225,248,138,176,2,32,1,161,225,248,138,176,2,42,1,161,225,248,138,176,2,43,1,129,225,248,138,176,2,44,1,29,244,226,228,149,2,0,39,0,203,184,221,173,11,2,7,112,114,105,118,97,116,101,1,161,158,156,181,152,10,24,1,161,207,228,238,162,8,24,1,129,207,228,238,162,8,49,1,8,0,158,156,181,152,10,16,1,118,1,2,105,100,119,36,48,53,51,51,50,98,97,52,45,97,54,57,48,45,52,50,57,51,45,57,56,54,54,45,56,52,100,97,99,55,102,101,50,97,101,97,168,158,156,181,152,10,15,1,122,0,0,0,0,101,251,252,70,161,158,156,181,152,10,22,1,39,0,203,184,221,173,11,1,36,48,53,51,51,50,98,97,52,45,97,54,57,48,45,52,50,57,51,45,57,56,54,54,45,56,52,100,97,99,55,102,101,50,97,101,97,1,40,0,244,226,228,149,2,7,2,105,100,1,119,36,48,53,51,51,50,98,97,52,45,97,54,57,48,45,52,50,57,51,45,57,56,54,54,45,56,52,100,97,99,55,102,101,50,97,101,97,40,0,244,226,228,149,2,7,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,244,226,228,149,2,7,3,98,105,100,1,119,36,100,49,52,50,51,57,101,57,45,50,98,102,55,45,52,56,50,52,45,57,51,101,99,45,52,102,51,99,99,53,54,49,54,55,50,48,40,0,244,226,228,149,2,7,4,100,101,115,99,1,119,0,40,0,244,226,228,149,2,7,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,40,0,244,226,228,149,2,7,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,251,252,70,39,0,203,184,221,173,11,4,36,48,53,51,51,50,98,97,52,45,97,54,57,48,45,52,50,57,51,45,57,56,54,54,45,56,52,100,97,99,55,102,101,50,97,101,97,0,40,0,244,226,228,149,2,7,4,105,99,111,110,1,119,0,40,0,244,226,228,149,2,7,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,244,226,228,149,2,7,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,244,226,228,149,2,7,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,2,161,244,226,228,149,2,17,1,39,0,244,226,228,149,2,0,18,51,48,52,49,50,48,49,48,57,48,55,49,51,51,57,53,50,48,0,8,0,244,226,228,149,2,21,1,118,2,2,105,100,119,36,48,53,51,51,50,98,97,52,45,97,54,57,48,45,52,50,57,51,45,57,56,54,54,45,56,52,100,97,99,55,102,101,50,97,101,97,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,101,251,252,70,161,207,228,238,162,8,37,1,161,244,226,228,149,2,19,1,161,244,226,228,149,2,20,1,129,244,226,228,149,2,3,1,161,244,226,228,149,2,24,1,161,244,226,228,149,2,25,1,129,244,226,228,149,2,26,1,1,232,207,157,148,2,0,161,141,171,170,217,4,1,2,6,171,142,166,254,1,0,161,143,184,153,180,6,3,1,161,143,184,153,180,6,4,1,129,143,184,153,180,6,5,1,161,171,142,166,254,1,0,1,161,171,142,166,254,1,1,1,129,171,142,166,254,1,2,1,1,140,228,230,243,1,0,161,250,198,166,187,7,1,2,3,147,206,229,235,1,0,161,229,154,128,197,12,3,1,161,229,154,128,197,12,4,1,129,162,159,252,196,11,2,1,52,241,155,213,233,1,0,161,234,153,236,158,4,70,1,161,234,153,236,158,4,71,1,129,234,153,236,158,4,72,1,161,234,153,236,158,4,52,1,161,234,153,236,158,4,53,1,129,241,155,213,233,1,2,1,136,234,153,236,158,4,6,1,118,1,2,105,100,119,36,101,101,51,97,101,56,99,101,45,57,53,57,97,45,52,100,102,51,45,56,55,51,52,45,52,48,98,53,51,53,102,102,56,56,101,51,161,234,153,236,158,4,7,1,161,234,153,236,158,4,8,1,39,0,203,184,221,173,11,1,36,101,101,51,97,101,56,99,101,45,57,53,57,97,45,52,100,102,51,45,56,55,51,52,45,52,48,98,53,51,53,102,102,56,56,101,51,1,40,0,241,155,213,233,1,9,2,105,100,1,119,36,101,101,51,97,101,56,99,101,45,57,53,57,97,45,52,100,102,51,45,56,55,51,52,45,52,48,98,53,51,53,102,102,56,56,101,51,33,0,241,155,213,233,1,9,4,110,97,109,101,1,40,0,241,155,213,233,1,9,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,241,155,213,233,1,9,4,100,101,115,99,1,119,0,40,0,241,155,213,233,1,9,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,3,33,0,241,155,213,233,1,9,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,101,101,51,97,101,56,99,101,45,57,53,57,97,45,52,100,102,51,45,56,55,51,52,45,52,48,98,53,51,53,102,102,56,56,101,51,0,40,0,241,155,213,233,1,9,4,105,99,111,110,1,119,0,40,0,241,155,213,233,1,9,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,241,155,213,233,1,9,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,241,155,213,233,1,9,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,234,153,236,158,4,21,1,161,241,155,213,233,1,20,1,161,241,155,213,233,1,19,1,129,241,155,213,233,1,5,1,161,241,155,213,233,1,22,1,161,241,155,213,233,1,23,1,161,241,155,213,233,1,11,1,161,241,155,213,233,1,25,1,161,241,155,213,233,1,26,1,161,241,155,213,233,1,27,1,161,241,155,213,233,1,28,1,161,241,155,213,233,1,29,1,161,241,155,213,233,1,30,1,161,241,155,213,233,1,31,1,161,241,155,213,233,1,32,1,161,241,155,213,233,1,33,1,161,241,155,213,233,1,34,1,161,241,155,213,233,1,35,1,161,241,155,213,233,1,36,1,161,241,155,213,233,1,37,1,161,241,155,213,233,1,38,1,161,241,155,213,233,1,39,1,161,241,155,213,233,1,40,1,161,241,155,213,233,1,41,1,161,241,155,213,233,1,42,1,161,241,155,213,233,1,43,1,161,241,155,213,233,1,44,1,161,241,155,213,233,1,45,1,161,241,155,213,233,1,46,1,161,241,155,213,233,1,47,1,168,241,155,213,233,1,48,1,119,8,67,97,108,101,110,100,97,114,1,240,253,240,229,1,0,161,178,203,205,182,4,0,79,20,176,154,159,227,1,0,33,0,203,184,221,173,11,2,7,112,114,105,118,97,116,101,1,136,130,180,254,251,6,0,1,118,1,2,105,100,119,36,54,53,98,48,54,100,98,56,45,55,48,54,49,45,52,98,102,54,45,98,51,49,53,45,55,53,56,99,48,100,100,50,53,99,100,102,161,130,180,254,251,6,1,1,161,130,180,254,251,6,2,1,39,0,203,184,221,173,11,1,36,54,53,98,48,54,100,98,56,45,55,48,54,49,45,52,98,102,54,45,98,51,49,53,45,55,53,56,99,48,100,100,50,53,99,100,102,1,40,0,176,154,159,227,1,4,2,105,100,1,119,36,54,53,98,48,54,100,98,56,45,55,48,54,49,45,52,98,102,54,45,98,51,49,53,45,55,53,56,99,48,100,100,50,53,99,100,102,40,0,176,154,159,227,1,4,4,110,97,109,101,1,119,0,40,0,176,154,159,227,1,4,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,176,154,159,227,1,4,4,100,101,115,99,1,119,0,40,0,176,154,159,227,1,4,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,176,154,159,227,1,4,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,12,194,112,39,0,203,184,221,173,11,4,36,54,53,98,48,54,100,98,56,45,55,48,54,49,45,52,98,102,54,45,98,51,49,53,45,55,53,56,99,48,100,100,50,53,99,100,102,0,40,0,176,154,159,227,1,4,4,105,99,111,110,1,119,0,40,0,176,154,159,227,1,4,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,176,154,159,227,1,4,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,176,154,159,227,1,4,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,207,228,238,162,8,37,1,161,176,154,159,227,1,15,1,161,176,154,159,227,1,14,1,129,207,228,238,162,8,49,1,2,175,147,217,214,1,0,161,246,185,174,192,6,87,1,161,246,185,174,192,6,89,32,6,202,160,246,212,1,0,161,178,162,190,217,10,0,1,161,178,162,190,217,10,1,1,161,178,162,190,217,10,2,1,161,202,160,246,212,1,0,1,161,202,160,246,212,1,1,1,161,202,160,246,212,1,2,1,39,137,164,190,210,1,0,168,166,201,221,141,13,69,1,122,4,56,115,160,190,64,16,0,168,166,201,221,141,13,70,1,122,0,0,0,0,102,86,193,57,136,166,201,221,141,13,71,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,86,193,57,2,105,100,119,36,50,97,54,101,53,101,50,49,45,97,57,51,56,45,52,53,97,53,45,97,52,52,53,45,100,48,98,55,49,52,57,53,98,48,55,55,161,174,151,139,93,254,1,1,161,174,151,139,93,255,1,1,136,162,238,198,212,7,2,1,118,2,2,105,100,119,36,101,52,49,48,55,52,55,98,45,53,102,50,102,45,52,53,97,48,45,98,50,102,55,45,56,57,48,97,100,51,48,48,49,51,53,53,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,87,240,30,161,247,200,243,247,14,15,1,168,137,164,190,210,1,3,1,122,4,56,115,160,190,64,16,0,168,137,164,190,210,1,4,1,122,0,0,0,0,102,87,240,30,136,137,164,190,210,1,5,1,118,2,2,105,100,119,36,101,52,49,48,55,52,55,98,45,53,102,50,102,45,52,53,97,48,45,98,50,102,55,45,56,57,48,97,100,51,48,48,49,51,53,53,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,87,240,30,39,0,203,184,221,173,11,1,36,48,51,50,55,98,54,57,52,45,50,100,101,51,45,53,101,48,48,45,98,51,54,56,45,57,56,99,97,49,56,50,51,48,102,97,57,1,40,0,137,164,190,210,1,10,2,105,100,1,119,36,48,51,50,55,98,54,57,52,45,50,100,101,51,45,53,101,48,48,45,98,51,54,56,45,57,56,99,97,49,56,50,51,48,102,97,57,40,0,137,164,190,210,1,10,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,137,164,190,210,1,10,3,98,105,100,1,119,36,48,51,50,55,98,54,57,52,45,50,100,101,51,45,53,101,48,48,45,98,51,54,56,45,57,56,99,97,49,56,50,51,48,102,97,57,40,0,137,164,190,210,1,10,4,100,101,115,99,1,119,0,40,0,137,164,190,210,1,10,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,137,164,190,210,1,10,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,87,240,32,39,0,203,184,221,173,11,4,36,48,51,50,55,98,54,57,52,45,50,100,101,51,45,53,101,48,48,45,98,51,54,56,45,57,56,99,97,49,56,50,51,48,102,97,57,0,40,0,137,164,190,210,1,10,4,105,99,111,110,1,119,0,40,0,137,164,190,210,1,10,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,137,164,190,210,1,10,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,137,164,190,210,1,10,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,168,137,164,190,210,1,21,1,122,4,56,115,160,190,64,16,0,168,137,164,190,210,1,20,1,122,0,0,0,0,102,87,240,32,40,0,137,164,190,210,1,10,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,161,137,164,190,210,1,6,1,161,166,201,221,141,13,13,1,161,166,201,221,141,13,14,1,136,137,164,190,210,1,9,1,118,2,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,88,24,223,168,137,164,190,210,1,26,1,122,4,56,115,160,190,64,16,0,168,137,164,190,210,1,27,1,122,0,0,0,0,102,88,24,223,136,137,164,190,210,1,28,1,118,2,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,88,24,223,161,162,238,198,212,7,0,1,161,162,238,198,212,7,1,1,136,137,164,190,210,1,31,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,88,31,80,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,168,137,164,190,210,1,25,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,168,137,164,190,210,1,32,1,122,4,56,115,160,190,64,16,0,168,137,164,190,210,1,33,1,122,0,0,0,0,102,88,31,80,136,137,164,190,210,1,34,1,118,2,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,88,31,80,1,152,252,186,192,1,0,161,211,166,203,229,4,194,1,2,3,248,136,168,181,1,0,161,197,254,154,201,10,0,1,161,197,254,154,201,10,1,1,129,197,254,154,201,10,2,1,1,234,187,164,181,1,0,161,253,205,145,137,11,5,24,3,164,188,201,172,1,0,161,222,205,223,235,7,28,1,161,222,205,223,235,7,29,1,129,222,205,223,235,7,30,1,4,233,247,183,159,1,0,161,244,226,228,149,2,23,1,161,248,153,216,10,0,1,161,248,153,216,10,1,1,129,187,173,214,176,15,2,1,1,190,139,191,155,1,0,161,157,207,243,216,6,1,2,3,141,216,158,150,1,0,161,225,248,138,176,2,46,1,161,225,248,138,176,2,47,1,129,225,248,138,176,2,48,1,1,213,255,156,145,1,0,161,177,219,160,167,7,3,2,38,170,255,211,105,0,161,140,152,206,145,6,162,1,1,161,140,152,206,145,6,163,1,1,136,140,152,206,145,6,161,1,1,118,2,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,246,42,161,245,220,194,52,3,1,161,245,220,194,52,4,1,129,245,220,194,52,11,1,161,140,152,206,145,6,158,1,1,161,170,255,211,105,3,1,161,170,255,211,105,4,1,129,170,255,211,105,5,1,161,140,152,206,145,6,37,1,161,140,152,206,145,6,38,1,129,170,255,211,105,9,1,161,170,255,211,105,6,1,161,170,255,211,105,10,1,161,170,255,211,105,11,1,129,170,255,211,105,12,1,161,245,220,194,52,18,1,161,245,220,194,52,19,1,129,170,255,211,105,16,1,161,170,255,211,105,13,1,161,170,255,211,105,17,1,161,170,255,211,105,18,1,129,170,255,211,105,19,1,161,170,255,211,105,14,1,161,170,255,211,105,15,1,129,170,255,211,105,23,1,161,170,255,211,105,20,1,168,170,255,211,105,24,1,122,4,56,115,160,190,64,16,0,168,170,255,211,105,25,1,122,0,0,0,0,102,83,252,197,136,170,255,211,105,26,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,252,197,2,105,100,119,36,101,101,51,97,101,56,99,101,45,57,53,57,97,45,52,100,102,51,45,56,55,51,52,45,52,48,98,53,51,53,102,102,56,56,101,51,161,245,220,194,52,24,1,161,245,220,194,52,25,1,129,170,255,211,105,30,1,161,170,255,211,105,27,1,161,170,255,211,105,31,1,161,170,255,211,105,32,1,129,170,255,211,105,33,1,179,2,174,151,139,93,0,161,177,161,136,243,11,7,1,161,177,161,136,243,11,8,1,129,177,161,136,243,11,9,1,161,177,161,136,243,11,0,1,161,177,161,136,243,11,1,1,129,174,151,139,93,2,1,161,177,161,136,243,11,6,1,161,174,151,139,93,3,1,161,174,151,139,93,4,1,129,174,151,139,93,5,1,161,165,139,157,171,15,14,1,161,165,139,157,171,15,13,1,129,174,151,139,93,9,1,161,174,151,139,93,6,1,161,174,151,139,93,10,1,161,174,151,139,93,11,1,129,174,151,139,93,12,1,161,174,151,139,93,13,1,161,174,151,139,93,7,1,161,174,151,139,93,8,1,129,174,151,139,93,16,1,161,174,151,139,93,18,1,161,174,151,139,93,19,1,129,174,151,139,93,20,1,161,241,155,213,233,1,3,1,161,241,155,213,233,1,4,1,129,174,151,139,93,23,1,161,174,151,139,93,17,1,161,174,151,139,93,24,1,161,174,151,139,93,25,1,129,174,151,139,93,26,1,161,174,151,139,93,21,1,161,174,151,139,93,22,1,129,174,151,139,93,30,1,161,174,151,139,93,27,1,161,174,151,139,93,31,1,161,174,151,139,93,32,1,129,174,151,139,93,33,1,161,174,151,139,93,0,1,161,174,151,139,93,1,1,129,174,151,139,93,37,1,161,174,151,139,93,34,1,161,174,151,139,93,38,1,161,174,151,139,93,39,1,129,174,151,139,93,40,1,39,0,203,184,221,173,11,1,36,102,53,54,98,100,102,48,102,45,57,48,99,56,45,53,51,102,98,45,57,55,100,57,45,97,100,53,56,54,48,100,50,98,55,97,48,1,40,0,174,151,139,93,45,2,105,100,1,119,36,102,53,54,98,100,102,48,102,45,57,48,99,56,45,53,51,102,98,45,57,55,100,57,45,97,100,53,56,54,48,100,50,98,55,97,48,40,0,174,151,139,93,45,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,174,151,139,93,45,3,98,105,100,1,119,36,102,53,54,98,100,102,48,102,45,57,48,99,56,45,53,51,102,98,45,57,55,100,57,45,97,100,53,56,54,48,100,50,98,55,97,48,40,0,174,151,139,93,45,4,100,101,115,99,1,119,0,40,0,174,151,139,93,45,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,174,151,139,93,45,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,77,101,46,39,0,203,184,221,173,11,4,36,102,53,54,98,100,102,48,102,45,57,48,99,56,45,53,51,102,98,45,57,55,100,57,45,97,100,53,56,54,48,100,50,98,55,97,48,0,40,0,174,151,139,93,45,4,105,99,111,110,1,119,0,40,0,174,151,139,93,45,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,174,151,139,93,45,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,174,151,139,93,45,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,168,174,151,139,93,56,1,122,4,56,115,160,190,64,16,0,168,174,151,139,93,55,1,122,0,0,0,0,102,77,101,47,40,0,174,151,139,93,45,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,161,174,151,139,93,42,1,161,174,151,139,93,43,1,129,174,151,139,93,44,1,161,174,151,139,93,60,1,161,174,151,139,93,61,1,129,174,151,139,93,62,1,161,234,153,236,158,4,61,1,161,234,153,236,158,4,62,1,129,174,151,139,93,65,1,161,174,151,139,93,41,1,161,174,151,139,93,66,1,161,174,151,139,93,67,1,129,174,151,139,93,68,1,161,174,151,139,93,63,1,161,174,151,139,93,64,1,129,174,151,139,93,72,1,161,174,151,139,93,69,1,161,174,151,139,93,73,1,161,174,151,139,93,74,1,129,174,151,139,93,75,1,161,174,151,139,93,70,1,161,174,151,139,93,71,1,129,174,151,139,93,79,1,161,174,151,139,93,76,1,161,174,151,139,93,80,1,161,174,151,139,93,81,1,129,174,151,139,93,82,1,161,174,151,139,93,83,1,161,174,151,139,93,28,1,161,174,151,139,93,29,1,129,174,151,139,93,86,1,161,174,151,139,93,87,1,161,201,129,238,197,4,71,1,161,201,129,238,197,4,70,1,129,174,151,139,93,90,1,161,174,151,139,93,88,1,161,174,151,139,93,89,1,129,174,151,139,93,94,1,161,174,151,139,93,91,1,161,174,151,139,93,35,1,161,174,151,139,93,36,1,129,174,151,139,93,97,1,161,174,151,139,93,99,1,161,174,151,139,93,100,1,129,174,151,139,93,101,1,161,174,151,139,93,92,1,161,174,151,139,93,93,1,129,174,151,139,93,104,1,161,174,151,139,93,102,1,161,174,151,139,93,103,1,129,174,151,139,93,107,1,161,174,151,139,93,108,1,161,174,151,139,93,109,1,129,174,151,139,93,110,1,39,0,203,184,221,173,11,1,36,50,49,97,100,55,99,57,48,45,98,102,53,57,45,53,100,97,56,45,57,97,98,99,45,53,98,50,50,102,56,102,102,54,99,52,101,1,40,0,174,151,139,93,114,2,105,100,1,119,36,50,49,97,100,55,99,57,48,45,98,102,53,57,45,53,100,97,56,45,57,97,98,99,45,53,98,50,50,102,56,102,102,54,99,52,101,40,0,174,151,139,93,114,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,174,151,139,93,114,3,98,105,100,1,119,36,50,49,97,100,55,99,57,48,45,98,102,53,57,45,53,100,97,56,45,57,97,98,99,45,53,98,50,50,102,56,102,102,54,99,52,101,40,0,174,151,139,93,114,4,100,101,115,99,1,119,0,40,0,174,151,139,93,114,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,174,151,139,93,114,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,77,101,175,39,0,203,184,221,173,11,4,36,50,49,97,100,55,99,57,48,45,98,102,53,57,45,53,100,97,56,45,57,97,98,99,45,53,98,50,50,102,56,102,102,54,99,52,101,0,40,0,174,151,139,93,114,4,105,99,111,110,1,119,0,40,0,174,151,139,93,114,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,174,151,139,93,114,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,174,151,139,93,114,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,168,174,151,139,93,125,1,122,4,56,115,160,190,64,16,0,168,174,151,139,93,124,1,122,0,0,0,0,102,77,101,175,40,0,174,151,139,93,114,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,161,174,151,139,93,111,1,161,174,151,139,93,112,1,129,174,151,139,93,113,1,161,174,151,139,93,129,1,1,161,174,151,139,93,130,1,1,129,174,151,139,93,131,1,1,161,174,151,139,93,77,1,161,174,151,139,93,78,1,129,174,151,139,93,134,1,1,161,174,151,139,93,98,1,161,174,151,139,93,135,1,1,161,174,151,139,93,136,1,1,129,174,151,139,93,137,1,1,161,174,151,139,93,132,1,1,161,174,151,139,93,133,1,1,129,174,151,139,93,141,1,1,161,174,151,139,93,138,1,1,161,174,151,139,93,142,1,1,161,174,151,139,93,143,1,1,129,174,151,139,93,144,1,1,161,174,151,139,93,95,1,161,174,151,139,93,96,1,129,174,151,139,93,148,1,1,161,174,151,139,93,145,1,1,161,174,151,139,93,149,1,1,161,174,151,139,93,150,1,1,129,174,151,139,93,151,1,1,161,174,151,139,93,146,1,1,161,174,151,139,93,147,1,1,129,174,151,139,93,155,1,1,161,174,151,139,93,152,1,1,161,174,151,139,93,156,1,1,161,174,151,139,93,157,1,1,129,174,151,139,93,158,1,1,161,174,151,139,93,139,1,1,161,174,151,139,93,140,1,1,129,174,151,139,93,162,1,1,161,174,151,139,93,159,1,1,161,174,151,139,93,163,1,1,161,174,151,139,93,164,1,1,129,174,151,139,93,165,1,1,161,174,151,139,93,160,1,1,161,174,151,139,93,161,1,1,129,174,151,139,93,169,1,1,161,174,151,139,93,166,1,1,161,174,151,139,93,170,1,1,161,174,151,139,93,171,1,1,129,174,151,139,93,172,1,1,8,0,241,155,213,233,1,16,1,118,1,2,105,100,119,36,54,54,97,54,102,51,98,99,45,99,55,56,102,45,52,102,55,52,45,97,48,57,101,45,48,56,100,52,55,49,55,98,102,49,102,100,161,241,155,213,233,1,15,1,161,174,151,139,93,175,1,1,39,0,203,184,221,173,11,1,36,54,54,97,54,102,51,98,99,45,99,55,56,102,45,52,102,55,52,45,97,48,57,101,45,48,56,100,52,55,49,55,98,102,49,102,100,1,40,0,174,151,139,93,180,1,2,105,100,1,119,36,54,54,97,54,102,51,98,99,45,99,55,56,102,45,52,102,55,52,45,97,48,57,101,45,48,56,100,52,55,49,55,98,102,49,102,100,40,0,174,151,139,93,180,1,4,110,97,109,101,1,119,4,71,114,105,100,40,0,174,151,139,93,180,1,3,98,105,100,1,119,36,101,101,51,97,101,56,99,101,45,57,53,57,97,45,52,100,102,51,45,56,55,51,52,45,52,48,98,53,51,53,102,102,56,56,101,51,40,0,174,151,139,93,180,1,4,100,101,115,99,1,119,0,40,0,174,151,139,93,180,1,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,40,0,174,151,139,93,180,1,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,77,165,65,39,0,203,184,221,173,11,4,36,54,54,97,54,102,51,98,99,45,99,55,56,102,45,52,102,55,52,45,97,48,57,101,45,48,56,100,52,55,49,55,98,102,49,102,100,0,40,0,174,151,139,93,180,1,4,105,99,111,110,1,119,0,40,0,174,151,139,93,180,1,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,174,151,139,93,180,1,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,102,77,165,65,40,0,174,151,139,93,180,1,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,39,0,203,184,221,173,11,1,36,49,102,98,50,53,48,49,57,45,52,51,57,52,45,53,57,54,53,45,97,49,50,98,45,49,98,48,101,52,99,57,55,55,48,55,99,1,40,0,174,151,139,93,192,1,2,105,100,1,119,36,49,102,98,50,53,48,49,57,45,52,51,57,52,45,53,57,54,53,45,97,49,50,98,45,49,98,48,101,52,99,57,55,55,48,55,99,40,0,174,151,139,93,192,1,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,174,151,139,93,192,1,3,98,105,100,1,119,36,49,102,98,50,53,48,49,57,45,52,51,57,52,45,53,57,54,53,45,97,49,50,98,45,49,98,48,101,52,99,57,55,55,48,55,99,40,0,174,151,139,93,192,1,4,100,101,115,99,1,119,0,40,0,174,151,139,93,192,1,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,174,151,139,93,192,1,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,77,166,20,39,0,203,184,221,173,11,4,36,49,102,98,50,53,48,49,57,45,52,51,57,52,45,53,57,54,53,45,97,49,50,98,45,49,98,48,101,52,99,57,55,55,48,55,99,0,40,0,174,151,139,93,192,1,4,105,99,111,110,1,119,0,40,0,174,151,139,93,192,1,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,174,151,139,93,192,1,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,174,151,139,93,192,1,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,168,174,151,139,93,203,1,1,122,4,56,115,160,190,64,16,0,168,174,151,139,93,202,1,1,122,0,0,0,0,102,77,166,20,40,0,174,151,139,93,192,1,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,39,0,203,184,221,173,11,1,36,54,97,102,100,54,57,56,52,45,48,51,98,52,45,53,53,57,100,45,98,49,52,54,45,52,49,100,98,97,54,49,50,49,48,98,56,1,40,0,174,151,139,93,207,1,2,105,100,1,119,36,54,97,102,100,54,57,56,52,45,48,51,98,52,45,53,53,57,100,45,98,49,52,54,45,52,49,100,98,97,54,49,50,49,48,98,56,40,0,174,151,139,93,207,1,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,174,151,139,93,207,1,3,98,105,100,1,119,36,54,97,102,100,54,57,56,52,45,48,51,98,52,45,53,53,57,100,45,98,49,52,54,45,52,49,100,98,97,54,49,50,49,48,98,56,40,0,174,151,139,93,207,1,4,100,101,115,99,1,119,0,40,0,174,151,139,93,207,1,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,174,151,139,93,207,1,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,77,183,211,39,0,203,184,221,173,11,4,36,54,97,102,100,54,57,56,52,45,48,51,98,52,45,53,53,57,100,45,98,49,52,54,45,52,49,100,98,97,54,49,50,49,48,98,56,0,40,0,174,151,139,93,207,1,4,105,99,111,110,1,119,0,40,0,174,151,139,93,207,1,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,174,151,139,93,207,1,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,174,151,139,93,207,1,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,168,174,151,139,93,218,1,1,122,4,56,115,160,190,64,16,0,168,174,151,139,93,217,1,1,122,0,0,0,0,102,77,183,211,40,0,174,151,139,93,207,1,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,39,0,203,184,221,173,11,1,36,53,54,53,50,101,52,54,54,45,101,52,99,101,45,53,54,57,99,45,98,49,101,54,45,102,100,56,101,48,101,55,100,99,48,100,99,1,40,0,174,151,139,93,222,1,2,105,100,1,119,36,53,54,53,50,101,52,54,54,45,101,52,99,101,45,53,54,57,99,45,98,49,101,54,45,102,100,56,101,48,101,55,100,99,48,100,99,40,0,174,151,139,93,222,1,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,174,151,139,93,222,1,3,98,105,100,1,119,36,53,54,53,50,101,52,54,54,45,101,52,99,101,45,53,54,57,99,45,98,49,101,54,45,102,100,56,101,48,101,55,100,99,48,100,99,40,0,174,151,139,93,222,1,4,100,101,115,99,1,119,0,40,0,174,151,139,93,222,1,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,174,151,139,93,222,1,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,77,187,249,39,0,203,184,221,173,11,4,36,53,54,53,50,101,52,54,54,45,101,52,99,101,45,53,54,57,99,45,98,49,101,54,45,102,100,56,101,48,101,55,100,99,48,100,99,0,40,0,174,151,139,93,222,1,4,105,99,111,110,1,119,0,40,0,174,151,139,93,222,1,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,174,151,139,93,222,1,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,174,151,139,93,222,1,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,168,174,151,139,93,233,1,1,122,4,56,115,160,190,64,16,0,168,174,151,139,93,232,1,1,122,0,0,0,0,102,77,187,249,40,0,174,151,139,93,222,1,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,161,174,151,139,93,167,1,1,161,174,151,139,93,168,1,1,129,174,151,139,93,176,1,1,161,174,151,139,93,173,1,1,161,174,151,139,93,237,1,1,161,174,151,139,93,238,1,1,129,174,151,139,93,239,1,1,161,174,151,139,93,241,1,1,161,174,151,139,93,242,1,1,129,241,130,161,205,7,11,1,161,174,151,139,93,244,1,1,161,174,151,139,93,245,1,1,129,174,151,139,93,246,1,1,161,241,130,161,205,7,3,1,161,241,130,161,205,7,4,1,129,174,151,139,93,249,1,1,161,174,151,139,93,240,1,1,161,174,151,139,93,250,1,1,161,174,151,139,93,251,1,1,129,174,151,139,93,252,1,1,161,174,151,139,93,247,1,1,161,174,151,139,93,248,1,1,129,174,151,139,93,128,2,1,161,174,151,139,93,253,1,1,161,174,151,139,93,129,2,1,161,174,151,139,93,130,2,1,129,174,151,139,93,131,2,1,161,226,212,179,248,2,9,1,161,226,212,179,248,2,10,1,129,174,151,139,93,135,2,1,161,174,151,139,93,132,2,1,161,174,151,139,93,136,2,1,161,174,151,139,93,137,2,1,129,174,151,139,93,138,2,1,161,174,151,139,93,133,2,1,161,174,151,139,93,134,2,1,129,174,151,139,93,142,2,1,161,174,151,139,93,139,2,1,161,174,151,139,93,143,2,1,161,174,151,139,93,144,2,1,129,174,151,139,93,145,2,1,39,0,203,184,221,173,11,1,36,51,50,48,102,56,48,97,100,45,50,51,52,101,45,53,49,55,50,45,97,49,55,50,45,102,55,56,52,54,52,55,50,55,98,100,97,1,40,0,174,151,139,93,150,2,2,105,100,1,119,36,51,50,48,102,56,48,97,100,45,50,51,52,101,45,53,49,55,50,45,97,49,55,50,45,102,55,56,52,54,52,55,50,55,98,100,97,40,0,174,151,139,93,150,2,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,174,151,139,93,150,2,3,98,105,100,1,119,36,51,50,48,102,56,48,97,100,45,50,51,52,101,45,53,49,55,50,45,97,49,55,50,45,102,55,56,52,54,52,55,50,55,98,100,97,40,0,174,151,139,93,150,2,4,100,101,115,99,1,119,0,40,0,174,151,139,93,150,2,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,174,151,139,93,150,2,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,78,228,14,39,0,203,184,221,173,11,4,36,51,50,48,102,56,48,97,100,45,50,51,52,101,45,53,49,55,50,45,97,49,55,50,45,102,55,56,52,54,52,55,50,55,98,100,97,0,40,0,174,151,139,93,150,2,4,105,99,111,110,1,119,0,40,0,174,151,139,93,150,2,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,174,151,139,93,150,2,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,174,151,139,93,150,2,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,168,174,151,139,93,161,2,1,122,4,56,115,160,190,64,16,0,168,174,151,139,93,160,2,1,122,0,0,0,0,102,78,228,14,40,0,174,151,139,93,150,2,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,161,174,151,139,93,14,1,161,174,151,139,93,15,1,129,174,151,139,93,149,2,1,161,174,151,139,93,146,2,1,168,174,151,139,93,165,2,1,122,4,56,115,160,190,64,16,0,161,174,151,139,93,166,2,1,136,174,151,139,93,167,2,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,78,229,144,2,105,100,119,36,97,53,53,54,54,101,52,57,45,102,49,53,54,45,52,49,54,56,45,57,98,50,100,45,49,55,57,50,54,99,53,100,97,51,50,57,161,174,151,139,93,147,2,1,161,174,151,139,93,148,2,1,129,174,151,139,93,171,2,1,161,174,151,139,93,168,2,1,161,174,151,139,93,172,2,1,161,174,151,139,93,173,2,1,129,174,151,139,93,174,2,1,1,184,231,170,67,0,161,145,144,146,185,5,11,6,39,245,220,194,52,0,161,209,250,203,254,15,0,1,161,209,250,203,254,15,1,1,136,209,250,203,254,15,2,1,118,2,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,246,151,161,140,152,206,145,6,152,1,1,161,140,152,206,145,6,153,1,1,129,245,220,194,52,2,1,161,245,220,194,52,0,1,161,245,220,194,52,1,1,136,245,220,194,52,5,1,118,2,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,246,202,161,140,152,206,145,6,87,1,161,140,152,206,145,6,88,1,136,245,220,194,52,8,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,246,206,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,161,245,220,194,52,3,1,161,245,220,194,52,4,1,129,245,220,194,52,11,1,161,170,255,211,105,7,1,161,170,255,211,105,8,1,161,140,152,206,145,6,151,1,1,161,245,220,194,52,15,1,161,245,220,194,52,16,1,161,245,220,194,52,17,1,161,170,255,211,105,21,1,161,170,255,211,105,22,1,161,245,220,194,52,20,1,161,245,220,194,52,21,1,161,245,220,194,52,22,1,161,245,220,194,52,23,1,161,170,255,211,105,35,1,161,170,255,211,105,36,1,129,170,255,211,105,37,1,161,245,220,194,52,27,1,161,245,220,194,52,28,1,129,245,220,194,52,29,1,161,245,220,194,52,30,1,161,245,220,194,52,31,1,161,245,220,194,52,26,1,161,245,220,194,52,33,1,161,245,220,194,52,34,1,161,245,220,194,52,35,1,6,166,203,155,46,0,161,140,152,206,145,6,30,1,161,140,152,206,145,6,31,1,129,162,238,198,212,7,2,1,168,166,203,155,46,0,1,122,4,56,115,160,190,64,16,0,168,166,203,155,46,1,1,122,0,0,0,0,102,88,52,80,136,166,203,155,46,2,1,118,2,2,105,100,119,36,48,99,101,49,51,52,49,53,45,54,99,99,101,45,52,52,57,55,45,57,52,99,54,45,52,55,53,97,100,57,54,99,50,52,57,101,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,88,52,80,3,179,252,154,44,0,161,157,240,144,231,2,0,1,161,157,240,144,231,2,1,1,129,157,240,144,231,2,2,1,3,248,153,216,10,0,161,163,236,177,169,4,9,1,161,163,236,177,169,4,10,1,129,163,236,177,169,4,11,1,155,1,128,252,161,128,4,1,0,33,130,180,254,251,6,4,0,3,5,2,9,1,13,4,135,240,136,178,10,1,0,45,135,232,133,203,9,1,0,15,137,226,192,199,6,1,0,20,138,202,240,189,2,1,0,134,1,139,240,196,145,14,1,0,138,2,140,228,230,243,1,1,0,2,139,152,215,249,10,1,0,34,141,216,158,150,1,1,0,3,142,130,192,134,11,1,0,3,143,184,153,180,6,1,0,6,145,190,137,224,10,1,0,2,145,144,146,185,5,1,0,12,140,152,206,145,6,16,0,46,47,9,57,3,61,24,86,3,90,3,94,2,97,3,101,2,105,1,111,1,113,20,134,1,20,155,1,2,158,1,3,162,1,2,135,166,246,235,6,1,0,2,147,206,229,235,1,1,0,3,137,164,190,210,1,5,3,2,6,1,20,2,25,3,32,2,152,252,186,192,1,1,0,2,153,130,203,161,6,1,0,97,154,244,246,165,8,10,0,24,26,1,37,2,56,1,71,1,82,3,88,36,127,18,148,1,35,193,1,2,156,148,170,169,10,1,0,16,157,240,144,231,2,1,0,3,158,156,181,152,10,7,0,6,7,2,15,1,19,8,28,2,32,1,40,9,159,156,204,250,6,1,0,27,160,192,253,131,5,1,0,3,161,178,132,150,11,4,0,15,17,1,28,64,93,8,158,182,250,251,9,1,0,15,163,236,177,169,4,1,0,12,164,188,201,172,1,1,0,3,158,184,218,165,3,1,0,38,162,238,198,212,7,1,0,2,170,140,240,234,9,1,0,31,171,204,155,217,8,1,0,3,171,142,166,254,1,1,0,6,173,252,148,184,13,3,0,40,41,2,44,20,176,154,159,227,1,3,0,1,2,2,14,6,178,162,190,217,10,1,0,3,179,252,154,44,1,0,3,180,230,210,212,13,2,0,2,3,4,182,172,247,194,5,1,0,3,183,226,184,158,8,1,0,8,195,242,227,194,8,1,0,3,196,154,250,183,6,1,0,62,197,254,154,201,10,1,0,3,200,142,208,241,4,1,0,157,1,202,160,246,212,1,1,0,6,203,184,221,173,11,6,14,1,19,1,21,2,29,1,33,2,36,1,206,220,129,131,4,3,0,3,4,2,16,5,207,228,238,162,8,4,1,2,13,9,23,2,35,15,209,250,203,254,15,1,0,2,210,228,153,221,12,1,0,3,211,166,203,229,4,1,0,195,1,211,202,217,232,12,1,0,7,214,168,149,214,3,1,0,15,225,248,138,176,2,6,0,9,10,2,13,1,18,2,26,1,30,19,226,212,179,248,2,1,0,15,229,154,128,197,12,4,0,6,7,2,15,1,19,5,234,182,182,157,9,1,0,8,235,178,165,206,5,1,0,72,241,130,161,205,7,1,0,9,244,226,228,149,2,4,1,3,6,1,17,4,23,7,245,220,194,52,4,0,2,3,5,9,2,12,27,247,200,243,247,14,5,2,1,5,1,13,8,22,32,58,39,248,136,168,181,1,1,0,3,248,210,237,129,13,1,0,2,250,198,166,187,7,1,0,2,248,196,187,185,10,1,0,26,252,218,241,167,14,1,0,2,255,140,248,220,6,1,0,3,128,211,179,216,2,1,0,10,133,159,138,205,12,14,0,7,9,1,20,9,42,14,57,2,61,1,65,1,67,1,69,17,87,6,94,2,106,2,109,2,121,10,135,167,156,250,14,1,0,16,135,193,208,135,7,1,0,16,141,245,194,142,11,1,0,7,141,205,220,149,4,1,0,3,143,131,148,152,6,1,1,2,141,171,170,217,4,1,0,2,145,159,164,217,14,1,0,3,149,129,169,191,12,1,0,16,149,249,242,175,4,3,0,8,11,2,16,15,149,189,189,215,8,1,0,3,149,161,132,184,14,1,0,221,2,154,243,157,196,14,1,0,12,154,193,208,134,10,1,0,9,155,165,205,152,11,1,0,3,155,159,180,195,15,1,0,6,157,207,243,216,6,1,0,2,154,235,215,240,4,1,0,13,161,239,241,154,13,1,0,106,162,159,252,196,11,1,0,3,164,155,139,169,7,1,0,35,165,139,157,171,15,11,2,1,9,1,13,5,19,2,27,1,31,6,39,1,52,5,58,12,72,1,85,18,164,203,250,235,13,1,0,7,167,131,133,162,9,1,0,11,166,201,221,141,13,11,0,6,7,2,10,2,13,2,26,2,31,2,34,3,38,6,45,2,57,11,69,3,166,203,155,46,1,0,3,170,255,211,105,3,0,2,3,25,31,7,169,197,188,221,3,1,0,3,173,187,245,170,14,1,0,46,174,151,139,93,14,0,45,55,2,60,54,124,2,129,1,48,178,1,2,202,1,2,217,1,2,232,1,2,237,1,41,160,2,2,165,2,4,170,2,1,172,2,7,175,225,172,150,8,1,0,10,175,147,217,214,1,1,0,33,177,161,136,243,11,1,0,10,178,203,205,182,4,1,0,1,175,205,156,228,6,1,0,10,180,205,189,133,13,1,0,20,181,175,219,209,12,1,0,10,182,143,233,195,4,1,0,111,177,219,160,167,7,1,0,4,184,201,188,172,10,1,0,3,184,231,170,67,1,0,6,186,197,166,179,15,1,0,7,188,171,136,250,8,1,0,21,188,237,223,145,6,1,0,26,190,139,191,155,1,1,0,2,191,157,147,233,9,1,0,32,193,249,142,142,4,1,0,17,198,189,216,175,6,1,0,23,200,205,214,172,10,1,0,30,201,129,238,197,4,8,0,6,9,33,43,2,51,1,55,2,58,2,66,1,70,13,201,191,159,147,14,1,0,17,200,203,236,184,2,1,0,35,200,159,185,206,9,1,0,8,205,149,231,236,11,1,0,68,213,161,242,209,13,5,0,3,4,2,8,1,16,7,27,8,214,139,213,136,8,13,0,2,5,2,10,2,15,2,20,2,25,2,30,2,35,2,40,2,45,2,50,2,55,2,60,6,213,255,156,145,1,1,0,2,219,227,140,137,6,1,0,34,221,147,167,147,15,1,0,177,2,222,205,223,235,7,2,0,9,10,21,223,209,193,147,11,1,0,81,227,209,197,253,2,1,0,14,229,153,197,202,7,1,0,241,6,231,139,244,188,8,1,0,13,232,207,157,148,2,1,0,2,233,165,139,246,14,4,0,2,3,4,8,2,20,23,233,247,183,159,1,1,0,4,235,225,184,133,10,1,0,3,234,153,236,158,4,8,0,6,7,2,11,1,15,1,19,6,27,1,38,7,46,27,234,187,164,181,1,1,0,24,231,189,134,196,8,1,0,77,239,199,189,146,3,1,0,24,240,149,229,225,6,1,1,2,241,155,213,233,1,5,0,6,7,2,11,1,15,1,19,32,240,253,240,229,1,1,0,79,243,239,182,181,13,2,1,2,16,2,236,229,225,232,8,1,0,116,246,185,174,192,6,1,0,90,248,153,216,10,1,0,3,251,189,220,155,14,1,0,3,252,163,130,200,6,2,1,2,16,2,253,205,145,137,11,1,0,10,252,171,209,175,15,1,0,4,255,255,147,249,10,1,0,3],"version":0,"object_id":"9eebea03-3ed5-4298-86b2-a7f77856d48b"},"code":0,"message":"Operation completed successfully."} \ No newline at end of file +{"data":{"state_vector":[160,1,128,252,161,128,4,33,130,180,254,251,6,18,135,232,133,203,9,15,135,240,136,178,10,45,137,226,192,199,6,20,138,202,240,189,2,134,1,139,240,196,145,14,138,2,139,152,215,249,10,34,141,216,158,150,1,3,142,130,192,134,11,3,143,184,153,180,6,6,140,228,230,243,1,2,145,190,137,224,10,2,145,144,146,185,5,12,140,152,206,145,6,165,1,135,166,246,235,6,3,147,206,229,235,1,3,137,164,190,210,1,39,152,158,185,230,10,7,153,130,203,161,6,97,152,252,186,192,1,2,154,244,246,165,8,198,1,156,148,170,169,10,16,157,240,144,231,2,3,158,156,181,152,10,49,158,182,250,251,9,15,160,192,253,131,5,3,161,178,132,150,11,101,159,156,204,250,6,27,163,236,177,169,4,12,164,188,201,172,1,3,158,184,218,165,3,38,162,238,198,212,7,3,170,140,240,234,9,31,171,204,155,217,8,3,171,142,166,254,1,6,173,252,148,184,13,64,176,154,159,227,1,20,178,162,190,217,10,3,179,252,154,44,3,180,230,210,212,13,7,182,172,247,194,5,3,183,226,184,158,8,8,187,220,199,239,8,70,195,242,227,194,8,3,196,154,250,183,6,62,197,254,154,201,10,3,200,142,208,241,4,157,1,202,160,246,212,1,6,203,184,221,173,11,37,206,220,129,131,4,21,207,228,238,162,8,50,209,250,203,254,15,3,210,228,153,221,12,3,211,202,217,232,12,7,211,166,203,229,4,195,1,214,168,149,214,3,15,219,220,239,171,8,10,225,248,138,176,2,49,226,212,179,248,2,15,229,154,128,197,12,24,234,182,182,157,9,8,235,178,165,206,5,72,234,156,130,211,12,12,241,130,161,205,7,12,244,226,228,149,2,30,245,220,194,52,39,247,200,243,247,14,100,248,136,168,181,1,3,248,210,237,129,13,2,250,198,166,187,7,2,248,196,187,185,10,31,252,218,241,167,14,3,255,140,248,220,6,3,128,211,179,216,2,10,133,159,138,205,12,131,1,135,167,156,250,14,16,135,193,208,135,7,16,141,245,194,142,11,7,141,205,220,149,4,3,143,131,148,152,6,15,141,171,170,217,4,2,145,159,164,217,14,3,149,129,169,191,12,16,149,249,242,175,4,31,149,189,189,215,8,3,149,161,132,184,14,221,2,154,243,157,196,14,12,154,193,208,134,10,9,155,165,205,152,11,3,154,235,215,240,4,13,155,159,180,195,15,6,157,207,243,216,6,2,161,239,241,154,13,106,162,159,252,196,11,3,164,155,139,169,7,35,165,139,157,171,15,103,164,203,250,235,13,7,167,131,133,162,9,11,166,201,221,141,13,72,169,197,188,221,3,3,170,255,211,105,38,166,203,155,46,6,173,187,245,170,14,46,174,151,139,93,179,2,175,225,172,150,8,11,175,147,217,214,1,33,177,161,136,243,11,10,178,203,205,182,4,1,175,205,156,228,6,10,180,205,189,133,13,20,181,175,219,209,12,10,182,143,233,195,4,111,177,219,160,167,7,4,184,201,188,172,10,3,184,231,170,67,6,186,197,166,179,15,7,187,173,214,176,15,3,188,171,136,250,8,21,188,237,223,145,6,26,190,139,191,155,1,2,191,157,147,233,9,32,193,249,142,142,4,17,198,189,216,175,6,23,200,205,214,172,10,30,201,129,238,197,4,84,201,191,159,147,14,17,200,203,236,184,2,35,200,159,185,206,9,8,205,149,231,236,11,68,213,161,242,209,13,35,214,139,213,136,8,66,213,255,156,145,1,2,219,227,140,137,6,34,221,147,167,147,15,177,2,222,205,223,235,7,31,223,209,193,147,11,81,227,209,197,253,2,14,229,153,197,202,7,241,6,231,139,244,188,8,13,232,207,157,148,2,2,233,165,139,246,14,43,233,247,183,159,1,4,235,225,184,133,10,3,234,153,236,158,4,73,234,187,164,181,1,24,231,189,134,196,8,77,239,199,189,146,3,24,240,149,229,225,6,15,241,155,213,233,1,52,240,253,240,229,1,79,243,239,182,181,13,30,236,229,225,232,8,116,246,185,174,192,6,90,248,153,216,10,3,251,189,220,155,14,3,252,163,130,200,6,30,253,205,145,137,11,10,252,171,209,175,15,4,255,255,147,249,10,3],"doc_state":[160,1,3,209,250,203,254,15,0,161,226,212,179,248,2,9,1,161,226,212,179,248,2,10,1,136,174,151,139,93,249,1,1,118,2,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,246,78,2,155,159,180,195,15,0,161,198,189,216,175,6,22,1,161,253,205,145,137,11,9,5,7,186,197,166,179,15,0,161,161,178,132,150,11,98,1,161,161,178,132,150,11,99,1,129,161,178,132,150,11,100,1,161,161,178,132,150,11,97,1,161,161,178,132,150,11,94,1,161,161,178,132,150,11,95,1,129,186,197,166,179,15,2,1,3,187,173,214,176,15,0,168,244,226,228,149,2,27,1,122,4,56,115,160,190,64,16,0,168,244,226,228,149,2,28,1,122,0,0,0,0,102,32,153,171,136,248,153,216,10,2,1,118,2,2,105,100,119,36,48,53,51,51,50,98,97,52,45,97,54,57,48,45,52,50,57,51,45,57,56,54,54,45,56,52,100,97,99,55,102,101,50,97,101,97,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,32,153,171,1,252,171,209,175,15,0,161,128,211,179,216,2,9,4,103,165,139,157,171,15,0,8,0,201,129,238,197,4,52,1,118,1,2,105,100,119,36,97,53,53,54,54,101,52,57,45,102,49,53,54,45,52,49,54,56,45,57,98,50,100,45,49,55,57,50,54,99,53,100,97,51,50,57,168,201,129,238,197,4,51,1,122,0,0,0,0,102,74,244,14,161,170,140,240,234,9,22,1,39,0,203,184,221,173,11,1,36,97,53,53,54,54,101,52,57,45,102,49,53,54,45,52,49,54,56,45,57,98,50,100,45,49,55,57,50,54,99,53,100,97,51,50,57,1,40,0,165,139,157,171,15,3,2,105,100,1,119,36,97,53,53,54,54,101,52,57,45,102,49,53,54,45,52,49,54,56,45,57,98,50,100,45,49,55,57,50,54,99,53,100,97,51,50,57,40,0,165,139,157,171,15,3,4,110,97,109,101,1,119,14,66,111,97,114,100,32,99,104,101,99,107,98,111,120,40,0,165,139,157,171,15,3,3,98,105,100,1,119,36,101,52,49,48,55,52,55,98,45,53,102,50,102,45,52,53,97,48,45,98,50,102,55,45,56,57,48,97,100,51,48,48,49,51,53,53,40,0,165,139,157,171,15,3,4,100,101,115,99,1,119,0,40,0,165,139,157,171,15,3,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,2,33,0,165,139,157,171,15,3,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,97,53,53,54,54,101,52,57,45,102,49,53,54,45,52,49,54,56,45,57,98,50,100,45,49,55,57,50,54,99,53,100,97,51,50,57,0,40,0,165,139,157,171,15,3,4,105,99,111,110,1,119,0,40,0,165,139,157,171,15,3,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,165,139,157,171,15,3,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,165,139,157,171,15,3,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,170,140,240,234,9,21,1,161,165,139,157,171,15,2,1,129,159,156,204,250,6,26,1,136,225,248,138,176,2,17,1,118,1,2,105,100,119,36,49,98,48,101,51,50,50,100,45,52,57,48,57,45,52,99,54,51,45,57,49,52,97,45,100,48,51,52,102,99,51,54,51,48,57,55,161,225,248,138,176,2,18,1,161,193,249,142,142,4,8,1,39,0,203,184,221,173,11,1,36,49,98,48,101,51,50,50,100,45,52,57,48,57,45,52,99,54,51,45,57,49,52,97,45,100,48,51,52,102,99,51,54,51,48,57,55,1,40,0,165,139,157,171,15,21,2,105,100,1,119,36,49,98,48,101,51,50,50,100,45,52,57,48,57,45,52,99,54,51,45,57,49,52,97,45,100,48,51,52,102,99,51,54,51,48,57,55,40,0,165,139,157,171,15,21,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,165,139,157,171,15,21,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,165,139,157,171,15,21,4,100,101,115,99,1,119,0,40,0,165,139,157,171,15,21,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,2,33,0,165,139,157,171,15,21,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,49,98,48,101,51,50,50,100,45,52,57,48,57,45,52,99,54,51,45,57,49,52,97,45,100,48,51,52,102,99,51,54,51,48,57,55,0,40,0,165,139,157,171,15,21,4,105,99,111,110,1,119,0,40,0,165,139,157,171,15,21,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,165,139,157,171,15,21,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,165,139,157,171,15,21,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,193,249,142,142,4,13,1,161,165,139,157,171,15,32,1,161,165,139,157,171,15,31,1,129,165,139,157,171,15,17,1,8,0,165,139,157,171,15,28,1,118,1,2,105,100,119,36,51,53,48,102,52,50,53,98,45,98,54,55,49,45,52,101,50,100,45,56,49,56,50,45,53,57,57,56,97,54,101,54,50,57,50,52,168,165,139,157,171,15,27,1,122,0,0,0,0,102,74,246,67,161,165,139,157,171,15,35,1,39,0,203,184,221,173,11,1,36,51,53,48,102,52,50,53,98,45,98,54,55,49,45,52,101,50,100,45,56,49,56,50,45,53,57,57,56,97,54,101,54,50,57,50,52,1,40,0,165,139,157,171,15,40,2,105,100,1,119,36,51,53,48,102,52,50,53,98,45,98,54,55,49,45,52,101,50,100,45,56,49,56,50,45,53,57,57,56,97,54,101,54,50,57,50,52,40,0,165,139,157,171,15,40,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,165,139,157,171,15,40,3,98,105,100,1,119,36,49,98,48,101,51,50,50,100,45,52,57,48,57,45,52,99,54,51,45,57,49,52,97,45,100,48,51,52,102,99,51,54,51,48,57,55,40,0,165,139,157,171,15,40,4,100,101,115,99,1,119,0,40,0,165,139,157,171,15,40,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,40,0,165,139,157,171,15,40,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,74,246,67,39,0,203,184,221,173,11,4,36,51,53,48,102,52,50,53,98,45,98,54,55,49,45,52,101,50,100,45,56,49,56,50,45,53,57,57,56,97,54,101,54,50,57,50,52,0,40,0,165,139,157,171,15,40,4,105,99,111,110,1,119,0,40,0,165,139,157,171,15,40,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,165,139,157,171,15,40,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,102,74,246,67,40,0,165,139,157,171,15,40,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,161,165,139,157,171,15,34,1,161,165,139,157,171,15,39,1,129,165,139,157,171,15,36,1,161,176,154,159,227,1,17,1,161,176,154,159,227,1,18,1,40,0,176,154,159,227,1,4,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,161,165,139,157,171,15,55,1,161,165,139,157,171,15,56,1,129,165,139,157,171,15,54,1,161,165,139,157,171,15,52,1,161,165,139,157,171,15,53,1,129,165,139,157,171,15,60,1,161,165,139,157,171,15,61,1,161,165,139,157,171,15,62,1,129,165,139,157,171,15,63,1,161,165,139,157,171,15,64,1,161,165,139,157,171,15,65,1,129,165,139,157,171,15,66,1,8,0,225,248,138,176,2,27,1,118,1,2,105,100,119,36,57,49,101,97,55,99,48,56,45,102,54,98,51,45,52,98,56,49,45,97,97,49,101,45,100,51,54,54,52,54,56,54,49,56,54,102,168,225,248,138,176,2,26,1,122,0,0,0,0,102,74,248,249,161,225,248,138,176,2,40,1,39,0,203,184,221,173,11,1,36,57,49,101,97,55,99,48,56,45,102,54,98,51,45,52,98,56,49,45,97,97,49,101,45,100,51,54,54,52,54,56,54,49,56,54,102,1,40,0,165,139,157,171,15,73,2,105,100,1,119,36,57,49,101,97,55,99,48,56,45,102,54,98,51,45,52,98,56,49,45,97,97,49,101,45,100,51,54,54,52,54,56,54,49,56,54,102,40,0,165,139,157,171,15,73,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,165,139,157,171,15,73,3,98,105,100,1,119,36,50,99,49,101,101,57,53,97,45,49,98,48,57,45,52,97,49,102,45,56,100,53,101,45,53,48,49,98,99,52,56,54,49,97,57,100,40,0,165,139,157,171,15,73,4,100,101,115,99,1,119,0,40,0,165,139,157,171,15,73,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,2,40,0,165,139,157,171,15,73,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,74,248,249,39,0,203,184,221,173,11,4,36,57,49,101,97,55,99,48,56,45,102,54,98,51,45,52,98,56,49,45,97,97,49,101,45,100,51,54,54,52,54,56,54,49,56,54,102,0,40,0,165,139,157,171,15,73,4,105,99,111,110,1,119,0,40,0,165,139,157,171,15,73,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,165,139,157,171,15,73,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,102,74,248,249,40,0,165,139,157,171,15,73,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,161,225,248,138,176,2,39,1,161,165,139,157,171,15,72,1,129,165,139,157,171,15,69,1,161,165,139,157,171,15,67,1,161,165,139,157,171,15,68,1,129,165,139,157,171,15,87,1,161,165,139,157,171,15,85,1,161,165,139,157,171,15,86,1,129,165,139,157,171,15,90,1,161,159,156,204,250,6,24,1,161,159,156,204,250,6,25,1,129,165,139,157,171,15,93,1,161,165,139,157,171,15,15,1,161,165,139,157,171,15,16,1,129,165,139,157,171,15,96,1,161,165,139,157,171,15,97,1,161,165,139,157,171,15,98,1,129,165,139,157,171,15,99,1,1,221,147,167,147,15,0,161,139,240,196,145,14,137,2,177,2,1,135,167,156,250,14,0,161,188,237,223,145,6,21,16,100,247,200,243,247,14,0,136,140,152,206,145,6,100,1,118,1,2,105,100,119,36,55,57,100,48,54,51,50,100,45,97,53,97,56,45,52,53,52,48,45,97,100,99,100,45,54,101,101,57,50,50,100,56,54,55,101,100,161,140,152,206,145,6,101,1,161,245,220,194,52,7,1,39,0,203,184,221,173,11,1,36,55,57,100,48,54,51,50,100,45,97,53,97,56,45,52,53,52,48,45,97,100,99,100,45,54,101,101,57,50,50,100,56,54,55,101,100,1,40,0,247,200,243,247,14,3,2,105,100,1,119,36,55,57,100,48,54,51,50,100,45,97,53,97,56,45,52,53,52,48,45,97,100,99,100,45,54,101,101,57,50,50,100,56,54,55,101,100,33,0,247,200,243,247,14,3,4,110,97,109,101,1,40,0,247,200,243,247,14,3,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,247,200,243,247,14,3,4,100,101,115,99,1,119,0,40,0,247,200,243,247,14,3,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,247,200,243,247,14,3,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,86,193,79,39,0,203,184,221,173,11,4,36,55,57,100,48,54,51,50,100,45,97,53,97,56,45,52,53,52,48,45,97,100,99,100,45,54,101,101,57,50,50,100,56,54,55,101,100,0,40,0,247,200,243,247,14,3,4,105,99,111,110,1,119,0,40,0,247,200,243,247,14,3,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,247,200,243,247,14,3,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,247,200,243,247,14,3,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,170,255,211,105,34,1,161,247,200,243,247,14,14,1,161,247,200,243,247,14,13,1,129,135,166,246,235,6,2,1,161,247,200,243,247,14,16,1,161,247,200,243,247,14,17,1,40,0,247,200,243,247,14,3,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,161,247,200,243,247,14,19,1,161,247,200,243,247,14,20,1,161,247,200,243,247,14,5,1,161,247,200,243,247,14,22,1,161,247,200,243,247,14,23,1,161,247,200,243,247,14,24,1,161,247,200,243,247,14,25,1,161,247,200,243,247,14,26,1,161,247,200,243,247,14,27,1,161,247,200,243,247,14,28,1,161,247,200,243,247,14,29,1,161,247,200,243,247,14,30,1,161,247,200,243,247,14,31,1,161,247,200,243,247,14,32,1,161,247,200,243,247,14,33,1,161,247,200,243,247,14,34,1,161,247,200,243,247,14,35,1,161,247,200,243,247,14,36,1,161,247,200,243,247,14,37,1,161,247,200,243,247,14,38,1,161,247,200,243,247,14,39,1,161,247,200,243,247,14,40,1,161,247,200,243,247,14,41,1,161,247,200,243,247,14,42,1,161,247,200,243,247,14,43,1,161,247,200,243,247,14,44,1,161,247,200,243,247,14,45,1,161,247,200,243,247,14,46,1,161,247,200,243,247,14,47,1,161,247,200,243,247,14,48,1,161,247,200,243,247,14,49,1,161,247,200,243,247,14,50,1,168,247,200,243,247,14,51,1,119,10,116,101,115,116,32,101,118,101,110,116,161,247,200,243,247,14,52,1,161,247,200,243,247,14,53,1,129,247,200,243,247,14,18,1,161,166,201,221,141,13,41,1,161,166,201,221,141,13,42,1,161,166,201,221,141,13,43,1,161,247,200,243,247,14,58,1,161,247,200,243,247,14,59,1,161,247,200,243,247,14,60,1,161,247,200,243,247,14,61,1,161,247,200,243,247,14,62,1,161,247,200,243,247,14,63,1,161,247,200,243,247,14,64,1,161,247,200,243,247,14,65,1,161,247,200,243,247,14,66,1,161,247,200,243,247,14,67,1,161,247,200,243,247,14,68,1,161,247,200,243,247,14,69,1,161,247,200,243,247,14,70,1,161,247,200,243,247,14,71,1,161,247,200,243,247,14,72,1,161,247,200,243,247,14,73,1,161,247,200,243,247,14,74,1,161,247,200,243,247,14,75,1,161,247,200,243,247,14,76,1,161,247,200,243,247,14,77,1,161,247,200,243,247,14,78,1,161,247,200,243,247,14,79,1,161,247,200,243,247,14,80,1,161,247,200,243,247,14,81,1,161,247,200,243,247,14,82,1,161,247,200,243,247,14,83,1,161,247,200,243,247,14,84,1,161,247,200,243,247,14,85,1,161,247,200,243,247,14,86,1,161,247,200,243,247,14,87,1,161,247,200,243,247,14,88,1,161,247,200,243,247,14,89,1,161,247,200,243,247,14,90,1,161,247,200,243,247,14,91,1,161,247,200,243,247,14,92,1,161,247,200,243,247,14,93,1,168,247,200,243,247,14,94,1,122,4,56,115,160,190,64,16,0,168,247,200,243,247,14,95,1,122,0,0,0,0,102,87,4,247,168,247,200,243,247,14,96,1,119,145,1,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,103,114,97,100,105,101,110,116,34,44,34,118,97,108,117,101,34,58,34,97,112,112,102,108,111,119,121,95,116,104,101,109,95,99,111,108,111,114,95,103,114,97,100,105,101,110,116,55,34,125,44,34,102,111,110,116,95,108,97,121,111,117,116,34,58,34,110,111,114,109,97,108,34,44,34,108,105,110,101,95,104,101,105,103,104,116,95,108,97,121,111,117,116,34,58,34,110,111,114,109,97,108,34,44,34,102,111,110,116,34,58,34,65,68,76,97,77,32,68,105,115,112,108,97,121,34,125,42,233,165,139,246,14,0,161,203,184,221,173,11,34,1,161,203,184,221,173,11,33,1,39,0,203,184,221,173,11,6,18,51,48,52,49,50,48,49,48,57,48,55,49,51,51,57,53,50,48,0,1,0,233,165,139,246,14,2,1,161,233,165,139,246,14,0,1,161,233,165,139,246,14,1,1,129,233,165,139,246,14,3,1,72,203,184,221,173,11,16,1,118,1,2,105,100,119,36,99,97,49,50,50,99,48,52,45,100,55,98,51,45,52,102,55,48,45,57,57,53,49,45,57,54,98,102,100,97,57,98,54,98,50,52,161,203,184,221,173,11,21,1,161,203,184,221,173,11,22,1,39,0,203,184,221,173,11,1,36,99,97,49,50,50,99,48,52,45,100,55,98,51,45,52,102,55,48,45,57,57,53,49,45,57,54,98,102,100,97,57,98,54,98,50,52,1,40,0,233,165,139,246,14,10,2,105,100,1,119,36,99,97,49,50,50,99,48,52,45,100,55,98,51,45,52,102,55,48,45,57,57,53,49,45,57,54,98,102,100,97,57,98,54,98,50,52,40,0,233,165,139,246,14,10,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,233,165,139,246,14,10,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,233,165,139,246,14,10,4,100,101,115,99,1,119,0,40,0,233,165,139,246,14,10,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,233,165,139,246,14,10,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,241,120,204,39,0,203,184,221,173,11,4,36,99,97,49,50,50,99,48,52,45,100,55,98,51,45,52,102,55,48,45,57,57,53,49,45,57,54,98,102,100,97,57,98,54,98,50,52,0,40,0,233,165,139,246,14,10,4,105,99,111,110,1,119,0,40,0,233,165,139,246,14,10,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,233,165,139,246,14,10,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,233,165,139,246,14,10,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,2,161,233,165,139,246,14,20,1,129,233,165,139,246,14,6,1,161,233,165,139,246,14,22,1,161,233,165,139,246,14,23,1,129,233,165,139,246,14,24,1,161,233,165,139,246,14,25,1,161,233,165,139,246,14,26,1,129,233,165,139,246,14,27,1,161,233,165,139,246,14,28,1,161,233,165,139,246,14,29,1,129,233,165,139,246,14,30,1,161,233,165,139,246,14,31,1,161,233,165,139,246,14,32,1,129,233,165,139,246,14,33,1,161,233,165,139,246,14,34,1,161,233,165,139,246,14,35,1,129,233,165,139,246,14,36,1,161,233,165,139,246,14,37,1,161,233,165,139,246,14,38,1,129,233,165,139,246,14,39,1,3,145,159,164,217,14,0,161,135,232,133,203,9,12,1,161,135,232,133,203,9,13,1,129,135,232,133,203,9,14,1,12,154,243,157,196,14,0,161,145,159,164,217,14,0,1,161,145,159,164,217,14,1,1,129,145,159,164,217,14,2,1,161,154,243,157,196,14,0,1,161,154,243,157,196,14,1,1,129,154,243,157,196,14,2,1,161,154,243,157,196,14,3,1,161,154,243,157,196,14,4,1,129,154,243,157,196,14,5,1,161,154,243,157,196,14,6,1,161,154,243,157,196,14,7,1,129,154,243,157,196,14,8,1,2,149,161,132,184,14,0,161,235,178,165,206,5,68,219,2,161,149,161,132,184,14,218,2,2,1,173,187,245,170,14,0,161,164,203,250,235,13,6,46,3,252,218,241,167,14,0,161,251,189,220,155,14,0,1,161,251,189,220,155,14,1,1,168,251,189,220,155,14,2,1,119,9,231,186,170,229,191,181,231,137,136,3,251,189,220,155,14,0,161,210,228,153,221,12,0,1,161,210,228,153,221,12,1,1,161,210,228,153,221,12,2,1,17,201,191,159,147,14,0,161,149,189,189,215,8,0,1,161,149,189,189,215,8,1,1,129,149,189,189,215,8,2,1,161,213,161,242,209,13,31,1,161,133,159,138,205,12,124,1,161,133,159,138,205,12,125,1,129,201,191,159,147,14,2,1,161,201,191,159,147,14,4,1,161,201,191,159,147,14,5,1,129,201,191,159,147,14,6,1,161,201,191,159,147,14,0,1,161,201,191,159,147,14,1,1,129,201,191,159,147,14,9,1,161,201,191,159,147,14,3,1,161,201,191,159,147,14,10,1,161,201,191,159,147,14,11,1,129,201,191,159,147,14,12,1,1,139,240,196,145,14,0,161,200,203,236,184,2,34,138,2,1,164,203,250,235,13,0,33,1,4,109,101,116,97,12,108,97,115,116,95,115,121,110,99,95,97,116,7,7,180,230,210,212,13,0,161,175,225,172,150,8,8,1,161,175,225,172,150,8,9,1,136,175,225,172,150,8,10,1,118,2,2,105,100,119,36,100,48,52,57,54,51,50,52,45,53,53,55,48,45,52,48,48,54,45,98,52,101,97,45,100,98,55,53,49,54,100,50,49,50,102,100,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,41,200,235,161,175,225,172,150,8,7,1,161,175,225,172,150,8,4,1,161,175,225,172,150,8,5,1,129,180,230,210,212,13,2,1,34,213,161,242,209,13,0,161,133,159,138,205,12,128,1,1,161,133,159,138,205,12,129,1,1,129,133,159,138,205,12,130,1,1,136,133,159,138,205,12,108,1,118,1,2,105,100,119,36,55,101,98,54,57,55,99,100,45,54,97,53,53,45,52,48,98,98,45,57,54,97,99,45,48,100,52,97,51,98,99,57,50,52,98,50,161,133,159,138,205,12,109,1,161,213,161,242,209,13,1,1,39,0,203,184,221,173,11,1,36,55,101,98,54,57,55,99,100,45,54,97,53,53,45,52,48,98,98,45,57,54,97,99,45,48,100,52,97,51,98,99,57,50,52,98,50,1,40,0,213,161,242,209,13,6,2,105,100,1,119,36,55,101,98,54,57,55,99,100,45,54,97,53,53,45,52,48,98,98,45,57,54,97,99,45,48,100,52,97,51,98,99,57,50,52,98,50,33,0,213,161,242,209,13,6,4,110,97,109,101,1,40,0,213,161,242,209,13,6,3,98,105,100,1,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,40,0,213,161,242,209,13,6,4,100,101,115,99,1,119,0,40,0,213,161,242,209,13,6,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,40,0,213,161,242,209,13,6,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,48,178,5,39,0,203,184,221,173,11,4,36,55,101,98,54,57,55,99,100,45,54,97,53,53,45,52,48,98,98,45,57,54,97,99,45,48,100,52,97,51,98,99,57,50,52,98,50,0,40,0,213,161,242,209,13,6,4,105,99,111,110,1,119,0,40,0,213,161,242,209,13,6,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,213,161,242,209,13,6,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,213,161,242,209,13,6,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,2,161,213,161,242,209,13,16,1,161,213,161,242,209,13,8,1,161,213,161,242,209,13,18,1,161,213,161,242,209,13,19,1,168,213,161,242,209,13,20,1,119,4,71,114,105,100,168,213,161,242,209,13,21,1,122,4,56,115,160,190,64,16,0,168,213,161,242,209,13,22,1,122,0,0,0,0,102,48,178,16,136,152,158,185,230,10,6,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,48,178,16,2,105,100,119,36,55,101,98,54,57,55,99,100,45,54,97,53,53,45,52,48,98,98,45,57,54,97,99,45,48,100,52,97,51,98,99,57,50,52,98,50,161,133,159,138,205,12,127,1,161,133,159,138,205,12,53,1,161,133,159,138,205,12,58,1,129,213,161,242,209,13,2,1,161,213,161,242,209,13,27,1,161,213,161,242,209,13,0,1,161,213,161,242,209,13,5,1,129,213,161,242,209,13,30,1,64,173,252,148,184,13,0,161,156,148,170,169,10,12,1,161,156,148,170,169,10,9,1,161,156,148,170,169,10,10,1,129,156,148,170,169,10,15,1,161,173,252,148,184,13,0,1,161,164,155,139,169,7,0,1,161,164,155,139,169,7,1,1,129,164,155,139,169,7,34,1,161,173,252,148,184,13,4,1,161,161,178,132,150,11,58,1,161,161,178,132,150,11,59,1,129,173,252,148,184,13,7,1,161,173,252,148,184,13,8,1,161,164,155,139,169,7,32,1,161,164,155,139,169,7,33,1,129,173,252,148,184,13,11,1,161,173,252,148,184,13,12,1,161,164,155,139,169,7,8,1,161,164,155,139,169,7,9,1,129,173,252,148,184,13,15,1,161,173,252,148,184,13,16,1,161,173,252,148,184,13,13,1,161,173,252,148,184,13,14,1,129,173,252,148,184,13,19,1,161,173,252,148,184,13,20,1,161,173,252,148,184,13,9,1,161,173,252,148,184,13,10,1,129,173,252,148,184,13,23,1,161,173,252,148,184,13,24,1,161,173,252,148,184,13,21,1,161,173,252,148,184,13,22,1,129,173,252,148,184,13,27,1,161,173,252,148,184,13,28,1,161,164,155,139,169,7,28,1,161,164,155,139,169,7,29,1,129,173,252,148,184,13,31,1,161,173,252,148,184,13,32,1,161,173,252,148,184,13,29,1,161,173,252,148,184,13,30,1,129,173,252,148,184,13,35,1,136,207,228,238,162,8,22,1,118,1,2,105,100,119,36,100,100,98,57,51,98,97,55,45,48,54,99,55,45,52,49,55,54,45,57,56,50,97,45,100,55,52,50,51,101,48,57,98,52,52,49,161,173,252,148,184,13,33,1,161,173,252,148,184,13,34,1,168,130,180,254,251,6,6,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,161,173,252,148,184,13,36,1,161,173,252,148,184,13,41,1,161,173,252,148,184,13,42,1,129,173,252,148,184,13,39,1,161,173,252,148,184,13,44,1,161,173,252,148,184,13,37,1,161,173,252,148,184,13,38,1,129,173,252,148,184,13,47,1,161,173,252,148,184,13,48,1,161,173,252,148,184,13,25,1,161,173,252,148,184,13,26,1,129,173,252,148,184,13,51,1,161,173,252,148,184,13,52,1,161,173,252,148,184,13,49,1,161,173,252,148,184,13,50,1,129,173,252,148,184,13,55,1,161,173,252,148,184,13,56,1,161,173,252,148,184,13,5,1,161,173,252,148,184,13,6,1,129,173,252,148,184,13,59,1,30,243,239,182,181,13,0,136,240,149,229,225,6,0,1,118,1,2,105,100,119,36,53,54,54,56,57,101,52,50,45,49,102,101,56,45,52,97,97,102,45,56,50,99,53,45,99,51,100,99,98,102,99,51,98,50,53,52,161,240,149,229,225,6,1,1,161,240,149,229,225,6,2,1,39,0,203,184,221,173,11,1,36,53,54,54,56,57,101,52,50,45,49,102,101,56,45,52,97,97,102,45,56,50,99,53,45,99,51,100,99,98,102,99,51,98,50,53,52,1,40,0,243,239,182,181,13,3,2,105,100,1,119,36,53,54,54,56,57,101,52,50,45,49,102,101,56,45,52,97,97,102,45,56,50,99,53,45,99,51,100,99,98,102,99,51,98,50,53,52,40,0,243,239,182,181,13,3,4,110,97,109,101,1,119,0,40,0,243,239,182,181,13,3,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,243,239,182,181,13,3,4,100,101,115,99,1,119,0,40,0,243,239,182,181,13,3,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,243,239,182,181,13,3,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,241,141,103,39,0,203,184,221,173,11,4,36,53,54,54,56,57,101,52,50,45,49,102,101,56,45,52,97,97,102,45,56,50,99,53,45,99,51,100,99,98,102,99,51,98,50,53,52,0,40,0,243,239,182,181,13,3,4,105,99,111,110,1,119,0,40,0,243,239,182,181,13,3,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,243,239,182,181,13,3,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,101,241,141,103,40,0,243,239,182,181,13,3,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,136,243,239,182,181,13,0,1,118,1,2,105,100,119,36,51,53,100,51,57,57,98,57,45,49,57,55,101,45,52,57,99,54,45,97,98,102,56,45,101,51,57,51,49,101,48,97,55,51,49,51,161,243,239,182,181,13,1,1,161,243,239,182,181,13,2,1,39,0,203,184,221,173,11,1,36,51,53,100,51,57,57,98,57,45,49,57,55,101,45,52,57,99,54,45,97,98,102,56,45,101,51,57,51,49,101,48,97,55,51,49,51,1,40,0,243,239,182,181,13,18,2,105,100,1,119,36,51,53,100,51,57,57,98,57,45,49,57,55,101,45,52,57,99,54,45,97,98,102,56,45,101,51,57,51,49,101,48,97,55,51,49,51,40,0,243,239,182,181,13,18,4,110,97,109,101,1,119,0,40,0,243,239,182,181,13,18,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,243,239,182,181,13,18,4,100,101,115,99,1,119,0,40,0,243,239,182,181,13,18,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,243,239,182,181,13,18,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,241,141,156,39,0,203,184,221,173,11,4,36,51,53,100,51,57,57,98,57,45,49,57,55,101,45,52,57,99,54,45,97,98,102,56,45,101,51,57,51,49,101,48,97,55,51,49,51,0,40,0,243,239,182,181,13,18,4,105,99,111,110,1,119,0,40,0,243,239,182,181,13,18,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,243,239,182,181,13,18,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,101,241,141,156,40,0,243,239,182,181,13,18,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,1,161,239,241,154,13,0,161,158,184,218,165,3,37,106,72,166,201,221,141,13,0,161,182,172,247,194,5,0,1,161,182,172,247,194,5,1,1,129,182,172,247,194,5,2,1,161,170,255,211,105,34,1,161,245,220,194,52,9,1,161,245,220,194,52,10,1,136,166,201,221,141,13,2,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,85,132,208,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,161,166,201,221,141,13,4,1,161,166,201,221,141,13,5,1,136,166,201,221,141,13,6,1,118,2,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,85,132,209,161,166,201,221,141,13,7,1,161,166,201,221,141,13,8,1,136,166,201,221,141,13,9,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,85,134,151,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,161,166,201,221,141,13,10,1,161,166,201,221,141,13,11,1,136,166,201,221,141,13,12,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,85,134,152,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,39,0,203,184,221,173,11,1,36,98,98,101,55,102,100,54,99,45,99,99,56,102,45,53,48,55,57,45,98,48,52,53,45,54,49,57,55,52,99,48,57,57,98,54,100,1,40,0,166,201,221,141,13,16,2,105,100,1,119,36,98,98,101,55,102,100,54,99,45,99,99,56,102,45,53,48,55,57,45,98,48,52,53,45,54,49,57,55,52,99,48,57,57,98,54,100,40,0,166,201,221,141,13,16,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,166,201,221,141,13,16,3,98,105,100,1,119,36,98,98,101,55,102,100,54,99,45,99,99,56,102,45,53,48,55,57,45,98,48,52,53,45,54,49,57,55,52,99,48,57,57,98,54,100,40,0,166,201,221,141,13,16,4,100,101,115,99,1,119,0,40,0,166,201,221,141,13,16,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,166,201,221,141,13,16,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,85,140,82,39,0,203,184,221,173,11,4,36,98,98,101,55,102,100,54,99,45,99,99,56,102,45,53,48,55,57,45,98,48,52,53,45,54,49,57,55,52,99,48,57,57,98,54,100,0,40,0,166,201,221,141,13,16,4,105,99,111,110,1,119,0,40,0,166,201,221,141,13,16,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,166,201,221,141,13,16,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,166,201,221,141,13,16,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,168,166,201,221,141,13,27,1,122,4,56,115,160,190,64,16,0,168,166,201,221,141,13,26,1,122,0,0,0,0,102,85,140,82,40,0,166,201,221,141,13,16,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,161,166,201,221,141,13,0,1,161,166,201,221,141,13,1,1,136,166,201,221,141,13,15,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,85,167,96,2,105,100,119,36,48,101,55,99,100,101,102,50,45,49,48,99,50,45,52,52,101,99,45,56,98,54,49,45,49,97,100,101,48,98,102,53,100,51,102,102,161,166,201,221,141,13,3,1,161,166,201,221,141,13,31,1,161,166,201,221,141,13,32,1,136,166,201,221,141,13,33,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,85,167,97,2,105,100,119,36,48,101,55,99,100,101,102,50,45,49,48,99,50,45,52,52,101,99,45,56,98,54,49,45,49,97,100,101,48,98,102,53,100,51,102,102,161,166,201,221,141,13,35,1,161,166,201,221,141,13,36,1,161,245,220,194,52,38,1,161,166,201,221,141,13,38,1,161,166,201,221,141,13,39,1,161,166,201,221,141,13,40,1,136,140,152,206,145,6,100,1,118,1,2,105,100,119,36,50,97,54,101,53,101,50,49,45,97,57,51,56,45,52,53,97,53,45,97,52,52,53,45,100,48,98,55,49,52,57,53,98,48,55,55,161,140,152,206,145,6,101,1,161,245,220,194,52,7,1,39,0,203,184,221,173,11,1,36,50,97,54,101,53,101,50,49,45,97,57,51,56,45,52,53,97,53,45,97,52,52,53,45,100,48,98,55,49,52,57,53,98,48,55,55,1,40,0,166,201,221,141,13,47,2,105,100,1,119,36,50,97,54,101,53,101,50,49,45,97,57,51,56,45,52,53,97,53,45,97,52,52,53,45,100,48,98,55,49,52,57,53,98,48,55,55,40,0,166,201,221,141,13,47,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,166,201,221,141,13,47,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,166,201,221,141,13,47,4,100,101,115,99,1,119,0,40,0,166,201,221,141,13,47,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,166,201,221,141,13,47,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,86,193,40,39,0,203,184,221,173,11,4,36,50,97,54,101,53,101,50,49,45,97,57,51,56,45,52,53,97,53,45,97,52,52,53,45,100,48,98,55,49,52,57,53,98,48,55,55,0,40,0,166,201,221,141,13,47,4,105,99,111,110,1,119,0,40,0,166,201,221,141,13,47,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,166,201,221,141,13,47,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,166,201,221,141,13,47,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,166,201,221,141,13,34,1,161,166,201,221,141,13,58,1,161,166,201,221,141,13,57,1,129,166,201,221,141,13,37,1,161,166,201,221,141,13,60,1,161,166,201,221,141,13,61,1,129,166,201,221,141,13,62,1,161,166,201,221,141,13,63,1,161,166,201,221,141,13,64,1,40,0,166,201,221,141,13,47,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,161,166,201,221,141,13,66,1,161,166,201,221,141,13,67,1,129,166,201,221,141,13,65,1,2,180,205,189,133,13,0,161,200,142,208,241,4,152,1,16,161,180,205,189,133,13,15,4,1,248,210,237,129,13,0,161,223,209,193,147,11,80,2,7,211,202,217,232,12,0,161,141,245,194,142,11,4,1,161,141,245,194,142,11,5,1,129,141,245,194,142,11,6,1,161,141,245,194,142,11,3,1,161,141,245,194,142,11,0,1,161,141,245,194,142,11,1,1,129,211,202,217,232,12,2,1,3,210,228,153,221,12,0,161,202,160,246,212,1,3,1,161,202,160,246,212,1,4,1,161,202,160,246,212,1,5,1,2,234,156,130,211,12,0,161,219,220,239,171,8,9,11,168,234,156,130,211,12,10,1,122,0,0,0,0,102,97,116,231,1,181,175,219,209,12,0,161,200,159,185,206,9,7,10,131,1,133,159,138,205,12,0,161,255,140,248,220,6,0,1,161,255,140,248,220,6,1,1,129,255,140,248,220,6,2,1,161,180,230,210,212,13,3,1,161,161,178,132,150,11,34,1,161,161,178,132,150,11,35,1,129,133,159,138,205,12,2,1,8,0,229,154,128,197,12,16,1,118,1,2,105,100,119,36,98,54,51,52,55,97,99,98,45,51,49,55,52,45,52,102,48,101,45,57,56,101,57,45,100,99,99,101,48,55,101,53,100,98,102,55,168,229,154,128,197,12,15,1,122,0,0,0,0,102,48,108,125,161,180,230,210,212,13,1,1,39,0,203,184,221,173,11,1,36,98,54,51,52,55,97,99,98,45,51,49,55,52,45,52,102,48,101,45,57,56,101,57,45,100,99,99,101,48,55,101,53,100,98,102,55,1,40,0,133,159,138,205,12,10,2,105,100,1,119,36,98,54,51,52,55,97,99,98,45,51,49,55,52,45,52,102,48,101,45,57,56,101,57,45,100,99,99,101,48,55,101,53,100,98,102,55,40,0,133,159,138,205,12,10,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,133,159,138,205,12,10,3,98,105,100,1,119,36,100,48,52,57,54,51,50,52,45,53,53,55,48,45,52,48,48,54,45,98,52,101,97,45,100,98,55,53,49,54,100,50,49,50,102,100,40,0,133,159,138,205,12,10,4,100,101,115,99,1,119,0,40,0,133,159,138,205,12,10,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,40,0,133,159,138,205,12,10,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,48,108,125,39,0,203,184,221,173,11,4,36,98,54,51,52,55,97,99,98,45,51,49,55,52,45,52,102,48,101,45,57,56,101,57,45,100,99,99,101,48,55,101,53,100,98,102,55,0,40,0,133,159,138,205,12,10,4,105,99,111,110,1,119,0,40,0,133,159,138,205,12,10,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,133,159,138,205,12,10,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,133,159,138,205,12,10,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,133,159,138,205,12,3,1,161,133,159,138,205,12,21,1,161,133,159,138,205,12,20,1,129,133,159,138,205,12,6,1,161,133,159,138,205,12,23,1,161,133,159,138,205,12,24,1,129,133,159,138,205,12,25,1,72,229,154,128,197,12,6,1,118,1,2,105,100,119,36,102,51,53,50,55,48,99,55,45,99,54,54,99,45,52,54,99,101,45,56,101,49,97,45,51,102,54,51,57,102,55,98,48,48,48,100,168,229,154,128,197,12,7,1,122,0,0,0,0,102,48,108,128,168,229,154,128,197,12,8,1,122,0,0,0,0,102,48,108,128,39,0,203,184,221,173,11,1,36,102,51,53,50,55,48,99,55,45,99,54,54,99,45,52,54,99,101,45,56,101,49,97,45,51,102,54,51,57,102,55,98,48,48,48,100,1,40,0,133,159,138,205,12,32,2,105,100,1,119,36,102,51,53,50,55,48,99,55,45,99,54,54,99,45,52,54,99,101,45,56,101,49,97,45,51,102,54,51,57,102,55,98,48,48,48,100,40,0,133,159,138,205,12,32,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,133,159,138,205,12,32,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,133,159,138,205,12,32,4,100,101,115,99,1,119,0,40,0,133,159,138,205,12,32,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,133,159,138,205,12,32,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,48,108,128,39,0,203,184,221,173,11,4,36,102,51,53,50,55,48,99,55,45,99,54,54,99,45,52,54,99,101,45,56,101,49,97,45,51,102,54,51,57,102,55,98,48,48,48,100,0,40,0,133,159,138,205,12,32,4,105,99,111,110,1,119,0,40,0,133,159,138,205,12,32,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,133,159,138,205,12,32,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,133,159,138,205,12,32,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,133,159,138,205,12,22,1,161,133,159,138,205,12,43,1,161,133,159,138,205,12,42,1,129,133,159,138,205,12,28,1,161,133,159,138,205,12,44,1,161,133,159,138,205,12,26,1,161,133,159,138,205,12,27,1,129,133,159,138,205,12,47,1,161,133,159,138,205,12,48,1,161,133,159,138,205,12,0,1,161,133,159,138,205,12,1,1,129,133,159,138,205,12,51,1,136,173,252,148,184,13,40,1,118,1,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,161,207,228,238,162,8,23,1,161,133,159,138,205,12,54,1,39,0,203,184,221,173,11,1,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,1,40,0,133,159,138,205,12,59,2,105,100,1,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,33,0,133,159,138,205,12,59,4,110,97,109,101,1,40,0,133,159,138,205,12,59,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,133,159,138,205,12,59,4,100,101,115,99,1,119,0,40,0,133,159,138,205,12,59,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,33,0,133,159,138,205,12,59,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,0,33,0,133,159,138,205,12,59,4,105,99,111,110,1,40,0,133,159,138,205,12,59,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,133,159,138,205,12,59,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,133,159,138,205,12,59,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,133,159,138,205,12,52,1,161,133,159,138,205,12,70,1,161,133,159,138,205,12,69,1,129,133,159,138,205,12,55,1,161,133,159,138,205,12,72,1,161,133,159,138,205,12,73,1,129,133,159,138,205,12,74,1,161,133,159,138,205,12,75,1,161,133,159,138,205,12,76,1,161,133,159,138,205,12,61,1,161,133,159,138,205,12,78,1,161,133,159,138,205,12,79,1,161,133,159,138,205,12,80,1,161,201,129,238,197,4,27,1,161,201,129,238,197,4,28,1,168,133,159,138,205,12,67,1,119,23,123,34,116,121,34,58,48,44,34,118,97,108,117,101,34,58,34,240,159,141,182,34,125,161,133,159,138,205,12,84,1,161,133,159,138,205,12,85,1,161,133,159,138,205,12,83,1,161,133,159,138,205,12,87,1,161,133,159,138,205,12,88,1,161,133,159,138,205,12,89,1,8,0,133,159,138,205,12,66,1,118,1,2,105,100,119,36,101,57,55,56,55,55,102,53,45,99,51,54,53,45,52,48,50,53,45,57,101,54,97,45,101,53,57,48,99,52,98,49,57,100,98,98,161,133,159,138,205,12,65,1,161,133,159,138,205,12,91,1,39,0,203,184,221,173,11,1,36,101,57,55,56,55,55,102,53,45,99,51,54,53,45,52,48,50,53,45,57,101,54,97,45,101,53,57,48,99,52,98,49,57,100,98,98,1,40,0,133,159,138,205,12,96,2,105,100,1,119,36,101,57,55,56,55,55,102,53,45,99,51,54,53,45,52,48,50,53,45,57,101,54,97,45,101,53,57,48,99,52,98,49,57,100,98,98,40,0,133,159,138,205,12,96,4,110,97,109,101,1,119,5,66,111,97,114,100,40,0,133,159,138,205,12,96,3,98,105,100,1,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,40,0,133,159,138,205,12,96,4,100,101,115,99,1,119,0,40,0,133,159,138,205,12,96,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,2,40,0,133,159,138,205,12,96,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,48,177,159,39,0,203,184,221,173,11,4,36,101,57,55,56,55,55,102,53,45,99,51,54,53,45,52,48,50,53,45,57,101,54,97,45,101,53,57,48,99,52,98,49,57,100,98,98,0,40,0,133,159,138,205,12,96,4,105,99,111,110,1,119,0,40,0,133,159,138,205,12,96,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,133,159,138,205,12,96,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,133,159,138,205,12,96,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,136,133,159,138,205,12,93,1,118,1,2,105,100,119,36,102,48,99,53,57,57,50,49,45,48,52,101,101,45,52,57,55,49,45,57,57,53,99,45,55,57,98,55,102,100,56,99,48,48,101,50,161,133,159,138,205,12,94,1,161,133,159,138,205,12,95,1,39,0,203,184,221,173,11,1,36,102,48,99,53,57,57,50,49,45,48,52,101,101,45,52,57,55,49,45,57,57,53,99,45,55,57,98,55,102,100,56,99,48,48,101,50,1,40,0,133,159,138,205,12,111,2,105,100,1,119,36,102,48,99,53,57,57,50,49,45,48,52,101,101,45,52,57,55,49,45,57,57,53,99,45,55,57,98,55,102,100,56,99,48,48,101,50,40,0,133,159,138,205,12,111,4,110,97,109,101,1,119,8,67,97,108,101,110,100,97,114,40,0,133,159,138,205,12,111,3,98,105,100,1,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,40,0,133,159,138,205,12,111,4,100,101,115,99,1,119,0,40,0,133,159,138,205,12,111,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,3,40,0,133,159,138,205,12,111,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,48,177,162,39,0,203,184,221,173,11,4,36,102,48,99,53,57,57,50,49,45,48,52,101,101,45,52,57,55,49,45,57,57,53,99,45,55,57,98,55,102,100,56,99,48,48,101,50,0,40,0,133,159,138,205,12,111,4,105,99,111,110,1,119,0,40,0,133,159,138,205,12,111,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,133,159,138,205,12,111,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,133,159,138,205,12,111,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,133,159,138,205,12,71,1,161,133,159,138,205,12,4,1,161,133,159,138,205,12,5,1,129,201,129,238,197,4,29,1,161,133,159,138,205,12,123,1,161,133,159,138,205,12,90,1,161,133,159,138,205,12,110,1,129,133,159,138,205,12,126,1,23,229,154,128,197,12,0,161,248,153,216,10,0,1,161,248,153,216,10,1,1,129,248,153,216,10,2,1,161,229,154,128,197,12,0,1,161,229,154,128,197,12,1,1,129,229,154,128,197,12,2,1,72,158,156,181,152,10,6,1,118,1,2,105,100,119,36,100,48,52,57,54,51,50,52,45,53,53,55,48,45,52,48,48,54,45,98,52,101,97,45,100,98,55,53,49,54,100,50,49,50,102,100,161,176,154,159,227,1,2,1,161,176,154,159,227,1,3,1,39,0,203,184,221,173,11,1,36,100,48,52,57,54,51,50,52,45,53,53,55,48,45,52,48,48,54,45,98,52,101,97,45,100,98,55,53,49,54,100,50,49,50,102,100,1,40,0,229,154,128,197,12,9,2,105,100,1,119,36,100,48,52,57,54,51,50,52,45,53,53,55,48,45,52,48,48,54,45,98,52,101,97,45,100,98,55,53,49,54,100,50,49,50,102,100,40,0,229,154,128,197,12,9,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,229,154,128,197,12,9,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,229,154,128,197,12,9,4,100,101,115,99,1,119,0,40,0,229,154,128,197,12,9,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,33,0,229,154,128,197,12,9,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,100,48,52,57,54,51,50,52,45,53,53,55,48,45,52,48,48,54,45,98,52,101,97,45,100,98,55,53,49,54,100,50,49,50,102,100,0,40,0,229,154,128,197,12,9,4,105,99,111,110,1,119,0,40,0,229,154,128,197,12,9,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,229,154,128,197,12,9,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,229,154,128,197,12,9,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,2,161,229,154,128,197,12,19,1,129,229,154,128,197,12,5,1,16,149,129,169,191,12,0,161,186,197,166,179,15,3,1,161,188,171,136,250,8,0,1,161,188,171,136,250,8,1,1,129,188,171,136,250,8,2,1,161,149,129,169,191,12,0,1,161,200,205,214,172,10,27,1,161,200,205,214,172,10,28,1,129,149,129,169,191,12,3,1,161,149,129,169,191,12,4,1,161,149,129,169,191,12,1,1,161,149,129,169,191,12,2,1,129,149,129,169,191,12,7,1,161,149,129,169,191,12,8,1,161,186,197,166,179,15,0,1,161,186,197,166,179,15,1,1,129,149,129,169,191,12,11,1,10,177,161,136,243,11,0,161,241,155,213,233,1,49,1,161,241,155,213,233,1,50,1,129,214,139,213,136,8,65,1,161,214,139,213,136,8,63,1,161,214,139,213,136,8,64,1,129,177,161,136,243,11,2,1,161,241,155,213,233,1,21,1,161,177,161,136,243,11,3,1,161,177,161,136,243,11,4,1,129,177,161,136,243,11,5,1,1,205,149,231,236,11,0,161,175,147,217,214,1,32,68,3,162,159,252,196,11,0,161,233,247,183,159,1,1,1,161,233,247,183,159,1,2,1,129,233,247,183,159,1,3,1,37,203,184,221,173,11,0,39,1,4,100,97,116,97,6,102,111,108,100,101,114,1,39,0,203,184,221,173,11,0,5,118,105,101,119,115,1,39,0,203,184,221,173,11,0,7,115,101,99,116,105,111,110,1,39,0,203,184,221,173,11,0,4,109,101,116,97,1,39,0,203,184,221,173,11,0,8,114,101,108,97,116,105,111,110,1,39,0,203,184,221,173,11,2,8,102,97,118,111,114,105,116,101,1,39,0,203,184,221,173,11,2,6,114,101,99,101,110,116,1,39,0,203,184,221,173,11,2,5,116,114,97,115,104,1,39,0,203,184,221,173,11,1,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,1,40,0,203,184,221,173,11,8,2,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,203,184,221,173,11,8,4,110,97,109,101,1,119,9,87,111,114,107,115,112,97,99,101,40,0,203,184,221,173,11,8,3,98,105,100,1,119,0,40,0,203,184,221,173,11,8,4,100,101,115,99,1,119,0,40,0,203,184,221,173,11,8,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,33,0,203,184,221,173,11,8,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,0,8,0,203,184,221,173,11,15,1,118,1,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,203,184,221,173,11,8,4,105,99,111,110,1,119,0,40,0,203,184,221,173,11,8,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,203,184,221,173,11,8,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,40,0,203,184,221,173,11,8,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,161,203,184,221,173,11,14,1,161,203,184,221,173,11,19,1,39,0,203,184,221,173,11,1,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,1,40,0,203,184,221,173,11,23,2,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,203,184,221,173,11,23,4,110,97,109,101,1,119,15,71,101,116,116,105,110,103,32,115,116,97,114,116,101,100,40,0,203,184,221,173,11,23,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,203,184,221,173,11,23,4,100,101,115,99,1,119,0,40,0,203,184,221,173,11,23,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,33,0,203,184,221,173,11,23,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,0,40,0,203,184,221,173,11,23,4,105,99,111,110,1,119,25,123,34,116,121,34,58,48,44,34,118,97,108,117,101,34,58,34,226,173,144,239,184,143,34,125,40,0,203,184,221,173,11,23,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,203,184,221,173,11,23,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,203,184,221,173,11,23,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,40,0,203,184,221,173,11,3,17,99,117,114,114,101,110,116,95,119,111,114,107,115,112,97,99,101,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,33,0,203,184,221,173,11,3,12,99,117,114,114,101,110,116,95,118,105,101,119,1,3,155,165,205,152,11,0,161,179,252,154,44,0,1,161,179,252,154,44,1,1,129,179,252,154,44,2,1,101,161,178,132,150,11,0,161,167,131,133,162,9,8,1,161,167,131,133,162,9,9,1,129,167,131,133,162,9,10,1,161,167,131,133,162,9,7,1,161,252,218,241,167,14,0,1,161,252,218,241,167,14,1,1,129,161,178,132,150,11,2,1,161,161,178,132,150,11,3,1,161,161,178,132,150,11,0,1,161,161,178,132,150,11,1,1,129,161,178,132,150,11,6,1,161,161,178,132,150,11,7,1,161,130,180,254,251,6,15,1,161,130,180,254,251,6,16,1,129,161,178,132,150,11,10,1,8,0,130,180,254,251,6,10,1,118,1,2,105,100,119,36,52,56,99,53,50,99,102,55,45,98,102,57,56,45,52,51,102,97,45,57,54,97,100,45,98,51,49,97,97,100,101,57,98,48,55,49,168,130,180,254,251,6,9,1,122,0,0,0,0,102,32,220,196,161,161,178,132,150,11,13,1,39,0,203,184,221,173,11,1,36,52,56,99,53,50,99,102,55,45,98,102,57,56,45,52,51,102,97,45,57,54,97,100,45,98,51,49,97,97,100,101,57,98,48,55,49,1,40,0,161,178,132,150,11,18,2,105,100,1,119,36,52,56,99,53,50,99,102,55,45,98,102,57,56,45,52,51,102,97,45,57,54,97,100,45,98,51,49,97,97,100,101,57,98,48,55,49,40,0,161,178,132,150,11,18,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,161,178,132,150,11,18,3,98,105,100,1,119,36,100,100,98,57,51,98,97,55,45,48,54,99,55,45,52,49,55,54,45,57,56,50,97,45,100,55,52,50,51,101,48,57,98,52,52,49,40,0,161,178,132,150,11,18,4,100,101,115,99,1,119,0,40,0,161,178,132,150,11,18,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,40,0,161,178,132,150,11,18,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,32,220,196,39,0,203,184,221,173,11,4,36,52,56,99,53,50,99,102,55,45,98,102,57,56,45,52,51,102,97,45,57,54,97,100,45,98,51,49,97,97,100,101,57,98,48,55,49,0,40,0,161,178,132,150,11,18,4,105,99,111,110,1,119,0,40,0,161,178,132,150,11,18,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,161,178,132,150,11,18,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,161,178,132,150,11,18,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,161,178,132,150,11,11,1,161,161,178,132,150,11,29,1,161,161,178,132,150,11,28,1,129,161,178,132,150,11,14,1,161,161,178,132,150,11,31,1,161,161,178,132,150,11,32,1,129,161,178,132,150,11,33,1,161,161,178,132,150,11,30,1,161,161,178,132,150,11,8,1,161,161,178,132,150,11,9,1,129,161,178,132,150,11,36,1,161,161,178,132,150,11,37,1,161,167,131,133,162,9,4,1,161,167,131,133,162,9,5,1,129,161,178,132,150,11,40,1,161,161,178,132,150,11,41,1,161,161,178,132,150,11,38,1,161,161,178,132,150,11,39,1,129,161,178,132,150,11,44,1,161,161,178,132,150,11,45,1,161,161,178,132,150,11,42,1,161,161,178,132,150,11,43,1,129,161,178,132,150,11,48,1,161,161,178,132,150,11,49,1,161,161,178,132,150,11,46,1,161,161,178,132,150,11,47,1,129,161,178,132,150,11,52,1,161,161,178,132,150,11,53,1,161,161,178,132,150,11,4,1,161,161,178,132,150,11,5,1,129,161,178,132,150,11,56,1,161,161,178,132,150,11,57,1,161,161,178,132,150,11,54,1,161,161,178,132,150,11,55,1,129,161,178,132,150,11,60,1,161,161,178,132,150,11,61,1,161,161,178,132,150,11,50,1,161,161,178,132,150,11,51,1,129,161,178,132,150,11,64,1,161,161,178,132,150,11,65,1,161,161,178,132,150,11,62,1,161,161,178,132,150,11,63,1,129,161,178,132,150,11,68,1,161,161,178,132,150,11,69,1,161,161,178,132,150,11,66,1,161,161,178,132,150,11,67,1,129,161,178,132,150,11,72,1,161,161,178,132,150,11,73,1,161,161,178,132,150,11,70,1,161,161,178,132,150,11,71,1,129,161,178,132,150,11,76,1,161,161,178,132,150,11,77,1,161,161,178,132,150,11,74,1,161,161,178,132,150,11,75,1,129,161,178,132,150,11,80,1,161,161,178,132,150,11,81,1,161,161,178,132,150,11,78,1,161,161,178,132,150,11,79,1,129,161,178,132,150,11,84,1,161,161,178,132,150,11,85,1,161,161,178,132,150,11,82,1,161,161,178,132,150,11,83,1,136,161,178,132,150,11,88,1,118,2,2,105,100,119,36,99,97,49,50,50,99,48,52,45,100,55,98,51,45,52,102,55,48,45,57,57,53,49,45,57,54,98,102,100,97,57,98,54,98,50,52,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,33,243,102,161,161,178,132,150,11,89,1,161,161,178,132,150,11,86,1,161,161,178,132,150,11,87,1,129,161,178,132,150,11,92,1,161,161,178,132,150,11,93,1,161,167,131,133,162,9,0,1,161,167,131,133,162,9,1,1,129,161,178,132,150,11,96,1,1,223,209,193,147,11,0,161,213,255,156,145,1,1,81,7,141,245,194,142,11,0,161,158,182,250,251,9,12,1,161,158,182,250,251,9,13,1,129,158,182,250,251,9,14,1,161,158,182,250,251,9,11,1,161,158,182,250,251,9,8,1,161,158,182,250,251,9,9,1,129,141,245,194,142,11,2,1,3,253,205,145,137,11,0,161,180,205,189,133,13,15,1,161,180,205,189,133,13,19,5,161,253,205,145,137,11,5,4,3,142,130,192,134,11,0,161,207,228,238,162,8,47,1,161,207,228,238,162,8,48,1,161,207,228,238,162,8,46,1,1,139,152,215,249,10,0,161,231,189,134,196,8,76,34,1,255,255,147,249,10,0,161,182,143,233,195,4,110,3,2,152,158,185,230,10,0,39,0,203,184,221,173,11,7,18,51,48,52,49,50,48,49,48,57,48,55,49,51,51,57,53,50,48,0,8,0,152,158,185,230,10,0,6,118,2,2,105,100,119,36,101,48,102,101,54,56,54,55,45,50,48,56,102,45,52,51,57,57,45,97,56,56,97,45,101,57,98,97,102,52,56,97,99,48,53,101,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,101,241,153,125,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,101,241,153,129,2,105,100,119,36,53,54,54,56,57,101,52,50,45,49,102,101,56,45,52,97,97,102,45,56,50,99,53,45,99,51,100,99,98,102,99,51,98,50,53,52,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,101,241,153,131,2,105,100,119,36,51,53,100,51,57,57,98,57,45,49,57,55,101,45,52,57,99,54,45,97,98,102,56,45,101,51,57,51,49,101,48,97,55,51,49,51,118,2,2,105,100,119,36,50,57,55,48,52,49,52,101,45,99,99,50,48,45,52,51,50,102,45,97,100,49,54,45,52,50,101,99,55,49,55,51,54,100,53,57,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,101,241,153,133,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,101,241,153,136,2,105,100,119,36,102,57,101,48,48,54,53,49,45,49,53,48,101,45,52,50,56,56,45,56,48,55,57,45,50,50,100,48,54,97,50,55,54,97,55,49,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,101,241,153,140,2,105,100,119,36,56,54,54,57,52,102,97,100,45,54,55,52,97,45,52,54,55,52,45,56,52,100,48,45,51,50,99,52,56,54,97,55,55,48,98,52,1,145,190,137,224,10,0,161,155,159,180,195,15,5,2,3,178,162,190,217,10,0,161,184,201,188,172,10,0,1,161,184,201,188,172,10,1,1,161,184,201,188,172,10,2,1,3,197,254,154,201,10,0,161,244,226,228,149,2,1,1,161,244,226,228,149,2,2,1,129,244,226,228,149,2,29,1,1,248,196,187,185,10,0,161,252,171,209,175,15,3,31,1,135,240,136,178,10,0,161,184,231,170,67,5,45,30,200,205,214,172,10,0,161,161,178,132,150,11,12,1,161,161,178,132,150,11,17,1,129,186,197,166,179,15,6,1,161,200,205,214,172,10,0,1,161,200,205,214,172,10,1,1,129,200,205,214,172,10,2,1,161,186,197,166,179,15,4,1,161,186,197,166,179,15,5,1,129,200,205,214,172,10,5,1,161,200,205,214,172,10,3,1,161,200,205,214,172,10,4,1,129,200,205,214,172,10,8,1,161,200,205,214,172,10,9,1,161,200,205,214,172,10,10,1,129,200,205,214,172,10,11,1,161,200,205,214,172,10,6,1,161,200,205,214,172,10,7,1,129,200,205,214,172,10,14,1,161,200,205,214,172,10,12,1,161,200,205,214,172,10,13,1,129,200,205,214,172,10,17,1,161,200,205,214,172,10,15,1,161,200,205,214,172,10,16,1,129,200,205,214,172,10,20,1,161,200,205,214,172,10,18,1,161,200,205,214,172,10,19,1,129,200,205,214,172,10,23,1,161,200,205,214,172,10,21,1,161,200,205,214,172,10,22,1,129,200,205,214,172,10,26,1,3,184,201,188,172,10,0,161,142,130,192,134,11,0,1,161,142,130,192,134,11,1,1,161,142,130,192,134,11,2,1,16,156,148,170,169,10,0,161,211,202,217,232,12,3,1,161,211,202,217,232,12,0,1,161,211,202,217,232,12,1,1,129,211,202,217,232,12,6,1,161,156,148,170,169,10,0,1,161,252,218,241,167,14,0,1,161,252,218,241,167,14,1,1,129,156,148,170,169,10,3,1,161,156,148,170,169,10,4,1,161,156,148,170,169,10,1,1,161,156,148,170,169,10,2,1,129,156,148,170,169,10,7,1,161,156,148,170,169,10,8,1,161,167,131,133,162,9,0,1,161,167,131,133,162,9,1,1,129,156,148,170,169,10,11,1,48,158,156,181,152,10,0,161,206,220,129,131,4,18,1,161,206,220,129,131,4,19,1,129,206,220,129,131,4,20,1,161,206,220,129,131,4,0,1,161,206,220,129,131,4,1,1,129,158,156,181,152,10,2,1,72,206,220,129,131,4,3,1,118,1,2,105,100,119,36,100,49,52,50,51,57,101,57,45,50,98,102,55,45,52,56,50,52,45,57,51,101,99,45,52,102,51,99,99,53,54,49,54,55,50,48,161,206,220,129,131,4,4,1,161,206,220,129,131,4,5,1,39,0,203,184,221,173,11,1,36,100,49,52,50,51,57,101,57,45,50,98,102,55,45,52,56,50,52,45,57,51,101,99,45,52,102,51,99,99,53,54,49,54,55,50,48,1,40,0,158,156,181,152,10,9,2,105,100,1,119,36,100,49,52,50,51,57,101,57,45,50,98,102,55,45,52,56,50,52,45,57,51,101,99,45,52,102,51,99,99,53,54,49,54,55,50,48,40,0,158,156,181,152,10,9,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,158,156,181,152,10,9,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,158,156,181,152,10,9,4,100,101,115,99,1,119,0,40,0,158,156,181,152,10,9,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,33,0,158,156,181,152,10,9,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,100,49,52,50,51,57,101,57,45,50,98,102,55,45,52,56,50,52,45,57,51,101,99,45,52,102,51,99,99,53,54,49,54,55,50,48,0,40,0,158,156,181,152,10,9,4,105,99,111,110,1,119,0,40,0,158,156,181,152,10,9,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,158,156,181,152,10,9,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,158,156,181,152,10,9,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,2,161,158,156,181,152,10,19,1,129,158,156,181,152,10,5,1,161,233,165,139,246,14,4,1,161,233,165,139,246,14,5,1,129,158,156,181,152,10,23,1,8,0,203,184,221,173,11,30,1,118,1,2,105,100,119,36,98,53,56,48,55,51,52,53,45,53,100,97,55,45,52,53,98,100,45,97,56,97,101,45,101,97,53,54,56,99,55,99,57,49,49,97,161,203,184,221,173,11,29,1,161,158,156,181,152,10,25,1,39,0,203,184,221,173,11,1,36,98,53,56,48,55,51,52,53,45,53,100,97,55,45,52,53,98,100,45,97,56,97,101,45,101,97,53,54,56,99,55,99,57,49,49,97,1,40,0,158,156,181,152,10,30,2,105,100,1,119,36,98,53,56,48,55,51,52,53,45,53,100,97,55,45,52,53,98,100,45,97,56,97,101,45,101,97,53,54,56,99,55,99,57,49,49,97,33,0,158,156,181,152,10,30,4,110,97,109,101,1,40,0,158,156,181,152,10,30,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,158,156,181,152,10,30,4,100,101,115,99,1,119,0,40,0,158,156,181,152,10,30,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,158,156,181,152,10,30,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,241,129,30,39,0,203,184,221,173,11,4,36,98,53,56,48,55,51,52,53,45,53,100,97,55,45,52,53,98,100,45,97,56,97,101,45,101,97,53,54,56,99,55,99,57,49,49,97,0,40,0,158,156,181,152,10,30,4,105,99,111,110,1,119,0,40,0,158,156,181,152,10,30,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,158,156,181,152,10,30,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,158,156,181,152,10,30,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,203,184,221,173,11,36,1,161,158,156,181,152,10,41,1,161,158,156,181,152,10,40,1,129,158,156,181,152,10,26,1,161,158,156,181,152,10,43,1,161,158,156,181,152,10,44,1,129,158,156,181,152,10,45,1,9,154,193,208,134,10,0,161,229,154,128,197,12,3,1,161,229,154,128,197,12,4,1,129,162,159,252,196,11,2,1,161,154,193,208,134,10,0,1,161,154,193,208,134,10,1,1,129,154,193,208,134,10,2,1,161,154,193,208,134,10,3,1,161,154,193,208,134,10,4,1,129,154,193,208,134,10,5,1,3,235,225,184,133,10,0,161,233,165,139,246,14,40,1,161,233,165,139,246,14,41,1,129,233,165,139,246,14,42,1,15,158,182,250,251,9,0,161,229,154,128,197,12,3,1,161,229,154,128,197,12,4,1,129,162,159,252,196,11,2,1,161,233,247,183,159,1,0,1,161,158,156,181,152,10,3,1,161,158,156,181,152,10,4,1,129,158,182,250,251,9,2,1,161,158,182,250,251,9,3,1,161,158,182,250,251,9,0,1,161,158,182,250,251,9,1,1,129,158,182,250,251,9,6,1,161,158,182,250,251,9,7,1,161,171,204,155,217,8,0,1,161,171,204,155,217,8,1,1,129,158,182,250,251,9,10,1,31,170,140,240,234,9,0,161,201,191,159,147,14,14,1,161,201,191,159,147,14,15,1,129,201,191,159,147,14,16,1,161,201,191,159,147,14,13,1,161,201,191,159,147,14,7,1,161,201,191,159,147,14,8,1,129,170,140,240,234,9,2,1,161,170,140,240,234,9,4,1,161,170,140,240,234,9,5,1,129,170,140,240,234,9,6,1,161,170,140,240,234,9,0,1,161,170,140,240,234,9,1,1,129,170,140,240,234,9,9,1,161,170,140,240,234,9,3,1,161,170,140,240,234,9,10,1,161,170,140,240,234,9,11,1,129,170,140,240,234,9,12,1,161,201,129,238,197,4,56,1,161,201,129,238,197,4,55,1,129,170,140,240,234,9,16,1,161,170,140,240,234,9,13,1,161,170,140,240,234,9,17,1,161,170,140,240,234,9,18,1,129,170,140,240,234,9,19,1,161,170,140,240,234,9,14,1,161,170,140,240,234,9,15,1,129,170,140,240,234,9,23,1,161,170,140,240,234,9,20,1,161,170,140,240,234,9,24,1,161,170,140,240,234,9,25,1,129,170,140,240,234,9,26,1,1,191,157,147,233,9,0,161,190,139,191,155,1,1,32,1,200,159,185,206,9,0,161,231,139,244,188,8,12,8,15,135,232,133,203,9,0,161,248,136,168,181,1,0,1,161,248,136,168,181,1,1,1,129,248,136,168,181,1,2,1,161,135,232,133,203,9,0,1,161,135,232,133,203,9,1,1,129,135,232,133,203,9,2,1,161,135,232,133,203,9,3,1,161,135,232,133,203,9,4,1,129,135,232,133,203,9,5,1,161,135,232,133,203,9,6,1,161,135,232,133,203,9,7,1,129,135,232,133,203,9,8,1,161,135,232,133,203,9,9,1,161,135,232,133,203,9,10,1,129,135,232,133,203,9,11,1,11,167,131,133,162,9,0,161,211,202,217,232,12,4,1,161,211,202,217,232,12,5,1,129,141,205,220,149,4,2,1,161,211,202,217,232,12,3,1,161,158,182,250,251,9,4,1,161,158,182,250,251,9,5,1,129,167,131,133,162,9,2,1,161,167,131,133,162,9,3,1,161,214,168,149,214,3,8,1,161,214,168,149,214,3,9,1,129,167,131,133,162,9,6,1,1,234,182,182,157,9,0,161,161,239,241,154,13,105,8,21,188,171,136,250,8,0,161,200,205,214,172,10,24,1,161,200,205,214,172,10,25,1,129,200,205,214,172,10,29,1,161,188,171,136,250,8,0,1,161,188,171,136,250,8,1,1,129,188,171,136,250,8,2,1,161,164,155,139,169,7,4,1,161,164,155,139,169,7,5,1,129,164,155,139,169,7,6,1,161,164,155,139,169,7,12,1,161,164,155,139,169,7,13,1,129,164,155,139,169,7,14,1,161,188,171,136,250,8,9,1,161,188,171,136,250,8,10,1,129,188,171,136,250,8,11,1,161,188,171,136,250,8,12,1,161,188,171,136,250,8,13,1,129,188,171,136,250,8,14,1,161,164,155,139,169,7,16,1,161,164,155,139,169,7,17,1,129,164,155,139,169,7,18,1,70,187,220,199,239,8,0,168,137,164,190,210,1,36,1,122,4,56,115,160,190,64,16,0,161,137,164,190,210,1,37,1,136,137,164,190,210,1,38,1,118,2,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,97,115,51,161,137,164,190,210,1,29,1,161,137,164,190,210,1,30,1,136,187,220,199,239,8,2,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,97,115,57,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,161,137,164,190,210,1,35,1,168,187,220,199,239,8,3,1,122,4,56,115,160,190,64,16,0,168,187,220,199,239,8,4,1,122,0,0,0,0,102,97,115,57,136,187,220,199,239,8,5,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,97,115,57,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,136,247,200,243,247,14,0,1,118,1,2,105,100,119,36,55,102,50,51,51,98,101,52,45,49,98,52,100,45,52,54,98,50,45,98,99,102,99,45,102,51,52,49,98,56,100,55,53,50,54,55,168,247,200,243,247,14,1,1,122,0,0,0,0,102,97,115,63,168,187,220,199,239,8,1,1,122,0,0,0,0,102,97,115,63,39,0,203,184,221,173,11,1,36,55,102,50,51,51,98,101,52,45,49,98,52,100,45,52,54,98,50,45,98,99,102,99,45,102,51,52,49,98,56,100,55,53,50,54,55,1,40,0,187,220,199,239,8,13,2,105,100,1,119,36,55,102,50,51,51,98,101,52,45,49,98,52,100,45,52,54,98,50,45,98,99,102,99,45,102,51,52,49,98,56,100,55,53,50,54,55,33,0,187,220,199,239,8,13,4,110,97,109,101,1,40,0,187,220,199,239,8,13,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,187,220,199,239,8,13,4,100,101,115,99,1,119,0,40,0,187,220,199,239,8,13,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,33,0,187,220,199,239,8,13,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,55,102,50,51,51,98,101,52,45,49,98,52,100,45,52,54,98,50,45,98,99,102,99,45,102,51,52,49,98,56,100,55,53,50,54,55,0,40,0,187,220,199,239,8,13,4,105,99,111,110,1,119,0,40,0,187,220,199,239,8,13,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,187,220,199,239,8,13,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,187,220,199,239,8,13,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,187,220,199,239,8,6,1,161,187,220,199,239,8,24,1,161,187,220,199,239,8,23,1,129,187,220,199,239,8,9,1,161,187,220,199,239,8,26,1,161,187,220,199,239,8,27,1,129,187,220,199,239,8,28,1,161,187,220,199,239,8,29,1,161,187,220,199,239,8,30,1,129,187,220,199,239,8,31,1,161,187,220,199,239,8,32,1,161,187,220,199,239,8,33,1,161,187,220,199,239,8,15,1,161,187,220,199,239,8,35,1,161,187,220,199,239,8,36,1,168,187,220,199,239,8,37,1,119,10,70,105,108,116,101,114,71,114,105,100,8,0,187,220,199,239,8,20,1,118,1,2,105,100,119,36,97,55,51,52,97,48,54,56,45,101,55,51,100,45,52,98,52,98,45,56,53,51,99,45,52,100,97,102,102,101,97,51,56,57,99,48,168,187,220,199,239,8,19,1,122,0,0,0,0,102,97,115,248,161,187,220,199,239,8,39,1,39,0,203,184,221,173,11,1,36,97,55,51,52,97,48,54,56,45,101,55,51,100,45,52,98,52,98,45,56,53,51,99,45,52,100,97,102,102,101,97,51,56,57,99,48,1,40,0,187,220,199,239,8,44,2,105,100,1,119,36,97,55,51,52,97,48,54,56,45,101,55,51,100,45,52,98,52,98,45,56,53,51,99,45,52,100,97,102,102,101,97,51,56,57,99,48,40,0,187,220,199,239,8,44,4,110,97,109,101,1,119,4,71,114,105,100,40,0,187,220,199,239,8,44,3,98,105,100,1,119,36,55,102,50,51,51,98,101,52,45,49,98,52,100,45,52,54,98,50,45,98,99,102,99,45,102,51,52,49,98,56,100,55,53,50,54,55,40,0,187,220,199,239,8,44,4,100,101,115,99,1,119,0,40,0,187,220,199,239,8,44,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,40,0,187,220,199,239,8,44,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,97,115,248,39,0,203,184,221,173,11,4,36,97,55,51,52,97,48,54,56,45,101,55,51,100,45,52,98,52,98,45,56,53,51,99,45,52,100,97,102,102,101,97,51,56,57,99,48,0,40,0,187,220,199,239,8,44,4,105,99,111,110,1,119,0,40,0,187,220,199,239,8,44,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,187,220,199,239,8,44,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,102,97,115,248,40,0,187,220,199,239,8,44,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,161,247,200,243,247,14,55,1,161,247,200,243,247,14,56,1,129,187,220,199,239,8,34,1,161,187,220,199,239,8,25,1,168,187,220,199,239,8,56,1,122,4,56,115,160,190,64,16,0,168,187,220,199,239,8,57,1,122,0,0,0,0,102,97,116,215,136,187,220,199,239,8,58,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,97,116,215,2,105,100,119,36,55,57,100,48,54,51,50,100,45,97,53,97,56,45,52,53,52,48,45,97,100,99,100,45,54,101,101,57,50,50,100,56,54,55,101,100,161,187,220,199,239,8,38,1,161,187,220,199,239,8,43,1,129,187,220,199,239,8,62,1,168,187,220,199,239,8,59,1,119,36,55,102,50,51,51,98,101,52,45,49,98,52,100,45,52,54,98,50,45,98,99,102,99,45,102,51,52,49,98,56,100,55,53,50,54,55,168,187,220,199,239,8,63,1,122,4,56,115,160,190,64,16,0,168,187,220,199,239,8,64,1,122,0,0,0,0,102,97,116,215,136,187,220,199,239,8,65,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,97,116,215,2,105,100,119,36,55,102,50,51,51,98,101,52,45,49,98,52,100,45,52,54,98,50,45,98,99,102,99,45,102,51,52,49,98,56,100,55,53,50,54,55,1,236,229,225,232,8,0,161,219,227,140,137,6,33,116,3,171,204,155,217,8,0,161,229,154,128,197,12,21,1,161,229,154,128,197,12,22,1,129,229,154,128,197,12,23,1,3,149,189,189,215,8,0,161,160,192,253,131,5,0,1,161,160,192,253,131,5,1,1,129,160,192,253,131,5,2,1,1,231,189,134,196,8,0,161,153,130,203,161,6,96,77,3,195,242,227,194,8,0,161,155,165,205,152,11,0,1,161,155,165,205,152,11,1,1,129,155,165,205,152,11,2,1,1,231,139,244,188,8,0,161,128,252,161,128,4,32,13,1,219,220,239,171,8,0,161,248,196,187,185,10,30,10,198,1,154,244,246,165,8,0,161,174,151,139,93,176,2,1,161,174,151,139,93,177,2,1,129,174,151,139,93,178,2,1,161,174,151,139,93,140,2,1,161,174,151,139,93,141,2,1,129,154,244,246,165,8,2,1,161,174,151,139,93,175,2,1,161,154,244,246,165,8,3,1,161,154,244,246,165,8,4,1,129,154,244,246,165,8,5,1,161,154,244,246,165,8,0,1,161,154,244,246,165,8,1,1,129,154,244,246,165,8,9,1,161,154,244,246,165,8,6,1,161,154,244,246,165,8,10,1,161,154,244,246,165,8,11,1,129,154,244,246,165,8,12,1,161,154,244,246,165,8,7,1,161,154,244,246,165,8,8,1,129,154,244,246,165,8,16,1,161,154,244,246,165,8,13,1,161,154,244,246,165,8,17,1,161,154,244,246,165,8,18,1,129,154,244,246,165,8,19,1,136,213,161,242,209,13,3,1,118,1,2,105,100,119,36,49,51,53,54,49,53,102,97,45,54,54,102,55,45,52,52,53,49,45,57,98,53,52,45,100,55,101,57,57,52,52,53,102,99,97,52,168,213,161,242,209,13,4,1,122,0,0,0,0,102,79,7,13,161,154,244,246,165,8,15,1,39,0,203,184,221,173,11,1,36,49,51,53,54,49,53,102,97,45,54,54,102,55,45,52,52,53,49,45,57,98,53,52,45,100,55,101,57,57,52,52,53,102,99,97,52,1,40,0,154,244,246,165,8,27,2,105,100,1,119,36,49,51,53,54,49,53,102,97,45,54,54,102,55,45,52,52,53,49,45,57,98,53,52,45,100,55,101,57,57,52,52,53,102,99,97,52,40,0,154,244,246,165,8,27,4,110,97,109,101,1,119,12,86,105,101,119,32,111,102,32,71,114,105,100,40,0,154,244,246,165,8,27,3,98,105,100,1,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,40,0,154,244,246,165,8,27,4,100,101,115,99,1,119,0,40,0,154,244,246,165,8,27,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,40,0,154,244,246,165,8,27,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,79,7,13,39,0,203,184,221,173,11,4,36,49,51,53,54,49,53,102,97,45,54,54,102,55,45,52,52,53,49,45,57,98,53,52,45,100,55,101,57,57,52,52,53,102,99,97,52,0,40,0,154,244,246,165,8,27,4,105,99,111,110,1,119,0,40,0,154,244,246,165,8,27,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,154,244,246,165,8,27,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,154,244,246,165,8,27,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,8,0,165,139,157,171,15,10,1,118,1,2,105,100,119,36,98,52,101,55,55,50,48,51,45,53,99,56,98,45,52,56,100,102,45,98,98,99,53,45,50,101,49,49,52,51,101,98,48,101,54,49,168,165,139,157,171,15,9,1,122,0,0,0,0,102,79,7,25,168,174,151,139,93,170,2,1,122,0,0,0,0,102,79,7,25,39,0,203,184,221,173,11,1,36,98,52,101,55,55,50,48,51,45,53,99,56,98,45,52,56,100,102,45,98,98,99,53,45,50,101,49,49,52,51,101,98,48,101,54,49,1,40,0,154,244,246,165,8,42,2,105,100,1,119,36,98,52,101,55,55,50,48,51,45,53,99,56,98,45,52,56,100,102,45,98,98,99,53,45,50,101,49,49,52,51,101,98,48,101,54,49,40,0,154,244,246,165,8,42,4,110,97,109,101,1,119,22,86,105,101,119,32,111,102,32,66,111,97,114,100,32,99,104,101,99,107,98,111,120,40,0,154,244,246,165,8,42,3,98,105,100,1,119,36,97,53,53,54,54,101,52,57,45,102,49,53,54,45,52,49,54,56,45,57,98,50,100,45,49,55,57,50,54,99,53,100,97,51,50,57,40,0,154,244,246,165,8,42,4,100,101,115,99,1,119,0,40,0,154,244,246,165,8,42,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,2,40,0,154,244,246,165,8,42,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,79,7,25,39,0,203,184,221,173,11,4,36,98,52,101,55,55,50,48,51,45,53,99,56,98,45,52,56,100,102,45,98,98,99,53,45,50,101,49,49,52,51,101,98,48,101,54,49,0,40,0,154,244,246,165,8,42,4,105,99,111,110,1,119,0,40,0,154,244,246,165,8,42,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,154,244,246,165,8,42,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,102,79,7,25,40,0,154,244,246,165,8,42,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,8,0,201,129,238,197,4,67,1,118,1,2,105,100,119,36,97,54,97,102,51,49,49,102,45,99,98,99,56,45,52,50,99,50,45,98,56,48,49,45,55,49,49,53,54,49,57,99,51,55,55,54,168,201,129,238,197,4,66,1,122,0,0,0,0,102,79,7,32,161,174,151,139,93,106,1,39,0,203,184,221,173,11,1,36,97,54,97,102,51,49,49,102,45,99,98,99,56,45,52,50,99,50,45,98,56,48,49,45,55,49,49,53,54,49,57,99,51,55,55,54,1,40,0,154,244,246,165,8,57,2,105,100,1,119,36,97,54,97,102,51,49,49,102,45,99,98,99,56,45,52,50,99,50,45,98,56,48,49,45,55,49,49,53,54,49,57,99,51,55,55,54,40,0,154,244,246,165,8,57,4,110,97,109,101,1,119,16,86,105,101,119,32,111,102,32,67,97,108,101,110,100,97,114,40,0,154,244,246,165,8,57,3,98,105,100,1,119,36,50,49,52,51,101,57,53,100,45,53,100,99,98,45,52,101,48,102,45,98,98,50,99,45,53,48,57,52,52,101,54,101,48,49,57,102,40,0,154,244,246,165,8,57,4,100,101,115,99,1,119,0,40,0,154,244,246,165,8,57,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,3,40,0,154,244,246,165,8,57,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,79,7,32,39,0,203,184,221,173,11,4,36,97,54,97,102,51,49,49,102,45,99,98,99,56,45,52,50,99,50,45,98,56,48,49,45,55,49,49,53,54,49,57,99,51,55,55,54,0,40,0,154,244,246,165,8,57,4,105,99,111,110,1,119,0,40,0,154,244,246,165,8,57,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,154,244,246,165,8,57,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,102,79,7,32,40,0,154,244,246,165,8,57,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,136,174,151,139,93,177,1,1,118,1,2,105,100,119,36,50,98,102,53,48,99,48,51,45,102,52,49,102,45,52,51,54,51,45,98,53,98,49,45,49,48,49,50,49,54,97,54,99,53,99,99,168,174,151,139,93,178,1,1,122,0,0,0,0,102,79,7,50,161,174,151,139,93,179,1,1,39,0,203,184,221,173,11,1,36,50,98,102,53,48,99,48,51,45,102,52,49,102,45,52,51,54,51,45,98,53,98,49,45,49,48,49,50,49,54,97,54,99,53,99,99,1,40,0,154,244,246,165,8,72,2,105,100,1,119,36,50,98,102,53,48,99,48,51,45,102,52,49,102,45,52,51,54,51,45,98,53,98,49,45,49,48,49,50,49,54,97,54,99,53,99,99,40,0,154,244,246,165,8,72,4,110,97,109,101,1,119,16,86,105,101,119,32,111,102,32,67,97,108,101,110,100,97,114,40,0,154,244,246,165,8,72,3,98,105,100,1,119,36,101,101,51,97,101,56,99,101,45,57,53,57,97,45,52,100,102,51,45,56,55,51,52,45,52,48,98,53,51,53,102,102,56,56,101,51,40,0,154,244,246,165,8,72,4,100,101,115,99,1,119,0,40,0,154,244,246,165,8,72,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,3,40,0,154,244,246,165,8,72,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,79,7,50,39,0,203,184,221,173,11,4,36,50,98,102,53,48,99,48,51,45,102,52,49,102,45,52,51,54,51,45,98,53,98,49,45,49,48,49,50,49,54,97,54,99,53,99,99,0,40,0,154,244,246,165,8,72,4,105,99,111,110,1,119,0,40,0,154,244,246,165,8,72,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,154,244,246,165,8,72,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,154,244,246,165,8,72,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,154,244,246,165,8,20,1,168,154,244,246,165,8,83,1,122,4,56,115,160,190,64,16,0,168,154,244,246,165,8,82,1,122,0,0,0,0,102,79,23,79,136,154,244,246,165,8,23,1,118,2,2,105,100,119,36,50,98,102,53,48,99,48,51,45,102,52,49,102,45,52,51,54,51,45,98,53,98,49,45,49,48,49,50,49,54,97,54,99,53,99,99,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,79,23,79,161,154,244,246,165,8,84,1,161,174,151,139,93,174,1,1,161,154,244,246,165,8,71,1,129,154,244,246,165,8,87,1,161,154,244,246,165,8,89,1,161,154,244,246,165,8,90,1,129,154,244,246,165,8,91,1,161,154,244,246,165,8,21,1,161,154,244,246,165,8,22,1,129,154,244,246,165,8,94,1,161,154,244,246,165,8,88,1,161,154,244,246,165,8,95,1,161,154,244,246,165,8,96,1,129,154,244,246,165,8,97,1,161,154,244,246,165,8,98,1,161,154,244,246,165,8,38,1,161,154,244,246,165,8,37,1,129,154,244,246,165,8,101,1,161,154,244,246,165,8,14,1,161,154,244,246,165,8,26,1,129,154,244,246,165,8,105,1,161,154,244,246,165,8,102,1,161,154,244,246,165,8,106,1,161,154,244,246,165,8,107,1,129,154,244,246,165,8,108,1,161,154,244,246,165,8,99,1,161,154,244,246,165,8,100,1,129,154,244,246,165,8,112,1,161,154,244,246,165,8,109,1,161,154,244,246,165,8,113,1,161,154,244,246,165,8,114,1,129,154,244,246,165,8,115,1,161,154,244,246,165,8,103,1,161,154,244,246,165,8,104,1,129,154,244,246,165,8,119,1,161,154,244,246,165,8,116,1,168,154,244,246,165,8,120,1,122,4,56,115,160,190,64,16,0,168,154,244,246,165,8,121,1,122,0,0,0,0,102,79,28,199,136,154,244,246,165,8,122,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,79,28,199,2,105,100,119,36,49,51,53,54,49,53,102,97,45,54,54,102,55,45,52,52,53,49,45,57,98,53,52,45,100,55,101,57,57,52,52,53,102,99,97,52,161,154,244,246,165,8,123,1,161,174,151,139,93,105,1,161,154,244,246,165,8,56,1,129,154,244,246,165,8,126,1,161,154,244,246,165,8,128,1,1,161,154,244,246,165,8,129,1,1,129,154,244,246,165,8,130,1,1,161,154,244,246,165,8,92,1,161,154,244,246,165,8,93,1,129,154,244,246,165,8,133,1,1,161,154,244,246,165,8,127,1,161,154,244,246,165,8,134,1,1,161,154,244,246,165,8,135,1,1,129,154,244,246,165,8,136,1,1,161,154,244,246,165,8,131,1,1,161,154,244,246,165,8,132,1,1,129,154,244,246,165,8,140,1,1,161,154,244,246,165,8,137,1,1,168,154,244,246,165,8,141,1,1,122,4,56,115,160,190,64,16,0,168,154,244,246,165,8,142,1,1,122,0,0,0,0,102,80,7,127,136,154,244,246,165,8,143,1,1,118,2,2,105,100,119,36,50,49,52,51,101,57,53,100,45,53,100,99,98,45,52,101,48,102,45,98,98,50,99,45,53,48,57,52,52,101,54,101,48,49,57,102,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,80,7,127,161,154,244,246,165,8,138,1,1,161,154,244,246,165,8,139,1,1,129,154,244,246,165,8,147,1,1,161,154,244,246,165,8,144,1,1,161,154,244,246,165,8,148,1,1,161,154,244,246,165,8,149,1,1,129,154,244,246,165,8,150,1,1,161,154,244,246,165,8,110,1,161,154,244,246,165,8,111,1,129,154,244,246,165,8,154,1,1,161,154,244,246,165,8,151,1,1,161,154,244,246,165,8,155,1,1,161,154,244,246,165,8,156,1,1,129,154,244,246,165,8,157,1,1,161,174,151,139,93,153,1,1,161,174,151,139,93,154,1,1,129,154,244,246,165,8,161,1,1,161,154,244,246,165,8,158,1,1,161,154,244,246,165,8,162,1,1,161,154,244,246,165,8,163,1,1,129,154,244,246,165,8,164,1,1,161,154,244,246,165,8,152,1,1,161,154,244,246,165,8,153,1,1,129,154,244,246,165,8,168,1,1,161,154,244,246,165,8,165,1,1,161,154,244,246,165,8,169,1,1,161,154,244,246,165,8,170,1,1,129,154,244,246,165,8,171,1,1,161,154,244,246,165,8,117,1,161,154,244,246,165,8,118,1,129,154,244,246,165,8,175,1,1,161,154,244,246,165,8,172,1,1,161,154,244,246,165,8,176,1,1,161,154,244,246,165,8,177,1,1,129,154,244,246,165,8,178,1,1,39,0,203,184,221,173,11,1,36,53,55,98,56,49,55,55,100,45,57,100,52,50,45,53,49,55,56,45,56,99,98,50,45,102,99,53,101,54,57,51,48,102,51,48,97,1,40,0,154,244,246,165,8,183,1,2,105,100,1,119,36,53,55,98,56,49,55,55,100,45,57,100,52,50,45,53,49,55,56,45,56,99,98,50,45,102,99,53,101,54,57,51,48,102,51,48,97,40,0,154,244,246,165,8,183,1,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,154,244,246,165,8,183,1,3,98,105,100,1,119,36,53,55,98,56,49,55,55,100,45,57,100,52,50,45,53,49,55,56,45,56,99,98,50,45,102,99,53,101,54,57,51,48,102,51,48,97,40,0,154,244,246,165,8,183,1,4,100,101,115,99,1,119,0,40,0,154,244,246,165,8,183,1,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,154,244,246,165,8,183,1,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,80,7,153,39,0,203,184,221,173,11,4,36,53,55,98,56,49,55,55,100,45,57,100,52,50,45,53,49,55,56,45,56,99,98,50,45,102,99,53,101,54,57,51,48,102,51,48,97,0,40,0,154,244,246,165,8,183,1,4,105,99,111,110,1,119,0,40,0,154,244,246,165,8,183,1,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,154,244,246,165,8,183,1,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,154,244,246,165,8,183,1,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,168,154,244,246,165,8,194,1,1,122,4,56,115,160,190,64,16,0,168,154,244,246,165,8,193,1,1,122,0,0,0,0,102,80,7,153,40,0,154,244,246,165,8,183,1,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,50,207,228,238,162,8,0,136,158,156,181,152,10,27,1,118,1,2,105,100,119,36,100,97,53,54,102,102,97,48,45,53,51,53,54,45,52,50,56,99,45,98,54,49,98,45,53,55,52,97,49,49,57,99,54,57,57,101,161,158,156,181,152,10,28,1,161,158,156,181,152,10,29,1,39,0,203,184,221,173,11,1,36,100,97,53,54,102,102,97,48,45,53,51,53,54,45,52,50,56,99,45,98,54,49,98,45,53,55,52,97,49,49,57,99,54,57,57,101,1,40,0,207,228,238,162,8,3,2,105,100,1,119,36,100,97,53,54,102,102,97,48,45,53,51,53,54,45,52,50,56,99,45,98,54,49,98,45,53,55,52,97,49,49,57,99,54,57,57,101,40,0,207,228,238,162,8,3,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,207,228,238,162,8,3,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,207,228,238,162,8,3,4,100,101,115,99,1,119,0,40,0,207,228,238,162,8,3,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,207,228,238,162,8,3,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,242,129,194,39,0,203,184,221,173,11,4,36,100,97,53,54,102,102,97,48,45,53,51,53,54,45,52,50,56,99,45,98,54,49,98,45,53,55,52,97,49,49,57,99,54,57,57,101,0,40,0,207,228,238,162,8,3,4,105,99,111,110,1,119,0,40,0,207,228,238,162,8,3,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,207,228,238,162,8,3,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,207,228,238,162,8,3,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,158,156,181,152,10,42,1,161,207,228,238,162,8,14,1,161,207,228,238,162,8,13,1,129,158,156,181,152,10,48,1,161,207,228,238,162,8,16,1,161,207,228,238,162,8,17,1,129,207,228,238,162,8,18,1,136,207,228,238,162,8,0,1,118,1,2,105,100,119,36,52,52,51,53,101,53,55,98,45,99,50,54,51,45,52,101,55,102,45,97,52,51,53,45,50,48,56,55,57,97,54,50,101,54,100,97,161,207,228,238,162,8,1,1,161,207,228,238,162,8,2,1,39,0,203,184,221,173,11,1,36,52,52,51,53,101,53,55,98,45,99,50,54,51,45,52,101,55,102,45,97,52,51,53,45,50,48,56,55,57,97,54,50,101,54,100,97,1,40,0,207,228,238,162,8,25,2,105,100,1,119,36,52,52,51,53,101,53,55,98,45,99,50,54,51,45,52,101,55,102,45,97,52,51,53,45,50,48,56,55,57,97,54,50,101,54,100,97,40,0,207,228,238,162,8,25,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,207,228,238,162,8,25,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,207,228,238,162,8,25,4,100,101,115,99,1,119,0,40,0,207,228,238,162,8,25,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,207,228,238,162,8,25,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,242,129,219,39,0,203,184,221,173,11,4,36,52,52,51,53,101,53,55,98,45,99,50,54,51,45,52,101,55,102,45,97,52,51,53,45,50,48,56,55,57,97,54,50,101,54,100,97,0,40,0,207,228,238,162,8,25,4,105,99,111,110,1,119,0,40,0,207,228,238,162,8,25,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,207,228,238,162,8,25,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,207,228,238,162,8,25,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,207,228,238,162,8,15,1,161,207,228,238,162,8,36,1,161,207,228,238,162,8,35,1,129,207,228,238,162,8,21,1,161,207,228,238,162,8,38,1,161,207,228,238,162,8,39,1,129,207,228,238,162,8,40,1,161,158,156,181,152,10,46,1,161,158,156,181,152,10,47,1,161,158,156,181,152,10,32,1,161,207,228,238,162,8,44,1,161,207,228,238,162,8,45,1,129,207,228,238,162,8,43,1,1,183,226,184,158,8,0,161,240,253,240,229,1,78,8,11,175,225,172,150,8,0,161,173,252,148,184,13,61,1,161,173,252,148,184,13,62,1,129,173,252,148,184,13,63,1,161,173,252,148,184,13,60,1,161,173,252,148,184,13,57,1,161,173,252,148,184,13,58,1,129,175,225,172,150,8,2,1,161,175,225,172,150,8,3,1,161,175,225,172,150,8,0,1,161,175,225,172,150,8,1,1,136,175,225,172,150,8,6,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,41,200,233,2,105,100,119,36,100,48,52,57,54,51,50,52,45,53,53,55,48,45,52,48,48,54,45,98,52,101,97,45,100,98,55,53,49,54,100,50,49,50,102,100,66,214,139,213,136,8,0,161,201,129,238,197,4,9,1,161,201,129,238,197,4,10,1,136,149,249,242,175,4,13,1,118,2,2,105,100,119,36,102,51,53,50,55,48,99,55,45,99,54,54,99,45,52,54,99,101,45,56,101,49,97,45,51,102,54,51,57,102,55,98,48,48,48,100,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,7,168,214,139,213,136,8,0,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,1,1,122,0,0,0,0,102,77,78,7,161,180,230,210,212,13,0,1,161,133,159,138,205,12,9,1,136,214,139,213,136,8,2,1,118,2,2,105,100,119,36,100,48,52,57,54,51,50,52,45,53,53,55,48,45,52,48,48,54,45,98,52,101,97,45,100,98,55,53,49,54,100,50,49,50,102,100,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,9,168,214,139,213,136,8,5,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,6,1,122,0,0,0,0,102,77,78,9,161,201,129,238,197,4,12,1,161,201,129,238,197,4,13,1,136,214,139,213,136,8,7,1,118,2,2,105,100,119,36,100,49,52,50,51,57,101,57,45,50,98,102,55,45,52,56,50,52,45,57,51,101,99,45,52,102,51,99,99,53,54,49,54,55,50,48,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,10,168,214,139,213,136,8,10,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,11,1,122,0,0,0,0,102,77,78,10,161,158,156,181,152,10,0,1,161,158,156,181,152,10,1,1,136,214,139,213,136,8,12,1,118,2,2,105,100,119,36,99,55,52,55,53,49,50,51,45,56,50,51,57,45,52,98,98,49,45,56,100,102,53,45,54,56,49,52,56,48,102,101,57,53,52,99,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,11,168,214,139,213,136,8,15,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,16,1,122,0,0,0,0,102,77,78,12,161,161,178,132,150,11,90,1,161,161,178,132,150,11,91,1,136,214,139,213,136,8,17,1,118,2,2,105,100,119,36,99,97,49,50,50,99,48,52,45,100,55,98,51,45,52,102,55,48,45,57,57,53,49,45,57,54,98,102,100,97,57,98,54,98,50,52,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,12,168,214,139,213,136,8,20,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,21,1,122,0,0,0,0,102,77,78,12,161,222,205,223,235,7,7,1,161,222,205,223,235,7,8,1,136,214,139,213,136,8,22,1,118,2,2,105,100,119,36,98,53,56,48,55,51,52,53,45,53,100,97,55,45,52,53,98,100,45,97,56,97,101,45,101,97,53,54,56,99,55,99,57,49,49,97,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,29,168,214,139,213,136,8,25,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,26,1,122,0,0,0,0,102,77,78,30,161,207,228,238,162,8,19,1,161,207,228,238,162,8,20,1,136,214,139,213,136,8,27,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,30,2,105,100,119,36,100,97,53,54,102,102,97,48,45,53,51,53,54,45,52,50,56,99,45,98,54,49,98,45,53,55,52,97,49,49,57,99,54,57,57,101,168,214,139,213,136,8,30,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,31,1,122,0,0,0,0,102,77,78,30,161,173,252,148,184,13,17,1,161,173,252,148,184,13,18,1,136,214,139,213,136,8,32,1,118,2,2,105,100,119,36,52,52,51,53,101,53,55,98,45,99,50,54,51,45,52,101,55,102,45,97,52,51,53,45,50,48,56,55,57,97,54,50,101,54,100,97,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,31,168,214,139,213,136,8,35,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,36,1,122,0,0,0,0,102,77,78,31,161,225,248,138,176,2,7,1,161,225,248,138,176,2,8,1,136,214,139,213,136,8,37,1,118,2,2,105,100,119,36,100,100,98,57,51,98,97,55,45,48,54,99,55,45,52,49,55,54,45,57,56,50,97,45,100,55,52,50,51,101,48,57,98,52,52,49,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,41,168,214,139,213,136,8,40,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,41,1,122,0,0,0,0,102,77,78,41,161,165,139,157,171,15,91,1,161,165,139,157,171,15,92,1,136,214,139,213,136,8,42,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,44,2,105,100,119,36,50,99,49,101,101,57,53,97,45,49,98,48,57,45,52,97,49,102,45,56,100,53,101,45,53,48,49,98,99,52,56,54,49,97,57,100,168,214,139,213,136,8,45,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,46,1,122,0,0,0,0,102,77,78,44,161,234,153,236,158,4,3,1,161,234,153,236,158,4,4,1,136,214,139,213,136,8,47,1,118,2,2,105,100,119,36,49,98,48,101,51,50,50,100,45,52,57,48,57,45,52,99,54,51,45,57,49,52,97,45,100,48,51,52,102,99,51,54,51,48,57,55,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,45,168,214,139,213,136,8,50,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,51,1,122,0,0,0,0,102,77,78,45,161,165,139,157,171,15,58,1,161,165,139,157,171,15,59,1,136,214,139,213,136,8,52,1,118,2,2,105,100,119,36,54,53,98,48,54,100,98,56,45,55,48,54,49,45,52,98,102,54,45,98,51,49,53,45,55,53,56,99,48,100,100,50,53,99,100,102,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,77,78,49,168,214,139,213,136,8,55,1,122,4,56,115,160,190,64,16,0,168,214,139,213,136,8,56,1,122,0,0,0,0,102,77,78,49,161,241,155,213,233,1,0,1,161,241,155,213,233,1,1,1,129,241,155,213,233,1,24,1,161,214,139,213,136,8,60,1,161,214,139,213,136,8,61,1,129,214,139,213,136,8,62,1,31,222,205,223,235,7,0,161,137,226,192,199,6,17,1,161,137,226,192,199,6,18,1,129,137,226,192,199,6,19,1,161,201,129,238,197,4,39,1,161,201,129,238,197,4,40,1,129,222,205,223,235,7,2,1,161,137,226,192,199,6,13,1,161,222,205,223,235,7,3,1,161,222,205,223,235,7,4,1,136,222,205,223,235,7,5,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,67,55,119,2,105,100,119,36,98,53,56,48,55,51,52,53,45,53,100,97,55,45,52,53,98,100,45,97,56,97,101,45,101,97,53,54,56,99,55,99,57,49,49,97,161,222,205,223,235,7,0,1,161,222,205,223,235,7,1,1,129,222,205,223,235,7,9,1,161,222,205,223,235,7,6,1,161,222,205,223,235,7,10,1,161,222,205,223,235,7,11,1,129,222,205,223,235,7,12,1,161,137,226,192,199,6,7,1,161,137,226,192,199,6,8,1,129,222,205,223,235,7,16,1,161,222,205,223,235,7,13,1,161,222,205,223,235,7,17,1,161,222,205,223,235,7,18,1,129,222,205,223,235,7,19,1,161,222,205,223,235,7,14,1,161,222,205,223,235,7,15,1,129,222,205,223,235,7,23,1,161,222,205,223,235,7,20,1,161,222,205,223,235,7,24,1,161,222,205,223,235,7,25,1,129,222,205,223,235,7,26,1,3,162,238,198,212,7,0,161,245,220,194,52,6,1,161,247,200,243,247,14,2,1,136,247,200,243,247,14,57,1,118,2,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,87,58,53,12,241,130,161,205,7,0,161,226,212,179,248,2,12,1,161,226,212,179,248,2,13,1,129,226,212,179,248,2,14,1,161,234,153,236,158,4,61,1,161,234,153,236,158,4,62,1,129,241,130,161,205,7,2,1,161,241,130,161,205,7,0,1,161,241,130,161,205,7,1,1,129,241,130,161,205,7,5,1,168,234,153,236,158,4,39,1,122,4,56,115,160,190,64,16,0,168,234,153,236,158,4,38,1,122,0,0,0,0,102,78,192,25,136,174,151,139,93,243,1,1,118,2,2,105,100,119,36,101,52,99,56,57,52,50,49,45,49,50,98,50,45,52,100,48,50,45,56,54,51,100,45,50,48,57,52,57,101,101,99,57,50,55,49,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,78,192,25,1,229,153,197,202,7,0,161,239,199,189,146,3,23,241,6,1,250,198,166,187,7,0,161,152,252,186,192,1,1,2,35,164,155,139,169,7,0,161,149,129,169,191,12,13,1,161,149,129,169,191,12,14,1,129,149,129,169,191,12,15,1,161,149,129,169,191,12,12,1,161,149,129,169,191,12,9,1,161,149,129,169,191,12,10,1,129,164,155,139,169,7,2,1,161,164,155,139,169,7,3,1,161,207,228,238,162,8,41,1,161,207,228,238,162,8,42,1,129,188,171,136,250,8,8,1,161,164,155,139,169,7,7,1,161,188,171,136,250,8,6,1,161,188,171,136,250,8,7,1,129,164,155,139,169,7,10,1,161,164,155,139,169,7,11,1,161,149,129,169,191,12,5,1,161,149,129,169,191,12,6,1,129,188,171,136,250,8,17,1,161,164,155,139,169,7,15,1,161,188,171,136,250,8,15,1,161,188,171,136,250,8,16,1,129,164,155,139,169,7,18,1,161,164,155,139,169,7,19,1,161,164,155,139,169,7,16,1,161,164,155,139,169,7,17,1,129,164,155,139,169,7,22,1,161,164,155,139,169,7,23,1,161,164,155,139,169,7,20,1,161,164,155,139,169,7,21,1,129,188,171,136,250,8,20,1,161,164,155,139,169,7,27,1,161,188,171,136,250,8,18,1,161,188,171,136,250,8,19,1,129,164,155,139,169,7,30,1,1,177,219,160,167,7,0,161,135,240,136,178,10,44,4,2,135,193,208,135,7,0,161,135,167,156,250,14,15,12,161,135,193,208,135,7,11,4,17,130,180,254,251,6,0,129,252,163,130,200,6,15,1,161,252,163,130,200,6,16,1,161,252,163,130,200,6,17,1,39,0,203,184,221,173,11,1,36,100,100,98,57,51,98,97,55,45,48,54,99,55,45,52,49,55,54,45,57,56,50,97,45,100,55,52,50,51,101,48,57,98,52,52,49,1,40,0,130,180,254,251,6,3,2,105,100,1,119,36,100,100,98,57,51,98,97,55,45,48,54,99,55,45,52,49,55,54,45,57,56,50,97,45,100,55,52,50,51,101,48,57,98,52,52,49,33,0,130,180,254,251,6,3,4,110,97,109,101,1,33,0,130,180,254,251,6,3,3,98,105,100,1,40,0,130,180,254,251,6,3,4,100,101,115,99,1,119,0,40,0,130,180,254,251,6,3,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,33,0,130,180,254,251,6,3,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,100,100,98,57,51,98,97,55,45,48,54,99,55,45,52,49,55,54,45,57,56,50,97,45,100,55,52,50,51,101,48,57,98,52,52,49,0,40,0,130,180,254,251,6,3,4,105,99,111,110,1,119,0,40,0,130,180,254,251,6,3,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,130,180,254,251,6,3,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,130,180,254,251,6,3,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,2,161,130,180,254,251,6,13,1,168,130,180,254,251,6,5,1,119,5,110,105,115,104,105,27,159,156,204,250,6,0,161,149,249,242,175,4,28,1,161,149,249,242,175,4,29,1,129,149,249,242,175,4,30,1,161,159,156,204,250,6,0,1,161,159,156,204,250,6,1,1,129,159,156,204,250,6,2,1,161,143,184,153,180,6,3,1,161,143,184,153,180,6,4,1,129,143,184,153,180,6,5,1,161,159,156,204,250,6,6,1,161,159,156,204,250,6,7,1,129,159,156,204,250,6,8,1,161,159,156,204,250,6,9,1,161,159,156,204,250,6,10,1,129,159,156,204,250,6,11,1,161,159,156,204,250,6,12,1,161,159,156,204,250,6,13,1,129,159,156,204,250,6,14,1,161,159,156,204,250,6,15,1,161,159,156,204,250,6,16,1,129,159,156,204,250,6,17,1,161,159,156,204,250,6,18,1,161,159,156,204,250,6,19,1,129,159,156,204,250,6,20,1,161,159,156,204,250,6,21,1,161,159,156,204,250,6,22,1,129,159,156,204,250,6,23,1,3,135,166,246,235,6,0,161,245,220,194,52,36,1,161,245,220,194,52,37,1,136,245,220,194,52,32,1,118,2,2,105,100,119,36,48,101,55,99,100,101,102,50,45,49,48,99,50,45,52,52,101,99,45,56,98,54,49,45,49,97,100,101,48,98,102,53,100,51,102,102,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,85,170,119,1,175,205,156,228,6,0,161,183,226,184,158,8,7,10,15,240,149,229,225,6,0,136,203,184,221,173,11,16,1,118,1,2,105,100,119,36,101,48,102,101,54,56,54,55,45,50,48,56,102,45,52,51,57,57,45,97,56,56,97,45,101,57,98,97,102,52,56,97,99,48,53,101,161,158,156,181,152,10,7,1,161,158,156,181,152,10,8,1,39,0,203,184,221,173,11,1,36,101,48,102,101,54,56,54,55,45,50,48,56,102,45,52,51,57,57,45,97,56,56,97,45,101,57,98,97,102,52,56,97,99,48,53,101,1,40,0,240,149,229,225,6,3,2,105,100,1,119,36,101,48,102,101,54,56,54,55,45,50,48,56,102,45,52,51,57,57,45,97,56,56,97,45,101,57,98,97,102,52,56,97,99,48,53,101,40,0,240,149,229,225,6,3,4,110,97,109,101,1,119,0,40,0,240,149,229,225,6,3,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,240,149,229,225,6,3,4,100,101,115,99,1,119,0,40,0,240,149,229,225,6,3,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,240,149,229,225,6,3,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,241,138,214,39,0,203,184,221,173,11,4,36,101,48,102,101,54,56,54,55,45,50,48,56,102,45,52,51,57,57,45,97,56,56,97,45,101,57,98,97,102,52,56,97,99,48,53,101,0,40,0,240,149,229,225,6,3,4,105,99,111,110,1,119,0,40,0,240,149,229,225,6,3,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,240,149,229,225,6,3,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,101,241,138,214,40,0,240,149,229,225,6,3,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,3,255,140,248,220,6,0,161,180,230,210,212,13,4,1,161,180,230,210,212,13,5,1,129,180,230,210,212,13,6,1,1,157,207,243,216,6,0,161,145,190,137,224,10,1,2,30,252,163,130,200,6,0,136,143,131,148,152,6,0,1,118,1,2,105,100,119,36,102,57,101,48,48,54,53,49,45,49,53,48,101,45,52,50,56,56,45,56,48,55,57,45,50,50,100,48,54,97,50,55,54,97,55,49,161,143,131,148,152,6,1,1,161,143,131,148,152,6,2,1,39,0,203,184,221,173,11,1,36,102,57,101,48,48,54,53,49,45,49,53,48,101,45,52,50,56,56,45,56,48,55,57,45,50,50,100,48,54,97,50,55,54,97,55,49,1,40,0,252,163,130,200,6,3,2,105,100,1,119,36,102,57,101,48,48,54,53,49,45,49,53,48,101,45,52,50,56,56,45,56,48,55,57,45,50,50,100,48,54,97,50,55,54,97,55,49,40,0,252,163,130,200,6,3,4,110,97,109,101,1,119,0,40,0,252,163,130,200,6,3,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,252,163,130,200,6,3,4,100,101,115,99,1,119,0,40,0,252,163,130,200,6,3,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,252,163,130,200,6,3,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,241,149,3,39,0,203,184,221,173,11,4,36,102,57,101,48,48,54,53,49,45,49,53,48,101,45,52,50,56,56,45,56,48,55,57,45,50,50,100,48,54,97,50,55,54,97,55,49,0,40,0,252,163,130,200,6,3,4,105,99,111,110,1,119,0,40,0,252,163,130,200,6,3,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,252,163,130,200,6,3,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,101,241,149,3,40,0,252,163,130,200,6,3,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,136,252,163,130,200,6,0,1,118,1,2,105,100,119,36,56,54,54,57,52,102,97,100,45,54,55,52,97,45,52,54,55,52,45,56,52,100,48,45,51,50,99,52,56,54,97,55,55,48,98,52,161,252,163,130,200,6,1,1,161,252,163,130,200,6,2,1,39,0,203,184,221,173,11,1,36,56,54,54,57,52,102,97,100,45,54,55,52,97,45,52,54,55,52,45,56,52,100,48,45,51,50,99,52,56,54,97,55,55,48,98,52,1,40,0,252,163,130,200,6,18,2,105,100,1,119,36,56,54,54,57,52,102,97,100,45,54,55,52,97,45,52,54,55,52,45,56,52,100,48,45,51,50,99,52,56,54,97,55,55,48,98,52,40,0,252,163,130,200,6,18,4,110,97,109,101,1,119,0,40,0,252,163,130,200,6,18,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,252,163,130,200,6,18,4,100,101,115,99,1,119,0,40,0,252,163,130,200,6,18,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,252,163,130,200,6,18,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,241,149,31,39,0,203,184,221,173,11,4,36,56,54,54,57,52,102,97,100,45,54,55,52,97,45,52,54,55,52,45,56,52,100,48,45,51,50,99,52,56,54,97,55,55,48,98,52,0,40,0,252,163,130,200,6,18,4,105,99,111,110,1,119,0,40,0,252,163,130,200,6,18,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,252,163,130,200,6,18,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,101,241,149,31,40,0,252,163,130,200,6,18,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,20,137,226,192,199,6,0,161,170,140,240,234,9,28,1,161,170,140,240,234,9,29,1,129,170,140,240,234,9,30,1,161,213,161,242,209,13,28,1,161,213,161,242,209,13,29,1,129,137,226,192,199,6,2,1,161,170,140,240,234,9,27,1,161,137,226,192,199,6,3,1,161,137,226,192,199,6,4,1,129,137,226,192,199,6,5,1,161,137,226,192,199,6,0,1,161,137,226,192,199,6,1,1,129,137,226,192,199,6,9,1,161,137,226,192,199,6,6,1,161,137,226,192,199,6,10,1,161,137,226,192,199,6,11,1,129,137,226,192,199,6,12,1,161,137,226,192,199,6,14,1,161,137,226,192,199,6,15,1,129,137,226,192,199,6,16,1,3,246,185,174,192,6,0,161,135,193,208,135,7,11,1,161,135,193,208,135,7,15,87,161,246,185,174,192,6,87,2,2,196,154,250,183,6,0,161,149,161,132,184,14,218,2,1,161,149,161,132,184,14,220,2,61,6,143,184,153,180,6,0,161,164,188,201,172,1,0,1,161,164,188,201,172,1,1,1,129,164,188,201,172,1,2,1,161,143,184,153,180,6,0,1,161,143,184,153,180,6,1,1,129,143,184,153,180,6,2,1,1,198,189,216,175,6,0,161,234,187,164,181,1,23,23,1,153,130,203,161,6,0,161,248,210,237,129,13,1,97,15,143,131,148,152,6,0,136,243,239,182,181,13,15,1,118,1,2,105,100,119,36,50,57,55,48,52,49,52,101,45,99,99,50,48,45,52,51,50,102,45,97,100,49,54,45,52,50,101,99,55,49,55,51,54,100,53,57,161,243,239,182,181,13,16,1,161,243,239,182,181,13,17,1,39,0,203,184,221,173,11,1,36,50,57,55,48,52,49,52,101,45,99,99,50,48,45,52,51,50,102,45,97,100,49,54,45,52,50,101,99,55,49,55,51,54,100,53,57,1,40,0,143,131,148,152,6,3,2,105,100,1,119,36,50,57,55,48,52,49,52,101,45,99,99,50,48,45,52,51,50,102,45,97,100,49,54,45,52,50,101,99,55,49,55,51,54,100,53,57,40,0,143,131,148,152,6,3,4,110,97,109,101,1,119,0,40,0,143,131,148,152,6,3,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,143,131,148,152,6,3,4,100,101,115,99,1,119,0,40,0,143,131,148,152,6,3,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,143,131,148,152,6,3,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,241,143,252,39,0,203,184,221,173,11,4,36,50,57,55,48,52,49,52,101,45,99,99,50,48,45,52,51,50,102,45,97,100,49,54,45,52,50,101,99,55,49,55,51,54,100,53,57,0,40,0,143,131,148,152,6,3,4,105,99,111,110,1,119,0,40,0,143,131,148,152,6,3,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,143,131,148,152,6,3,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,101,241,143,252,40,0,143,131,148,152,6,3,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,1,188,237,223,145,6,0,161,221,147,167,147,15,176,2,26,165,1,140,152,206,145,6,0,161,154,244,246,165,8,180,1,1,161,154,244,246,165,8,181,1,1,129,154,244,246,165,8,182,1,1,161,140,152,206,145,6,0,1,161,140,152,206,145,6,1,1,129,140,152,206,145,6,2,1,161,140,152,206,145,6,3,1,161,140,152,206,145,6,4,1,129,140,152,206,145,6,5,1,161,154,244,246,165,8,159,1,1,161,154,244,246,165,8,160,1,1,129,140,152,206,145,6,8,1,161,154,244,246,165,8,179,1,1,161,140,152,206,145,6,9,1,161,140,152,206,145,6,10,1,129,140,152,206,145,6,11,1,161,140,152,206,145,6,12,1,161,140,152,206,145,6,6,1,161,140,152,206,145,6,7,1,129,140,152,206,145,6,15,1,161,140,152,206,145,6,17,1,161,140,152,206,145,6,18,1,129,140,152,206,145,6,19,1,161,140,152,206,145,6,20,1,161,140,152,206,145,6,21,1,129,140,152,206,145,6,22,1,161,154,244,246,165,8,166,1,1,161,154,244,246,165,8,167,1,1,129,140,152,206,145,6,25,1,161,140,152,206,145,6,16,1,161,140,152,206,145,6,26,1,161,140,152,206,145,6,27,1,129,140,152,206,145,6,28,1,161,154,244,246,165,8,173,1,1,161,154,244,246,165,8,174,1,1,129,140,152,206,145,6,32,1,161,140,152,206,145,6,29,1,161,140,152,206,145,6,33,1,161,140,152,206,145,6,34,1,129,140,152,206,145,6,35,1,161,140,152,206,145,6,13,1,161,140,152,206,145,6,14,1,129,140,152,206,145,6,39,1,161,140,152,206,145,6,36,1,161,140,152,206,145,6,40,1,161,140,152,206,145,6,41,1,129,140,152,206,145,6,42,1,161,140,152,206,145,6,43,1,161,140,152,206,145,6,23,1,161,140,152,206,145,6,24,1,129,140,152,206,145,6,46,1,161,140,152,206,145,6,48,1,161,140,152,206,145,6,49,1,129,140,152,206,145,6,50,1,161,140,152,206,145,6,44,1,161,140,152,206,145,6,45,1,129,140,152,206,145,6,53,1,161,140,152,206,145,6,47,1,161,140,152,206,145,6,54,1,161,140,152,206,145,6,55,1,136,140,152,206,145,6,56,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,230,246,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,161,140,152,206,145,6,51,1,161,140,152,206,145,6,52,1,129,140,152,206,145,6,60,1,161,140,152,206,145,6,57,1,161,140,152,206,145,6,61,1,161,140,152,206,145,6,62,1,129,140,152,206,145,6,63,1,161,140,152,206,145,6,65,1,161,140,152,206,145,6,66,1,161,149,249,242,175,4,2,1,161,140,152,206,145,6,68,1,161,140,152,206,145,6,69,1,161,140,152,206,145,6,70,1,161,140,152,206,145,6,71,1,161,140,152,206,145,6,72,1,161,140,152,206,145,6,73,1,161,140,152,206,145,6,74,1,161,140,152,206,145,6,75,1,161,140,152,206,145,6,76,1,161,140,152,206,145,6,77,1,161,140,152,206,145,6,78,1,161,140,152,206,145,6,79,1,161,140,152,206,145,6,58,1,161,140,152,206,145,6,59,1,136,140,152,206,145,6,67,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,241,108,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,161,140,152,206,145,6,64,1,161,140,152,206,145,6,83,1,161,140,152,206,145,6,84,1,136,140,152,206,145,6,85,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,241,109,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,161,140,152,206,145,6,86,1,161,140,152,206,145,6,80,1,161,140,152,206,145,6,81,1,129,140,152,206,145,6,89,1,161,140,152,206,145,6,91,1,161,140,152,206,145,6,92,1,136,140,152,206,145,6,93,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,241,111,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,161,140,152,206,145,6,94,1,161,140,152,206,145,6,95,1,161,140,152,206,145,6,82,1,136,241,155,213,233,1,6,1,118,1,2,105,100,119,36,48,101,55,99,100,101,102,50,45,49,48,99,50,45,52,52,101,99,45,56,98,54,49,45,49,97,100,101,48,98,102,53,100,51,102,102,161,241,155,213,233,1,7,1,161,140,152,206,145,6,98,1,39,0,203,184,221,173,11,1,36,48,101,55,99,100,101,102,50,45,49,48,99,50,45,52,52,101,99,45,56,98,54,49,45,49,97,100,101,48,98,102,53,100,51,102,102,1,40,0,140,152,206,145,6,103,2,105,100,1,119,36,48,101,55,99,100,101,102,50,45,49,48,99,50,45,52,52,101,99,45,56,98,54,49,45,49,97,100,101,48,98,102,53,100,51,102,102,33,0,140,152,206,145,6,103,4,110,97,109,101,1,40,0,140,152,206,145,6,103,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,140,152,206,145,6,103,4,100,101,115,99,1,119,0,40,0,140,152,206,145,6,103,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,140,152,206,145,6,103,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,83,241,173,39,0,203,184,221,173,11,4,36,48,101,55,99,100,101,102,50,45,49,48,99,50,45,52,52,101,99,45,56,98,54,49,45,49,97,100,101,48,98,102,53,100,51,102,102,0,33,0,140,152,206,145,6,103,4,105,99,111,110,1,40,0,140,152,206,145,6,103,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,140,152,206,145,6,103,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,140,152,206,145,6,103,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,140,152,206,145,6,90,1,161,140,152,206,145,6,114,1,161,140,152,206,145,6,113,1,129,140,152,206,145,6,96,1,161,140,152,206,145,6,116,1,161,140,152,206,145,6,117,1,129,140,152,206,145,6,118,1,161,140,152,206,145,6,119,1,161,140,152,206,145,6,120,1,33,0,140,152,206,145,6,103,5,101,120,116,114,97,1,161,140,152,206,145,6,122,1,161,140,152,206,145,6,123,1,129,140,152,206,145,6,121,1,161,140,152,206,145,6,125,1,161,140,152,206,145,6,126,1,161,140,152,206,145,6,105,1,161,140,152,206,145,6,128,1,1,161,140,152,206,145,6,129,1,1,168,140,152,206,145,6,130,1,1,119,2,104,105,161,140,152,206,145,6,131,1,1,161,140,152,206,145,6,132,1,1,161,140,152,206,145,6,124,1,161,140,152,206,145,6,134,1,1,161,140,152,206,145,6,135,1,1,161,140,152,206,145,6,136,1,1,161,140,152,206,145,6,137,1,1,161,140,152,206,145,6,138,1,1,161,140,152,206,145,6,139,1,1,161,140,152,206,145,6,140,1,1,161,140,152,206,145,6,141,1,1,161,140,152,206,145,6,142,1,1,161,140,152,206,145,6,143,1,1,161,140,152,206,145,6,144,1,1,161,140,152,206,145,6,145,1,1,161,140,152,206,145,6,146,1,1,161,140,152,206,145,6,147,1,1,161,140,152,206,145,6,148,1,1,161,140,152,206,145,6,149,1,1,161,140,152,206,145,6,150,1,1,168,140,152,206,145,6,111,1,119,23,123,34,116,121,34,58,48,44,34,118,97,108,117,101,34,58,34,240,159,154,184,34,125,161,140,152,206,145,6,97,1,161,140,152,206,145,6,102,1,136,140,152,206,145,6,127,1,118,2,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,244,231,161,140,152,206,145,6,115,1,161,140,152,206,145,6,155,1,1,161,140,152,206,145,6,156,1,1,136,140,152,206,145,6,157,1,1,118,2,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,244,231,161,140,152,206,145,6,159,1,1,161,140,152,206,145,6,160,1,1,168,140,152,206,145,6,99,1,119,225,1,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,117,110,115,112,108,97,115,104,34,44,34,118,97,108,117,101,34,58,34,104,116,116,112,115,58,47,47,105,109,97,103,101,115,46,117,110,115,112,108,97,115,104,46,99,111,109,47,112,104,111,116,111,45,49,55,49,52,53,48,56,56,54,50,55,56,56,45,52,52,101,52,53,99,52,51,49,53,100,48,63,99,114,111,112,61,101,110,116,114,111,112,121,38,99,115,61,116,105,110,121,115,114,103,98,38,102,105,116,61,109,97,120,38,102,109,61,106,112,103,38,105,120,105,100,61,77,51,119,49,77,84,69,49,77,122,100,56,77,72,119,120,102,72,74,104,98,109,82,118,98,88,120,56,102,72,120,56,102,72,120,56,102,68,69,51,77,84,89,51,78,122,103,121,77,84,108,56,38,105,120,108,105,98,61,114,98,45,52,46,48,46,51,38,113,61,56,48,38,119,61,49,48,56,48,34,125,125,1,219,227,140,137,6,0,161,140,228,230,243,1,1,34,1,235,178,165,206,5,0,161,255,255,147,249,10,2,72,3,182,172,247,194,5,0,161,245,220,194,52,30,1,161,245,220,194,52,31,1,129,245,220,194,52,32,1,1,145,144,146,185,5,0,161,175,205,156,228,6,9,12,3,160,192,253,131,5,0,161,195,242,227,194,8,0,1,161,195,242,227,194,8,1,1,129,195,242,227,194,8,2,1,1,200,142,208,241,4,0,161,196,154,250,183,6,61,157,1,1,154,235,215,240,4,0,161,173,187,245,170,14,45,13,1,211,166,203,229,4,0,161,234,182,182,157,9,7,195,1,1,141,171,170,217,4,0,161,191,157,147,233,9,31,2,84,201,129,238,197,4,0,161,161,178,132,150,11,34,1,161,161,178,132,150,11,35,1,129,173,252,148,184,13,51,1,161,133,159,138,205,12,49,1,161,133,159,138,205,12,50,1,129,133,159,138,205,12,77,1,168,201,129,238,197,4,3,1,122,4,56,115,160,190,64,16,0,168,201,129,238,197,4,4,1,122,0,0,0,0,102,48,111,8,136,201,129,238,197,4,5,1,118,2,2,105,100,119,36,98,54,51,52,55,97,99,98,45,51,49,55,52,45,52,102,48,101,45,57,56,101,57,45,100,99,99,101,48,55,101,53,100,98,102,55,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,48,111,8,161,133,159,138,205,12,45,1,161,133,159,138,205,12,46,1,129,201,129,238,197,4,8,1,161,158,156,181,152,10,21,1,161,244,226,228,149,2,6,1,129,201,129,238,197,4,11,1,161,133,159,138,205,12,81,1,161,133,159,138,205,12,82,1,129,201,129,238,197,4,14,1,161,201,129,238,197,4,15,1,161,201,129,238,197,4,16,1,129,201,129,238,197,4,17,1,161,201,129,238,197,4,18,1,161,201,129,238,197,4,19,1,129,201,129,238,197,4,20,1,161,201,129,238,197,4,21,1,161,201,129,238,197,4,22,1,129,201,129,238,197,4,23,1,161,201,129,238,197,4,24,1,161,201,129,238,197,4,25,1,129,201,129,238,197,4,26,1,161,201,129,238,197,4,27,1,161,201,129,238,197,4,28,1,129,201,129,238,197,4,29,1,161,133,159,138,205,12,90,1,161,133,159,138,205,12,91,1,129,201,129,238,197,4,32,1,161,201,129,238,197,4,33,1,161,201,129,238,197,4,34,1,129,201,129,238,197,4,35,1,161,173,252,148,184,13,53,1,161,173,252,148,184,13,54,1,129,201,129,238,197,4,38,1,8,0,133,159,138,205,12,66,1,118,1,2,105,100,119,36,101,52,49,48,55,52,55,98,45,53,102,50,102,45,52,53,97,48,45,98,50,102,55,45,56,57,48,97,100,51,48,48,49,51,53,53,161,133,159,138,205,12,65,1,161,201,129,238,197,4,37,1,39,0,203,184,221,173,11,1,36,101,52,49,48,55,52,55,98,45,53,102,50,102,45,52,53,97,48,45,98,50,102,55,45,56,57,48,97,100,51,48,48,49,51,53,53,1,40,0,201,129,238,197,4,45,2,105,100,1,119,36,101,52,49,48,55,52,55,98,45,53,102,50,102,45,52,53,97,48,45,98,50,102,55,45,56,57,48,97,100,51,48,48,49,51,53,53,40,0,201,129,238,197,4,45,4,110,97,109,101,1,119,5,66,111,97,114,100,40,0,201,129,238,197,4,45,3,98,105,100,1,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,40,0,201,129,238,197,4,45,4,100,101,115,99,1,119,0,40,0,201,129,238,197,4,45,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,2,33,0,201,129,238,197,4,45,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,101,52,49,48,55,52,55,98,45,53,102,50,102,45,52,53,97,48,45,98,50,102,55,45,56,57,48,97,100,51,48,48,49,51,53,53,0,40,0,201,129,238,197,4,45,4,105,99,111,110,1,119,0,40,0,201,129,238,197,4,45,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,201,129,238,197,4,45,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,201,129,238,197,4,45,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,136,201,129,238,197,4,42,1,118,1,2,105,100,119,36,50,49,52,51,101,57,53,100,45,53,100,99,98,45,52,101,48,102,45,98,98,50,99,45,53,48,57,52,52,101,54,101,48,49,57,102,161,201,129,238,197,4,43,1,161,201,129,238,197,4,44,1,39,0,203,184,221,173,11,1,36,50,49,52,51,101,57,53,100,45,53,100,99,98,45,52,101,48,102,45,98,98,50,99,45,53,48,57,52,52,101,54,101,48,49,57,102,1,40,0,201,129,238,197,4,60,2,105,100,1,119,36,50,49,52,51,101,57,53,100,45,53,100,99,98,45,52,101,48,102,45,98,98,50,99,45,53,48,57,52,52,101,54,101,48,49,57,102,40,0,201,129,238,197,4,60,4,110,97,109,101,1,119,8,67,97,108,101,110,100,97,114,40,0,201,129,238,197,4,60,3,98,105,100,1,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,40,0,201,129,238,197,4,60,4,100,101,115,99,1,119,0,40,0,201,129,238,197,4,60,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,3,33,0,201,129,238,197,4,60,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,50,49,52,51,101,57,53,100,45,53,100,99,98,45,52,101,48,102,45,98,98,50,99,45,53,48,57,52,52,101,54,101,48,49,57,102,0,40,0,201,129,238,197,4,60,4,105,99,111,110,1,119,0,40,0,201,129,238,197,4,60,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,201,129,238,197,4,60,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,201,129,238,197,4,60,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,201,129,238,197,4,36,1,161,201,129,238,197,4,59,1,161,133,159,138,205,12,92,1,161,201,129,238,197,4,72,1,161,201,129,238,197,4,73,1,161,201,129,238,197,4,74,1,161,201,129,238,197,4,75,1,161,201,129,238,197,4,76,1,161,201,129,238,197,4,77,1,161,201,129,238,197,4,78,1,161,201,129,238,197,4,79,1,168,201,129,238,197,4,80,1,119,4,71,114,105,100,1,182,143,233,195,4,0,161,205,149,231,236,11,67,111,1,178,203,205,182,4,0,161,227,209,197,253,2,13,1,31,149,249,242,175,4,0,161,213,161,242,209,13,28,1,161,213,161,242,209,13,29,1,33,0,203,184,221,173,11,23,5,101,120,116,114,97,1,161,149,249,242,175,4,0,1,161,149,249,242,175,4,1,1,129,201,191,159,147,14,2,1,161,133,159,138,205,12,122,1,161,133,159,138,205,12,121,1,136,213,161,242,209,13,26,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,60,201,181,2,105,100,119,36,102,48,99,53,57,57,50,49,45,48,52,101,101,45,52,57,55,49,45,57,57,53,99,45,55,57,98,55,102,100,56,99,48,48,101,50,168,149,249,242,175,4,6,1,122,4,56,115,160,190,64,16,0,168,149,249,242,175,4,7,1,122,0,0,0,0,102,60,201,181,161,133,159,138,205,12,107,1,161,133,159,138,205,12,106,1,136,149,249,242,175,4,8,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,60,201,183,2,105,100,119,36,101,57,55,56,55,55,102,53,45,99,51,54,53,45,52,48,50,53,45,57,101,54,97,45,101,53,57,48,99,52,98,49,57,100,98,98,168,149,249,242,175,4,11,1,122,4,56,115,160,190,64,16,0,168,149,249,242,175,4,12,1,122,0,0,0,0,102,60,201,183,161,201,191,159,147,14,0,1,161,201,191,159,147,14,1,1,129,149,249,242,175,4,5,1,161,149,249,242,175,4,16,1,161,149,249,242,175,4,17,1,129,149,249,242,175,4,18,1,161,149,249,242,175,4,19,1,161,149,249,242,175,4,20,1,129,149,249,242,175,4,21,1,161,149,249,242,175,4,22,1,161,149,249,242,175,4,23,1,129,149,249,242,175,4,24,1,161,149,249,242,175,4,25,1,161,149,249,242,175,4,26,1,129,149,249,242,175,4,27,1,12,163,236,177,169,4,0,161,154,243,157,196,14,9,1,161,154,243,157,196,14,10,1,129,154,243,157,196,14,11,1,161,163,236,177,169,4,0,1,161,163,236,177,169,4,1,1,129,163,236,177,169,4,2,1,161,163,236,177,169,4,3,1,161,163,236,177,169,4,4,1,129,163,236,177,169,4,5,1,161,163,236,177,169,4,6,1,161,163,236,177,169,4,7,1,129,163,236,177,169,4,8,1,73,234,153,236,158,4,0,161,165,139,157,171,15,100,1,161,165,139,157,171,15,101,1,129,165,139,157,171,15,102,1,161,165,139,157,171,15,88,1,161,165,139,157,171,15,89,1,129,234,153,236,158,4,2,1,136,165,139,157,171,15,18,1,118,1,2,105,100,119,36,48,99,101,49,51,52,49,53,45,54,99,99,101,45,52,52,57,55,45,57,52,99,54,45,52,55,53,97,100,57,54,99,50,52,57,101,161,165,139,157,171,15,19,1,161,165,139,157,171,15,20,1,39,0,203,184,221,173,11,1,36,48,99,101,49,51,52,49,53,45,54,99,99,101,45,52,52,57,55,45,57,52,99,54,45,52,55,53,97,100,57,54,99,50,52,57,101,1,40,0,234,153,236,158,4,9,2,105,100,1,119,36,48,99,101,49,51,52,49,53,45,54,99,99,101,45,52,52,57,55,45,57,52,99,54,45,52,55,53,97,100,57,54,99,50,52,57,101,33,0,234,153,236,158,4,9,4,110,97,109,101,1,40,0,234,153,236,158,4,9,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,234,153,236,158,4,9,4,100,101,115,99,1,119,0,40,0,234,153,236,158,4,9,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,2,33,0,234,153,236,158,4,9,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,48,99,101,49,51,52,49,53,45,54,99,99,101,45,52,52,57,55,45,57,52,99,54,45,52,55,53,97,100,57,54,99,50,52,57,101,0,40,0,234,153,236,158,4,9,4,105,99,111,110,1,119,0,40,0,234,153,236,158,4,9,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,234,153,236,158,4,9,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,234,153,236,158,4,9,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,165,139,157,171,15,33,1,161,234,153,236,158,4,20,1,161,234,153,236,158,4,19,1,129,234,153,236,158,4,5,1,8,0,234,153,236,158,4,16,1,118,1,2,105,100,119,36,101,52,99,56,57,52,50,49,45,49,50,98,50,45,52,100,48,50,45,56,54,51,100,45,50,48,57,52,57,101,101,99,57,50,55,49,168,234,153,236,158,4,15,1,122,0,0,0,0,102,76,39,166,161,234,153,236,158,4,23,1,39,0,203,184,221,173,11,1,36,101,52,99,56,57,52,50,49,45,49,50,98,50,45,52,100,48,50,45,56,54,51,100,45,50,48,57,52,57,101,101,99,57,50,55,49,1,40,0,234,153,236,158,4,28,2,105,100,1,119,36,101,52,99,56,57,52,50,49,45,49,50,98,50,45,52,100,48,50,45,56,54,51,100,45,50,48,57,52,57,101,101,99,57,50,55,49,40,0,234,153,236,158,4,28,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,234,153,236,158,4,28,3,98,105,100,1,119,36,48,99,101,49,51,52,49,53,45,54,99,99,101,45,52,52,57,55,45,57,52,99,54,45,52,55,53,97,100,57,54,99,50,52,57,101,40,0,234,153,236,158,4,28,4,100,101,115,99,1,119,0,40,0,234,153,236,158,4,28,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,40,0,234,153,236,158,4,28,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,76,39,166,39,0,203,184,221,173,11,4,36,101,52,99,56,57,52,50,49,45,49,50,98,50,45,52,100,48,50,45,56,54,51,100,45,50,48,57,52,57,101,101,99,57,50,55,49,0,40,0,234,153,236,158,4,28,4,105,99,111,110,1,119,0,40,0,234,153,236,158,4,28,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,234,153,236,158,4,28,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,234,153,236,158,4,28,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,234,153,236,158,4,22,1,161,234,153,236,158,4,27,1,129,234,153,236,158,4,24,1,161,234,153,236,158,4,40,1,161,234,153,236,158,4,41,1,168,234,153,236,158,4,11,1,119,14,99,104,101,99,107,98,111,120,32,98,111,97,114,100,161,234,153,236,158,4,43,1,161,234,153,236,158,4,44,1,129,234,153,236,158,4,42,1,161,234,153,236,158,4,46,1,161,234,153,236,158,4,47,1,129,234,153,236,158,4,48,1,161,234,153,236,158,4,49,1,161,234,153,236,158,4,50,1,129,234,153,236,158,4,51,1,161,165,139,157,171,15,94,1,161,165,139,157,171,15,95,1,129,234,153,236,158,4,54,1,161,234,153,236,158,4,55,1,161,234,153,236,158,4,56,1,129,234,153,236,158,4,57,1,161,234,153,236,158,4,0,1,161,234,153,236,158,4,1,1,129,234,153,236,158,4,60,1,161,234,153,236,158,4,58,1,161,234,153,236,158,4,59,1,129,234,153,236,158,4,63,1,161,234,153,236,158,4,64,1,161,234,153,236,158,4,65,1,129,234,153,236,158,4,66,1,161,234,153,236,158,4,67,1,161,234,153,236,158,4,68,1,129,234,153,236,158,4,69,1,3,141,205,220,149,4,0,161,214,168,149,214,3,12,1,161,214,168,149,214,3,13,1,129,214,168,149,214,3,14,1,17,193,249,142,142,4,0,161,141,216,158,150,1,0,1,161,141,216,158,150,1,1,1,129,141,216,158,150,1,2,1,161,225,248,138,176,2,45,1,161,222,205,223,235,7,21,1,161,225,248,138,176,2,19,1,129,193,249,142,142,4,2,1,161,193,249,142,142,4,4,1,161,193,249,142,142,4,5,1,129,193,249,142,142,4,6,1,161,193,249,142,142,4,0,1,161,193,249,142,142,4,1,1,129,193,249,142,142,4,9,1,161,193,249,142,142,4,3,1,161,193,249,142,142,4,10,1,161,193,249,142,142,4,11,1,129,193,249,142,142,4,12,1,20,206,220,129,131,4,0,161,235,225,184,133,10,0,1,161,235,225,184,133,10,1,1,129,235,225,184,133,10,2,1,72,233,165,139,246,14,7,1,118,1,2,105,100,119,36,99,55,52,55,53,49,50,51,45,56,50,51,57,45,52,98,98,49,45,56,100,102,53,45,54,56,49,52,56,48,102,101,57,53,52,99,161,233,165,139,246,14,8,1,161,233,165,139,246,14,9,1,39,0,203,184,221,173,11,1,36,99,55,52,55,53,49,50,51,45,56,50,51,57,45,52,98,98,49,45,56,100,102,53,45,54,56,49,52,56,48,102,101,57,53,52,99,1,40,0,206,220,129,131,4,6,2,105,100,1,119,36,99,55,52,55,53,49,50,51,45,56,50,51,57,45,52,98,98,49,45,56,100,102,53,45,54,56,49,52,56,48,102,101,57,53,52,99,40,0,206,220,129,131,4,6,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,206,220,129,131,4,6,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,206,220,129,131,4,6,4,100,101,115,99,1,119,0,40,0,206,220,129,131,4,6,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,206,220,129,131,4,6,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,241,122,107,39,0,203,184,221,173,11,4,36,99,55,52,55,53,49,50,51,45,56,50,51,57,45,52,98,98,49,45,56,100,102,53,45,54,56,49,52,56,48,102,101,57,53,52,99,0,40,0,206,220,129,131,4,6,4,105,99,111,110,1,119,0,40,0,206,220,129,131,4,6,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,206,220,129,131,4,6,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,206,220,129,131,4,6,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,2,161,206,220,129,131,4,16,1,129,206,220,129,131,4,2,1,1,128,252,161,128,4,0,161,232,207,157,148,2,1,33,3,169,197,188,221,3,0,161,154,193,208,134,10,3,1,161,154,193,208,134,10,4,1,129,154,193,208,134,10,5,1,15,214,168,149,214,3,0,161,169,197,188,221,3,0,1,161,169,197,188,221,3,1,1,129,169,197,188,221,3,2,1,161,233,247,183,159,1,0,1,161,158,156,181,152,10,3,1,161,158,156,181,152,10,4,1,129,154,193,208,134,10,8,1,161,214,168,149,214,3,3,1,161,154,193,208,134,10,6,1,161,154,193,208,134,10,7,1,129,214,168,149,214,3,6,1,161,214,168,149,214,3,7,1,161,171,204,155,217,8,0,1,161,171,204,155,217,8,1,1,129,214,168,149,214,3,10,1,1,158,184,218,165,3,0,161,139,152,215,249,10,33,38,1,239,199,189,146,3,0,161,154,235,215,240,4,12,24,1,227,209,197,253,2,0,161,181,175,219,209,12,9,14,15,226,212,179,248,2,0,161,214,139,213,136,8,63,1,161,214,139,213,136,8,64,1,129,214,139,213,136,8,65,1,161,226,212,179,248,2,0,1,161,226,212,179,248,2,1,1,129,226,212,179,248,2,2,1,161,226,212,179,248,2,3,1,161,226,212,179,248,2,4,1,129,226,212,179,248,2,5,1,161,193,249,142,142,4,7,1,161,241,155,213,233,1,8,1,129,226,212,179,248,2,8,1,161,226,212,179,248,2,6,1,161,226,212,179,248,2,7,1,129,226,212,179,248,2,11,1,3,157,240,144,231,2,0,161,213,161,242,209,13,32,1,161,213,161,242,209,13,33,1,129,213,161,242,209,13,34,1,1,128,211,179,216,2,0,161,236,229,225,232,8,115,10,1,138,202,240,189,2,0,161,229,153,197,202,7,240,6,134,1,1,200,203,236,184,2,0,161,138,202,240,189,2,133,1,35,49,225,248,138,176,2,0,161,171,142,166,254,1,3,1,161,171,142,166,254,1,4,1,129,171,142,166,254,1,5,1,161,222,205,223,235,7,27,1,161,173,252,148,184,13,45,1,161,173,252,148,184,13,46,1,129,225,248,138,176,2,2,1,161,225,248,138,176,2,4,1,161,225,248,138,176,2,5,1,136,225,248,138,176,2,6,1,118,2,2,105,100,119,36,100,100,98,57,51,98,97,55,45,48,54,99,55,45,52,49,55,54,45,57,56,50,97,45,100,55,52,50,51,101,48,57,98,52,52,49,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,68,43,241,161,170,140,240,234,9,7,1,161,170,140,240,234,9,8,1,136,225,248,138,176,2,9,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,68,43,243,2,105,100,119,36,52,56,99,53,50,99,102,55,45,98,102,57,56,45,52,51,102,97,45,57,54,97,100,45,98,51,49,97,97,100,101,57,98,48,55,49,161,225,248,138,176,2,3,1,168,225,248,138,176,2,10,1,122,4,56,115,160,190,64,16,0,168,225,248,138,176,2,11,1,122,0,0,0,0,102,68,43,244,136,225,248,138,176,2,12,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,68,43,244,2,105,100,119,36,52,56,99,53,50,99,102,55,45,98,102,57,56,45,52,51,102,97,45,57,54,97,100,45,98,51,49,97,97,100,101,57,98,48,55,49,136,133,159,138,205,12,56,1,118,1,2,105,100,119,36,50,99,49,101,101,57,53,97,45,49,98,48,57,45,52,97,49,102,45,56,100,53,101,45,53,48,49,98,99,52,56,54,49,97,57,100,161,133,159,138,205,12,57,1,161,222,205,223,235,7,22,1,39,0,203,184,221,173,11,1,36,50,99,49,101,101,57,53,97,45,49,98,48,57,45,52,97,49,102,45,56,100,53,101,45,53,48,49,98,99,52,56,54,49,97,57,100,1,40,0,225,248,138,176,2,20,2,105,100,1,119,36,50,99,49,101,101,57,53,97,45,49,98,48,57,45,52,97,49,102,45,56,100,53,101,45,53,48,49,98,99,52,56,54,49,97,57,100,40,0,225,248,138,176,2,20,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,225,248,138,176,2,20,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,225,248,138,176,2,20,4,100,101,115,99,1,119,0,40,0,225,248,138,176,2,20,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,33,0,225,248,138,176,2,20,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,50,99,49,101,101,57,53,97,45,49,98,48,57,45,52,97,49,102,45,56,100,53,101,45,53,48,49,98,99,52,56,54,49,97,57,100,0,40,0,225,248,138,176,2,20,4,105,99,111,110,1,119,0,40,0,225,248,138,176,2,20,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,225,248,138,176,2,20,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,225,248,138,176,2,20,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,225,248,138,176,2,13,1,161,225,248,138,176,2,31,1,161,225,248,138,176,2,30,1,129,225,248,138,176,2,16,1,161,225,248,138,176,2,33,1,161,225,248,138,176,2,34,1,129,225,248,138,176,2,35,1,161,225,248,138,176,2,36,1,161,225,248,138,176,2,37,1,129,225,248,138,176,2,38,1,161,225,248,138,176,2,0,1,161,225,248,138,176,2,1,1,129,225,248,138,176,2,41,1,161,225,248,138,176,2,32,1,161,225,248,138,176,2,42,1,161,225,248,138,176,2,43,1,129,225,248,138,176,2,44,1,29,244,226,228,149,2,0,39,0,203,184,221,173,11,2,7,112,114,105,118,97,116,101,1,161,158,156,181,152,10,24,1,161,207,228,238,162,8,24,1,129,207,228,238,162,8,49,1,8,0,158,156,181,152,10,16,1,118,1,2,105,100,119,36,48,53,51,51,50,98,97,52,45,97,54,57,48,45,52,50,57,51,45,57,56,54,54,45,56,52,100,97,99,55,102,101,50,97,101,97,168,158,156,181,152,10,15,1,122,0,0,0,0,101,251,252,70,161,158,156,181,152,10,22,1,39,0,203,184,221,173,11,1,36,48,53,51,51,50,98,97,52,45,97,54,57,48,45,52,50,57,51,45,57,56,54,54,45,56,52,100,97,99,55,102,101,50,97,101,97,1,40,0,244,226,228,149,2,7,2,105,100,1,119,36,48,53,51,51,50,98,97,52,45,97,54,57,48,45,52,50,57,51,45,57,56,54,54,45,56,52,100,97,99,55,102,101,50,97,101,97,40,0,244,226,228,149,2,7,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,244,226,228,149,2,7,3,98,105,100,1,119,36,100,49,52,50,51,57,101,57,45,50,98,102,55,45,52,56,50,52,45,57,51,101,99,45,52,102,51,99,99,53,54,49,54,55,50,48,40,0,244,226,228,149,2,7,4,100,101,115,99,1,119,0,40,0,244,226,228,149,2,7,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,40,0,244,226,228,149,2,7,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,101,251,252,70,39,0,203,184,221,173,11,4,36,48,53,51,51,50,98,97,52,45,97,54,57,48,45,52,50,57,51,45,57,56,54,54,45,56,52,100,97,99,55,102,101,50,97,101,97,0,40,0,244,226,228,149,2,7,4,105,99,111,110,1,119,0,40,0,244,226,228,149,2,7,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,244,226,228,149,2,7,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,244,226,228,149,2,7,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,2,161,244,226,228,149,2,17,1,39,0,244,226,228,149,2,0,18,51,48,52,49,50,48,49,48,57,48,55,49,51,51,57,53,50,48,0,8,0,244,226,228,149,2,21,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,101,251,252,70,2,105,100,119,36,48,53,51,51,50,98,97,52,45,97,54,57,48,45,52,50,57,51,45,57,56,54,54,45,56,52,100,97,99,55,102,101,50,97,101,97,161,207,228,238,162,8,37,1,161,244,226,228,149,2,19,1,161,244,226,228,149,2,20,1,129,244,226,228,149,2,3,1,161,244,226,228,149,2,24,1,161,244,226,228,149,2,25,1,129,244,226,228,149,2,26,1,1,232,207,157,148,2,0,161,141,171,170,217,4,1,2,6,171,142,166,254,1,0,161,143,184,153,180,6,3,1,161,143,184,153,180,6,4,1,129,143,184,153,180,6,5,1,161,171,142,166,254,1,0,1,161,171,142,166,254,1,1,1,129,171,142,166,254,1,2,1,1,140,228,230,243,1,0,161,250,198,166,187,7,1,2,3,147,206,229,235,1,0,161,229,154,128,197,12,3,1,161,229,154,128,197,12,4,1,129,162,159,252,196,11,2,1,52,241,155,213,233,1,0,161,234,153,236,158,4,70,1,161,234,153,236,158,4,71,1,129,234,153,236,158,4,72,1,161,234,153,236,158,4,52,1,161,234,153,236,158,4,53,1,129,241,155,213,233,1,2,1,136,234,153,236,158,4,6,1,118,1,2,105,100,119,36,101,101,51,97,101,56,99,101,45,57,53,57,97,45,52,100,102,51,45,56,55,51,52,45,52,48,98,53,51,53,102,102,56,56,101,51,161,234,153,236,158,4,7,1,161,234,153,236,158,4,8,1,39,0,203,184,221,173,11,1,36,101,101,51,97,101,56,99,101,45,57,53,57,97,45,52,100,102,51,45,56,55,51,52,45,52,48,98,53,51,53,102,102,56,56,101,51,1,40,0,241,155,213,233,1,9,2,105,100,1,119,36,101,101,51,97,101,56,99,101,45,57,53,57,97,45,52,100,102,51,45,56,55,51,52,45,52,48,98,53,51,53,102,102,56,56,101,51,33,0,241,155,213,233,1,9,4,110,97,109,101,1,40,0,241,155,213,233,1,9,3,98,105,100,1,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,40,0,241,155,213,233,1,9,4,100,101,115,99,1,119,0,40,0,241,155,213,233,1,9,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,3,33,0,241,155,213,233,1,9,10,99,114,101,97,116,101,100,95,97,116,1,39,0,203,184,221,173,11,4,36,101,101,51,97,101,56,99,101,45,57,53,57,97,45,52,100,102,51,45,56,55,51,52,45,52,48,98,53,51,53,102,102,56,56,101,51,0,40,0,241,155,213,233,1,9,4,105,99,111,110,1,119,0,40,0,241,155,213,233,1,9,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,241,155,213,233,1,9,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,241,155,213,233,1,9,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,234,153,236,158,4,21,1,161,241,155,213,233,1,20,1,161,241,155,213,233,1,19,1,129,241,155,213,233,1,5,1,161,241,155,213,233,1,22,1,161,241,155,213,233,1,23,1,161,241,155,213,233,1,11,1,161,241,155,213,233,1,25,1,161,241,155,213,233,1,26,1,161,241,155,213,233,1,27,1,161,241,155,213,233,1,28,1,161,241,155,213,233,1,29,1,161,241,155,213,233,1,30,1,161,241,155,213,233,1,31,1,161,241,155,213,233,1,32,1,161,241,155,213,233,1,33,1,161,241,155,213,233,1,34,1,161,241,155,213,233,1,35,1,161,241,155,213,233,1,36,1,161,241,155,213,233,1,37,1,161,241,155,213,233,1,38,1,161,241,155,213,233,1,39,1,161,241,155,213,233,1,40,1,161,241,155,213,233,1,41,1,161,241,155,213,233,1,42,1,161,241,155,213,233,1,43,1,161,241,155,213,233,1,44,1,161,241,155,213,233,1,45,1,161,241,155,213,233,1,46,1,161,241,155,213,233,1,47,1,168,241,155,213,233,1,48,1,119,8,67,97,108,101,110,100,97,114,1,240,253,240,229,1,0,161,178,203,205,182,4,0,79,20,176,154,159,227,1,0,33,0,203,184,221,173,11,2,7,112,114,105,118,97,116,101,1,136,130,180,254,251,6,0,1,118,1,2,105,100,119,36,54,53,98,48,54,100,98,56,45,55,48,54,49,45,52,98,102,54,45,98,51,49,53,45,55,53,56,99,48,100,100,50,53,99,100,102,161,130,180,254,251,6,1,1,161,130,180,254,251,6,2,1,39,0,203,184,221,173,11,1,36,54,53,98,48,54,100,98,56,45,55,48,54,49,45,52,98,102,54,45,98,51,49,53,45,55,53,56,99,48,100,100,50,53,99,100,102,1,40,0,176,154,159,227,1,4,2,105,100,1,119,36,54,53,98,48,54,100,98,56,45,55,48,54,49,45,52,98,102,54,45,98,51,49,53,45,55,53,56,99,48,100,100,50,53,99,100,102,40,0,176,154,159,227,1,4,4,110,97,109,101,1,119,0,40,0,176,154,159,227,1,4,3,98,105,100,1,119,36,57,101,101,98,101,97,48,51,45,51,101,100,53,45,52,50,57,56,45,56,54,98,50,45,97,55,102,55,55,56,53,54,100,52,56,98,40,0,176,154,159,227,1,4,4,100,101,115,99,1,119,0,40,0,176,154,159,227,1,4,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,176,154,159,227,1,4,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,12,194,112,39,0,203,184,221,173,11,4,36,54,53,98,48,54,100,98,56,45,55,48,54,49,45,52,98,102,54,45,98,51,49,53,45,55,53,56,99,48,100,100,50,53,99,100,102,0,40,0,176,154,159,227,1,4,4,105,99,111,110,1,119,0,40,0,176,154,159,227,1,4,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,176,154,159,227,1,4,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,176,154,159,227,1,4,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,161,207,228,238,162,8,37,1,161,176,154,159,227,1,15,1,161,176,154,159,227,1,14,1,129,207,228,238,162,8,49,1,2,175,147,217,214,1,0,161,246,185,174,192,6,87,1,161,246,185,174,192,6,89,32,6,202,160,246,212,1,0,161,178,162,190,217,10,0,1,161,178,162,190,217,10,1,1,161,178,162,190,217,10,2,1,161,202,160,246,212,1,0,1,161,202,160,246,212,1,1,1,161,202,160,246,212,1,2,1,39,137,164,190,210,1,0,168,166,201,221,141,13,69,1,122,4,56,115,160,190,64,16,0,168,166,201,221,141,13,70,1,122,0,0,0,0,102,86,193,57,136,166,201,221,141,13,71,1,118,2,2,105,100,119,36,50,97,54,101,53,101,50,49,45,97,57,51,56,45,52,53,97,53,45,97,52,52,53,45,100,48,98,55,49,52,57,53,98,48,55,55,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,86,193,57,161,174,151,139,93,254,1,1,161,174,151,139,93,255,1,1,136,162,238,198,212,7,2,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,87,240,30,2,105,100,119,36,101,52,49,48,55,52,55,98,45,53,102,50,102,45,52,53,97,48,45,98,50,102,55,45,56,57,48,97,100,51,48,48,49,51,53,53,161,247,200,243,247,14,15,1,168,137,164,190,210,1,3,1,122,4,56,115,160,190,64,16,0,168,137,164,190,210,1,4,1,122,0,0,0,0,102,87,240,30,136,137,164,190,210,1,5,1,118,2,2,105,100,119,36,101,52,49,48,55,52,55,98,45,53,102,50,102,45,52,53,97,48,45,98,50,102,55,45,56,57,48,97,100,51,48,48,49,51,53,53,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,87,240,30,39,0,203,184,221,173,11,1,36,48,51,50,55,98,54,57,52,45,50,100,101,51,45,53,101,48,48,45,98,51,54,56,45,57,56,99,97,49,56,50,51,48,102,97,57,1,40,0,137,164,190,210,1,10,2,105,100,1,119,36,48,51,50,55,98,54,57,52,45,50,100,101,51,45,53,101,48,48,45,98,51,54,56,45,57,56,99,97,49,56,50,51,48,102,97,57,40,0,137,164,190,210,1,10,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,137,164,190,210,1,10,3,98,105,100,1,119,36,48,51,50,55,98,54,57,52,45,50,100,101,51,45,53,101,48,48,45,98,51,54,56,45,57,56,99,97,49,56,50,51,48,102,97,57,40,0,137,164,190,210,1,10,4,100,101,115,99,1,119,0,40,0,137,164,190,210,1,10,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,137,164,190,210,1,10,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,87,240,32,39,0,203,184,221,173,11,4,36,48,51,50,55,98,54,57,52,45,50,100,101,51,45,53,101,48,48,45,98,51,54,56,45,57,56,99,97,49,56,50,51,48,102,97,57,0,40,0,137,164,190,210,1,10,4,105,99,111,110,1,119,0,40,0,137,164,190,210,1,10,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,137,164,190,210,1,10,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,137,164,190,210,1,10,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,168,137,164,190,210,1,21,1,122,4,56,115,160,190,64,16,0,168,137,164,190,210,1,20,1,122,0,0,0,0,102,87,240,32,40,0,137,164,190,210,1,10,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,161,137,164,190,210,1,6,1,161,166,201,221,141,13,13,1,161,166,201,221,141,13,14,1,136,137,164,190,210,1,9,1,118,2,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,88,24,223,161,137,164,190,210,1,26,1,161,137,164,190,210,1,27,1,136,137,164,190,210,1,28,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,88,24,223,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,161,162,238,198,212,7,0,1,161,162,238,198,212,7,1,1,136,137,164,190,210,1,31,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,88,31,80,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,161,137,164,190,210,1,25,1,161,137,164,190,210,1,32,1,161,137,164,190,210,1,33,1,136,137,164,190,210,1,34,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,88,31,80,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,1,152,252,186,192,1,0,161,211,166,203,229,4,194,1,2,3,248,136,168,181,1,0,161,197,254,154,201,10,0,1,161,197,254,154,201,10,1,1,129,197,254,154,201,10,2,1,1,234,187,164,181,1,0,161,253,205,145,137,11,5,24,3,164,188,201,172,1,0,161,222,205,223,235,7,28,1,161,222,205,223,235,7,29,1,129,222,205,223,235,7,30,1,4,233,247,183,159,1,0,161,244,226,228,149,2,23,1,161,248,153,216,10,0,1,161,248,153,216,10,1,1,129,187,173,214,176,15,2,1,1,190,139,191,155,1,0,161,157,207,243,216,6,1,2,3,141,216,158,150,1,0,161,225,248,138,176,2,46,1,161,225,248,138,176,2,47,1,129,225,248,138,176,2,48,1,1,213,255,156,145,1,0,161,177,219,160,167,7,3,2,38,170,255,211,105,0,161,140,152,206,145,6,162,1,1,161,140,152,206,145,6,163,1,1,136,140,152,206,145,6,161,1,1,118,2,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,246,42,161,245,220,194,52,3,1,161,245,220,194,52,4,1,129,245,220,194,52,11,1,161,140,152,206,145,6,158,1,1,161,170,255,211,105,3,1,161,170,255,211,105,4,1,129,170,255,211,105,5,1,161,140,152,206,145,6,37,1,161,140,152,206,145,6,38,1,129,170,255,211,105,9,1,161,170,255,211,105,6,1,161,170,255,211,105,10,1,161,170,255,211,105,11,1,129,170,255,211,105,12,1,161,245,220,194,52,18,1,161,245,220,194,52,19,1,129,170,255,211,105,16,1,161,170,255,211,105,13,1,161,170,255,211,105,17,1,161,170,255,211,105,18,1,129,170,255,211,105,19,1,161,170,255,211,105,14,1,161,170,255,211,105,15,1,129,170,255,211,105,23,1,161,170,255,211,105,20,1,168,170,255,211,105,24,1,122,4,56,115,160,190,64,16,0,168,170,255,211,105,25,1,122,0,0,0,0,102,83,252,197,136,170,255,211,105,26,1,118,2,2,105,100,119,36,101,101,51,97,101,56,99,101,45,57,53,57,97,45,52,100,102,51,45,56,55,51,52,45,52,48,98,53,51,53,102,102,56,56,101,51,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,252,197,161,245,220,194,52,24,1,161,245,220,194,52,25,1,129,170,255,211,105,30,1,161,170,255,211,105,27,1,161,170,255,211,105,31,1,161,170,255,211,105,32,1,129,170,255,211,105,33,1,179,2,174,151,139,93,0,161,177,161,136,243,11,7,1,161,177,161,136,243,11,8,1,129,177,161,136,243,11,9,1,161,177,161,136,243,11,0,1,161,177,161,136,243,11,1,1,129,174,151,139,93,2,1,161,177,161,136,243,11,6,1,161,174,151,139,93,3,1,161,174,151,139,93,4,1,129,174,151,139,93,5,1,161,165,139,157,171,15,14,1,161,165,139,157,171,15,13,1,129,174,151,139,93,9,1,161,174,151,139,93,6,1,161,174,151,139,93,10,1,161,174,151,139,93,11,1,129,174,151,139,93,12,1,161,174,151,139,93,13,1,161,174,151,139,93,7,1,161,174,151,139,93,8,1,129,174,151,139,93,16,1,161,174,151,139,93,18,1,161,174,151,139,93,19,1,129,174,151,139,93,20,1,161,241,155,213,233,1,3,1,161,241,155,213,233,1,4,1,129,174,151,139,93,23,1,161,174,151,139,93,17,1,161,174,151,139,93,24,1,161,174,151,139,93,25,1,129,174,151,139,93,26,1,161,174,151,139,93,21,1,161,174,151,139,93,22,1,129,174,151,139,93,30,1,161,174,151,139,93,27,1,161,174,151,139,93,31,1,161,174,151,139,93,32,1,129,174,151,139,93,33,1,161,174,151,139,93,0,1,161,174,151,139,93,1,1,129,174,151,139,93,37,1,161,174,151,139,93,34,1,161,174,151,139,93,38,1,161,174,151,139,93,39,1,129,174,151,139,93,40,1,39,0,203,184,221,173,11,1,36,102,53,54,98,100,102,48,102,45,57,48,99,56,45,53,51,102,98,45,57,55,100,57,45,97,100,53,56,54,48,100,50,98,55,97,48,1,40,0,174,151,139,93,45,2,105,100,1,119,36,102,53,54,98,100,102,48,102,45,57,48,99,56,45,53,51,102,98,45,57,55,100,57,45,97,100,53,56,54,48,100,50,98,55,97,48,40,0,174,151,139,93,45,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,174,151,139,93,45,3,98,105,100,1,119,36,102,53,54,98,100,102,48,102,45,57,48,99,56,45,53,51,102,98,45,57,55,100,57,45,97,100,53,56,54,48,100,50,98,55,97,48,40,0,174,151,139,93,45,4,100,101,115,99,1,119,0,40,0,174,151,139,93,45,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,174,151,139,93,45,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,77,101,46,39,0,203,184,221,173,11,4,36,102,53,54,98,100,102,48,102,45,57,48,99,56,45,53,51,102,98,45,57,55,100,57,45,97,100,53,56,54,48,100,50,98,55,97,48,0,40,0,174,151,139,93,45,4,105,99,111,110,1,119,0,40,0,174,151,139,93,45,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,174,151,139,93,45,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,174,151,139,93,45,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,168,174,151,139,93,56,1,122,4,56,115,160,190,64,16,0,168,174,151,139,93,55,1,122,0,0,0,0,102,77,101,47,40,0,174,151,139,93,45,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,161,174,151,139,93,42,1,161,174,151,139,93,43,1,129,174,151,139,93,44,1,161,174,151,139,93,60,1,161,174,151,139,93,61,1,129,174,151,139,93,62,1,161,234,153,236,158,4,61,1,161,234,153,236,158,4,62,1,129,174,151,139,93,65,1,161,174,151,139,93,41,1,161,174,151,139,93,66,1,161,174,151,139,93,67,1,129,174,151,139,93,68,1,161,174,151,139,93,63,1,161,174,151,139,93,64,1,129,174,151,139,93,72,1,161,174,151,139,93,69,1,161,174,151,139,93,73,1,161,174,151,139,93,74,1,129,174,151,139,93,75,1,161,174,151,139,93,70,1,161,174,151,139,93,71,1,129,174,151,139,93,79,1,161,174,151,139,93,76,1,161,174,151,139,93,80,1,161,174,151,139,93,81,1,129,174,151,139,93,82,1,161,174,151,139,93,83,1,161,174,151,139,93,28,1,161,174,151,139,93,29,1,129,174,151,139,93,86,1,161,174,151,139,93,87,1,161,201,129,238,197,4,71,1,161,201,129,238,197,4,70,1,129,174,151,139,93,90,1,161,174,151,139,93,88,1,161,174,151,139,93,89,1,129,174,151,139,93,94,1,161,174,151,139,93,91,1,161,174,151,139,93,35,1,161,174,151,139,93,36,1,129,174,151,139,93,97,1,161,174,151,139,93,99,1,161,174,151,139,93,100,1,129,174,151,139,93,101,1,161,174,151,139,93,92,1,161,174,151,139,93,93,1,129,174,151,139,93,104,1,161,174,151,139,93,102,1,161,174,151,139,93,103,1,129,174,151,139,93,107,1,161,174,151,139,93,108,1,161,174,151,139,93,109,1,129,174,151,139,93,110,1,39,0,203,184,221,173,11,1,36,50,49,97,100,55,99,57,48,45,98,102,53,57,45,53,100,97,56,45,57,97,98,99,45,53,98,50,50,102,56,102,102,54,99,52,101,1,40,0,174,151,139,93,114,2,105,100,1,119,36,50,49,97,100,55,99,57,48,45,98,102,53,57,45,53,100,97,56,45,57,97,98,99,45,53,98,50,50,102,56,102,102,54,99,52,101,40,0,174,151,139,93,114,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,174,151,139,93,114,3,98,105,100,1,119,36,50,49,97,100,55,99,57,48,45,98,102,53,57,45,53,100,97,56,45,57,97,98,99,45,53,98,50,50,102,56,102,102,54,99,52,101,40,0,174,151,139,93,114,4,100,101,115,99,1,119,0,40,0,174,151,139,93,114,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,174,151,139,93,114,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,77,101,175,39,0,203,184,221,173,11,4,36,50,49,97,100,55,99,57,48,45,98,102,53,57,45,53,100,97,56,45,57,97,98,99,45,53,98,50,50,102,56,102,102,54,99,52,101,0,40,0,174,151,139,93,114,4,105,99,111,110,1,119,0,40,0,174,151,139,93,114,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,174,151,139,93,114,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,174,151,139,93,114,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,168,174,151,139,93,125,1,122,4,56,115,160,190,64,16,0,168,174,151,139,93,124,1,122,0,0,0,0,102,77,101,175,40,0,174,151,139,93,114,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,161,174,151,139,93,111,1,161,174,151,139,93,112,1,129,174,151,139,93,113,1,161,174,151,139,93,129,1,1,161,174,151,139,93,130,1,1,129,174,151,139,93,131,1,1,161,174,151,139,93,77,1,161,174,151,139,93,78,1,129,174,151,139,93,134,1,1,161,174,151,139,93,98,1,161,174,151,139,93,135,1,1,161,174,151,139,93,136,1,1,129,174,151,139,93,137,1,1,161,174,151,139,93,132,1,1,161,174,151,139,93,133,1,1,129,174,151,139,93,141,1,1,161,174,151,139,93,138,1,1,161,174,151,139,93,142,1,1,161,174,151,139,93,143,1,1,129,174,151,139,93,144,1,1,161,174,151,139,93,95,1,161,174,151,139,93,96,1,129,174,151,139,93,148,1,1,161,174,151,139,93,145,1,1,161,174,151,139,93,149,1,1,161,174,151,139,93,150,1,1,129,174,151,139,93,151,1,1,161,174,151,139,93,146,1,1,161,174,151,139,93,147,1,1,129,174,151,139,93,155,1,1,161,174,151,139,93,152,1,1,161,174,151,139,93,156,1,1,161,174,151,139,93,157,1,1,129,174,151,139,93,158,1,1,161,174,151,139,93,139,1,1,161,174,151,139,93,140,1,1,129,174,151,139,93,162,1,1,161,174,151,139,93,159,1,1,161,174,151,139,93,163,1,1,161,174,151,139,93,164,1,1,129,174,151,139,93,165,1,1,161,174,151,139,93,160,1,1,161,174,151,139,93,161,1,1,129,174,151,139,93,169,1,1,161,174,151,139,93,166,1,1,161,174,151,139,93,170,1,1,161,174,151,139,93,171,1,1,129,174,151,139,93,172,1,1,8,0,241,155,213,233,1,16,1,118,1,2,105,100,119,36,54,54,97,54,102,51,98,99,45,99,55,56,102,45,52,102,55,52,45,97,48,57,101,45,48,56,100,52,55,49,55,98,102,49,102,100,161,241,155,213,233,1,15,1,161,174,151,139,93,175,1,1,39,0,203,184,221,173,11,1,36,54,54,97,54,102,51,98,99,45,99,55,56,102,45,52,102,55,52,45,97,48,57,101,45,48,56,100,52,55,49,55,98,102,49,102,100,1,40,0,174,151,139,93,180,1,2,105,100,1,119,36,54,54,97,54,102,51,98,99,45,99,55,56,102,45,52,102,55,52,45,97,48,57,101,45,48,56,100,52,55,49,55,98,102,49,102,100,40,0,174,151,139,93,180,1,4,110,97,109,101,1,119,4,71,114,105,100,40,0,174,151,139,93,180,1,3,98,105,100,1,119,36,101,101,51,97,101,56,99,101,45,57,53,57,97,45,52,100,102,51,45,56,55,51,52,45,52,48,98,53,51,53,102,102,56,56,101,51,40,0,174,151,139,93,180,1,4,100,101,115,99,1,119,0,40,0,174,151,139,93,180,1,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,1,40,0,174,151,139,93,180,1,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,77,165,65,39,0,203,184,221,173,11,4,36,54,54,97,54,102,51,98,99,45,99,55,56,102,45,52,102,55,52,45,97,48,57,101,45,48,56,100,52,55,49,55,98,102,49,102,100,0,40,0,174,151,139,93,180,1,4,105,99,111,110,1,119,0,40,0,174,151,139,93,180,1,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,40,0,174,151,139,93,180,1,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,122,0,0,0,0,102,77,165,65,40,0,174,151,139,93,180,1,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,39,0,203,184,221,173,11,1,36,49,102,98,50,53,48,49,57,45,52,51,57,52,45,53,57,54,53,45,97,49,50,98,45,49,98,48,101,52,99,57,55,55,48,55,99,1,40,0,174,151,139,93,192,1,2,105,100,1,119,36,49,102,98,50,53,48,49,57,45,52,51,57,52,45,53,57,54,53,45,97,49,50,98,45,49,98,48,101,52,99,57,55,55,48,55,99,40,0,174,151,139,93,192,1,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,174,151,139,93,192,1,3,98,105,100,1,119,36,49,102,98,50,53,48,49,57,45,52,51,57,52,45,53,57,54,53,45,97,49,50,98,45,49,98,48,101,52,99,57,55,55,48,55,99,40,0,174,151,139,93,192,1,4,100,101,115,99,1,119,0,40,0,174,151,139,93,192,1,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,174,151,139,93,192,1,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,77,166,20,39,0,203,184,221,173,11,4,36,49,102,98,50,53,48,49,57,45,52,51,57,52,45,53,57,54,53,45,97,49,50,98,45,49,98,48,101,52,99,57,55,55,48,55,99,0,40,0,174,151,139,93,192,1,4,105,99,111,110,1,119,0,40,0,174,151,139,93,192,1,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,174,151,139,93,192,1,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,174,151,139,93,192,1,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,168,174,151,139,93,203,1,1,122,4,56,115,160,190,64,16,0,168,174,151,139,93,202,1,1,122,0,0,0,0,102,77,166,20,40,0,174,151,139,93,192,1,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,39,0,203,184,221,173,11,1,36,54,97,102,100,54,57,56,52,45,48,51,98,52,45,53,53,57,100,45,98,49,52,54,45,52,49,100,98,97,54,49,50,49,48,98,56,1,40,0,174,151,139,93,207,1,2,105,100,1,119,36,54,97,102,100,54,57,56,52,45,48,51,98,52,45,53,53,57,100,45,98,49,52,54,45,52,49,100,98,97,54,49,50,49,48,98,56,40,0,174,151,139,93,207,1,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,174,151,139,93,207,1,3,98,105,100,1,119,36,54,97,102,100,54,57,56,52,45,48,51,98,52,45,53,53,57,100,45,98,49,52,54,45,52,49,100,98,97,54,49,50,49,48,98,56,40,0,174,151,139,93,207,1,4,100,101,115,99,1,119,0,40,0,174,151,139,93,207,1,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,174,151,139,93,207,1,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,77,183,211,39,0,203,184,221,173,11,4,36,54,97,102,100,54,57,56,52,45,48,51,98,52,45,53,53,57,100,45,98,49,52,54,45,52,49,100,98,97,54,49,50,49,48,98,56,0,40,0,174,151,139,93,207,1,4,105,99,111,110,1,119,0,40,0,174,151,139,93,207,1,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,174,151,139,93,207,1,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,174,151,139,93,207,1,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,168,174,151,139,93,218,1,1,122,4,56,115,160,190,64,16,0,168,174,151,139,93,217,1,1,122,0,0,0,0,102,77,183,211,40,0,174,151,139,93,207,1,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,39,0,203,184,221,173,11,1,36,53,54,53,50,101,52,54,54,45,101,52,99,101,45,53,54,57,99,45,98,49,101,54,45,102,100,56,101,48,101,55,100,99,48,100,99,1,40,0,174,151,139,93,222,1,2,105,100,1,119,36,53,54,53,50,101,52,54,54,45,101,52,99,101,45,53,54,57,99,45,98,49,101,54,45,102,100,56,101,48,101,55,100,99,48,100,99,40,0,174,151,139,93,222,1,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,174,151,139,93,222,1,3,98,105,100,1,119,36,53,54,53,50,101,52,54,54,45,101,52,99,101,45,53,54,57,99,45,98,49,101,54,45,102,100,56,101,48,101,55,100,99,48,100,99,40,0,174,151,139,93,222,1,4,100,101,115,99,1,119,0,40,0,174,151,139,93,222,1,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,174,151,139,93,222,1,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,77,187,249,39,0,203,184,221,173,11,4,36,53,54,53,50,101,52,54,54,45,101,52,99,101,45,53,54,57,99,45,98,49,101,54,45,102,100,56,101,48,101,55,100,99,48,100,99,0,40,0,174,151,139,93,222,1,4,105,99,111,110,1,119,0,40,0,174,151,139,93,222,1,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,174,151,139,93,222,1,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,174,151,139,93,222,1,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,168,174,151,139,93,233,1,1,122,4,56,115,160,190,64,16,0,168,174,151,139,93,232,1,1,122,0,0,0,0,102,77,187,249,40,0,174,151,139,93,222,1,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,161,174,151,139,93,167,1,1,161,174,151,139,93,168,1,1,129,174,151,139,93,176,1,1,161,174,151,139,93,173,1,1,161,174,151,139,93,237,1,1,161,174,151,139,93,238,1,1,129,174,151,139,93,239,1,1,161,174,151,139,93,241,1,1,161,174,151,139,93,242,1,1,129,241,130,161,205,7,11,1,161,174,151,139,93,244,1,1,161,174,151,139,93,245,1,1,129,174,151,139,93,246,1,1,161,241,130,161,205,7,3,1,161,241,130,161,205,7,4,1,129,174,151,139,93,249,1,1,161,174,151,139,93,240,1,1,161,174,151,139,93,250,1,1,161,174,151,139,93,251,1,1,129,174,151,139,93,252,1,1,161,174,151,139,93,247,1,1,161,174,151,139,93,248,1,1,129,174,151,139,93,128,2,1,161,174,151,139,93,253,1,1,161,174,151,139,93,129,2,1,161,174,151,139,93,130,2,1,129,174,151,139,93,131,2,1,161,226,212,179,248,2,9,1,161,226,212,179,248,2,10,1,129,174,151,139,93,135,2,1,161,174,151,139,93,132,2,1,161,174,151,139,93,136,2,1,161,174,151,139,93,137,2,1,129,174,151,139,93,138,2,1,161,174,151,139,93,133,2,1,161,174,151,139,93,134,2,1,129,174,151,139,93,142,2,1,161,174,151,139,93,139,2,1,161,174,151,139,93,143,2,1,161,174,151,139,93,144,2,1,129,174,151,139,93,145,2,1,39,0,203,184,221,173,11,1,36,51,50,48,102,56,48,97,100,45,50,51,52,101,45,53,49,55,50,45,97,49,55,50,45,102,55,56,52,54,52,55,50,55,98,100,97,1,40,0,174,151,139,93,150,2,2,105,100,1,119,36,51,50,48,102,56,48,97,100,45,50,51,52,101,45,53,49,55,50,45,97,49,55,50,45,102,55,56,52,54,52,55,50,55,98,100,97,40,0,174,151,139,93,150,2,4,110,97,109,101,1,119,8,85,110,116,105,116,108,101,100,40,0,174,151,139,93,150,2,3,98,105,100,1,119,36,51,50,48,102,56,48,97,100,45,50,51,52,101,45,53,49,55,50,45,97,49,55,50,45,102,55,56,52,54,52,55,50,55,98,100,97,40,0,174,151,139,93,150,2,4,100,101,115,99,1,119,0,40,0,174,151,139,93,150,2,6,108,97,121,111,117,116,1,122,0,0,0,0,0,0,0,0,40,0,174,151,139,93,150,2,10,99,114,101,97,116,101,100,95,97,116,1,122,0,0,0,0,102,78,228,14,39,0,203,184,221,173,11,4,36,51,50,48,102,56,48,97,100,45,50,51,52,101,45,53,49,55,50,45,97,49,55,50,45,102,55,56,52,54,52,55,50,55,98,100,97,0,40,0,174,151,139,93,150,2,4,105,99,111,110,1,119,0,40,0,174,151,139,93,150,2,10,99,114,101,97,116,101,100,95,98,121,1,122,4,56,115,160,190,64,16,0,33,0,174,151,139,93,150,2,16,108,97,115,116,95,101,100,105,116,101,100,95,116,105,109,101,1,33,0,174,151,139,93,150,2,14,108,97,115,116,95,101,100,105,116,101,100,95,98,121,1,168,174,151,139,93,161,2,1,122,4,56,115,160,190,64,16,0,168,174,151,139,93,160,2,1,122,0,0,0,0,102,78,228,14,40,0,174,151,139,93,150,2,5,101,120,116,114,97,1,119,36,123,34,99,111,118,101,114,34,58,123,34,116,121,112,101,34,58,34,110,111,110,101,34,44,34,118,97,108,117,101,34,58,34,34,125,125,161,174,151,139,93,14,1,161,174,151,139,93,15,1,129,174,151,139,93,149,2,1,161,174,151,139,93,146,2,1,168,174,151,139,93,165,2,1,122,4,56,115,160,190,64,16,0,161,174,151,139,93,166,2,1,136,174,151,139,93,167,2,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,78,229,144,2,105,100,119,36,97,53,53,54,54,101,52,57,45,102,49,53,54,45,52,49,54,56,45,57,98,50,100,45,49,55,57,50,54,99,53,100,97,51,50,57,161,174,151,139,93,147,2,1,161,174,151,139,93,148,2,1,129,174,151,139,93,171,2,1,161,174,151,139,93,168,2,1,161,174,151,139,93,172,2,1,161,174,151,139,93,173,2,1,129,174,151,139,93,174,2,1,1,184,231,170,67,0,161,145,144,146,185,5,11,6,39,245,220,194,52,0,161,209,250,203,254,15,0,1,161,209,250,203,254,15,1,1,136,209,250,203,254,15,2,1,118,2,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,246,151,161,140,152,206,145,6,152,1,1,161,140,152,206,145,6,153,1,1,129,245,220,194,52,2,1,161,245,220,194,52,0,1,161,245,220,194,52,1,1,136,245,220,194,52,5,1,118,2,2,105,100,119,36,50,54,100,53,99,56,99,49,45,49,99,54,54,45,52,53,57,99,45,98,99,54,99,45,102,52,100,97,49,97,54,54,51,51,52,56,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,246,202,161,140,152,206,145,6,87,1,161,140,152,206,145,6,88,1,136,245,220,194,52,8,1,118,2,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,83,246,206,2,105,100,119,36,55,100,50,49,52,56,102,99,45,99,97,99,101,45,52,52,53,50,45,57,99,53,99,45,57,54,101,53,50,101,54,98,102,56,98,53,161,245,220,194,52,3,1,161,245,220,194,52,4,1,129,245,220,194,52,11,1,161,170,255,211,105,7,1,161,170,255,211,105,8,1,161,140,152,206,145,6,151,1,1,161,245,220,194,52,15,1,161,245,220,194,52,16,1,161,245,220,194,52,17,1,161,170,255,211,105,21,1,161,170,255,211,105,22,1,161,245,220,194,52,20,1,161,245,220,194,52,21,1,161,245,220,194,52,22,1,161,245,220,194,52,23,1,161,170,255,211,105,35,1,161,170,255,211,105,36,1,129,170,255,211,105,37,1,161,245,220,194,52,27,1,161,245,220,194,52,28,1,129,245,220,194,52,29,1,161,245,220,194,52,30,1,161,245,220,194,52,31,1,161,245,220,194,52,26,1,161,245,220,194,52,33,1,161,245,220,194,52,34,1,161,245,220,194,52,35,1,6,166,203,155,46,0,161,140,152,206,145,6,30,1,161,140,152,206,145,6,31,1,129,162,238,198,212,7,2,1,168,166,203,155,46,0,1,122,4,56,115,160,190,64,16,0,168,166,203,155,46,1,1,122,0,0,0,0,102,88,52,80,136,166,203,155,46,2,1,118,2,2,105,100,119,36,48,99,101,49,51,52,49,53,45,54,99,99,101,45,52,52,57,55,45,57,52,99,54,45,52,55,53,97,100,57,54,99,50,52,57,101,9,116,105,109,101,115,116,97,109,112,122,0,0,0,0,102,88,52,80,3,179,252,154,44,0,161,157,240,144,231,2,0,1,161,157,240,144,231,2,1,1,129,157,240,144,231,2,2,1,3,248,153,216,10,0,161,163,236,177,169,4,9,1,161,163,236,177,169,4,10,1,129,163,236,177,169,4,11,1,158,1,128,252,161,128,4,1,0,33,130,180,254,251,6,4,0,3,5,2,9,1,13,4,135,240,136,178,10,1,0,45,135,232,133,203,9,1,0,15,137,226,192,199,6,1,0,20,138,202,240,189,2,1,0,134,1,139,240,196,145,14,1,0,138,2,140,228,230,243,1,1,0,2,139,152,215,249,10,1,0,34,141,216,158,150,1,1,0,3,142,130,192,134,11,1,0,3,143,184,153,180,6,1,0,6,145,190,137,224,10,1,0,2,145,144,146,185,5,1,0,12,140,152,206,145,6,13,0,60,61,24,86,3,90,6,97,3,101,2,105,1,111,1,113,20,134,1,20,155,1,2,158,1,3,162,1,2,135,166,246,235,6,1,0,2,147,206,229,235,1,1,0,3,137,164,190,210,1,7,3,2,6,1,20,2,25,3,29,2,32,2,35,3,152,252,186,192,1,1,0,2,153,130,203,161,6,1,0,97,154,244,246,165,8,10,0,24,26,1,37,2,56,1,71,1,82,3,88,36,127,18,148,1,35,193,1,2,156,148,170,169,10,1,0,16,157,240,144,231,2,1,0,3,158,156,181,152,10,7,0,6,7,2,15,1,19,8,28,2,32,1,40,9,159,156,204,250,6,1,0,27,160,192,253,131,5,1,0,3,161,178,132,150,11,4,0,15,17,1,28,64,93,8,158,182,250,251,9,1,0,15,163,236,177,169,4,1,0,12,164,188,201,172,1,1,0,3,158,184,218,165,3,1,0,38,162,238,198,212,7,1,0,2,170,140,240,234,9,1,0,31,171,204,155,217,8,1,0,3,171,142,166,254,1,1,0,6,173,252,148,184,13,3,0,40,41,2,44,20,176,154,159,227,1,3,0,1,2,2,14,6,178,162,190,217,10,1,0,3,179,252,154,44,1,0,3,180,230,210,212,13,2,0,2,3,4,182,172,247,194,5,1,0,3,183,226,184,158,8,1,0,8,187,220,199,239,8,9,1,1,3,2,6,1,15,1,19,1,23,17,43,1,56,4,63,3,195,242,227,194,8,1,0,3,196,154,250,183,6,1,0,62,197,254,154,201,10,1,0,3,200,142,208,241,4,1,0,157,1,202,160,246,212,1,1,0,6,203,184,221,173,11,6,14,1,19,1,21,2,29,1,33,2,36,1,206,220,129,131,4,3,0,3,4,2,16,5,207,228,238,162,8,4,1,2,13,9,23,2,35,15,209,250,203,254,15,1,0,2,210,228,153,221,12,1,0,3,211,166,203,229,4,1,0,195,1,211,202,217,232,12,1,0,7,214,168,149,214,3,1,0,15,219,220,239,171,8,1,0,10,225,248,138,176,2,6,0,9,10,2,13,1,18,2,26,1,30,19,226,212,179,248,2,1,0,15,229,154,128,197,12,4,0,6,7,2,15,1,19,5,234,182,182,157,9,1,0,8,235,178,165,206,5,1,0,72,234,156,130,211,12,1,0,11,241,130,161,205,7,1,0,9,244,226,228,149,2,4,1,3,6,1,17,4,23,7,245,220,194,52,4,0,2,3,5,9,2,12,27,247,200,243,247,14,5,1,2,5,1,13,8,22,32,55,42,248,136,168,181,1,1,0,3,248,210,237,129,13,1,0,2,250,198,166,187,7,1,0,2,248,196,187,185,10,1,0,31,252,218,241,167,14,1,0,2,255,140,248,220,6,1,0,3,128,211,179,216,2,1,0,10,133,159,138,205,12,14,0,7,9,1,20,9,42,14,57,2,61,1,65,1,67,1,69,17,87,6,94,2,106,2,109,2,121,10,135,167,156,250,14,1,0,16,135,193,208,135,7,1,0,16,141,245,194,142,11,1,0,7,141,205,220,149,4,1,0,3,143,131,148,152,6,1,1,2,141,171,170,217,4,1,0,2,145,159,164,217,14,1,0,3,149,129,169,191,12,1,0,16,149,249,242,175,4,3,0,8,11,2,16,15,149,189,189,215,8,1,0,3,149,161,132,184,14,1,0,221,2,154,243,157,196,14,1,0,12,154,193,208,134,10,1,0,9,155,165,205,152,11,1,0,3,155,159,180,195,15,1,0,6,157,207,243,216,6,1,0,2,154,235,215,240,4,1,0,13,161,239,241,154,13,1,0,106,162,159,252,196,11,1,0,3,164,155,139,169,7,1,0,35,165,139,157,171,15,11,2,1,9,1,13,5,19,2,27,1,31,6,39,1,52,5,58,12,72,1,85,18,164,203,250,235,13,1,0,7,167,131,133,162,9,1,0,11,166,201,221,141,13,11,0,6,7,2,10,2,13,2,26,2,31,2,34,3,38,6,45,2,57,11,69,3,169,197,188,221,3,1,0,3,170,255,211,105,3,0,2,3,25,31,7,166,203,155,46,1,0,3,173,187,245,170,14,1,0,46,174,151,139,93,14,0,45,55,2,60,54,124,2,129,1,48,178,1,2,202,1,2,217,1,2,232,1,2,237,1,41,160,2,2,165,2,4,170,2,1,172,2,7,175,225,172,150,8,1,0,10,175,147,217,214,1,1,0,33,177,161,136,243,11,1,0,10,178,203,205,182,4,1,0,1,175,205,156,228,6,1,0,10,180,205,189,133,13,1,0,20,181,175,219,209,12,1,0,10,182,143,233,195,4,1,0,111,177,219,160,167,7,1,0,4,184,201,188,172,10,1,0,3,184,231,170,67,1,0,6,186,197,166,179,15,1,0,7,188,171,136,250,8,1,0,21,188,237,223,145,6,1,0,26,190,139,191,155,1,1,0,2,191,157,147,233,9,1,0,32,193,249,142,142,4,1,0,17,198,189,216,175,6,1,0,23,200,205,214,172,10,1,0,30,201,129,238,197,4,8,0,6,9,33,43,2,51,1,55,2,58,2,66,1,70,13,201,191,159,147,14,1,0,17,200,203,236,184,2,1,0,35,200,159,185,206,9,1,0,8,205,149,231,236,11,1,0,68,213,161,242,209,13,5,0,3,4,2,8,1,16,7,27,8,214,139,213,136,8,13,0,2,5,2,10,2,15,2,20,2,25,2,30,2,35,2,40,2,45,2,50,2,55,2,60,6,213,255,156,145,1,1,0,2,219,227,140,137,6,1,0,34,221,147,167,147,15,1,0,177,2,222,205,223,235,7,2,0,9,10,21,223,209,193,147,11,1,0,81,227,209,197,253,2,1,0,14,229,153,197,202,7,1,0,241,6,231,139,244,188,8,1,0,13,232,207,157,148,2,1,0,2,233,165,139,246,14,4,0,2,3,4,8,2,20,23,233,247,183,159,1,1,0,4,235,225,184,133,10,1,0,3,234,153,236,158,4,8,0,6,7,2,11,1,15,1,19,6,27,1,38,7,46,27,234,187,164,181,1,1,0,24,231,189,134,196,8,1,0,77,239,199,189,146,3,1,0,24,240,149,229,225,6,1,1,2,241,155,213,233,1,5,0,6,7,2,11,1,15,1,19,32,240,253,240,229,1,1,0,79,243,239,182,181,13,2,1,2,16,2,236,229,225,232,8,1,0,116,246,185,174,192,6,1,0,90,248,153,216,10,1,0,3,251,189,220,155,14,1,0,3,252,163,130,200,6,2,1,2,16,2,253,205,145,137,11,1,0,10,252,171,209,175,15,1,0,4,255,255,147,249,10,1,0,3],"version":0,"object_id":"9eebea03-3ed5-4298-86b2-a7f77856d48b"},"code":0,"message":"Operation completed successfully."} \ No newline at end of file diff --git a/frontend/appflowy_web_app/cypress/support/component.ts b/frontend/appflowy_web_app/cypress/support/component.ts index c34213c8e2..b86b3d71bb 100644 --- a/frontend/appflowy_web_app/cypress/support/component.ts +++ b/frontend/appflowy_web_app/cypress/support/component.ts @@ -36,12 +36,36 @@ declare global { mockCurrentWorkspace: () => void; mockGetWorkspaceDatabases: () => void; mockDocument: (id: string) => void; + clickOutside: () => void; + getTestingSelector: (testId: string) => Chainable>; } } } Cypress.Commands.add('mount', mount); +Cypress.Commands.add('getTestingSelector', (testId: string) => { + return cy.get(`[data-testid="${testId}"]`); +}); + +Cypress.Commands.add('clickOutside', () => { + cy.document().then((doc) => { + // [0, 0] is the top left corner of the window + const x = 0; + const y = 0; + + const evt = new MouseEvent('click', { + bubbles: true, + cancelable: true, + view: window, + clientX: x, + clientY: y, + }); + + // Dispatch the event + doc.elementFromPoint(x, y)?.dispatchEvent(evt); + }); +}); // Example use: // cy.mount() diff --git a/frontend/appflowy_web_app/src/application/folder-yjs/context.ts b/frontend/appflowy_web_app/src/application/folder-yjs/context.ts index 02a2cfcba4..cb0e1f63ff 100644 --- a/frontend/appflowy_web_app/src/application/folder-yjs/context.ts +++ b/frontend/appflowy_web_app/src/application/folder-yjs/context.ts @@ -1,5 +1,5 @@ import { ViewLayout, YFolder, YjsFolderKey } from '@/application/collab.type'; -import { createContext, useCallback, useContext } from 'react'; +import { createContext, useContext } from 'react'; import { useParams } from 'react-router-dom'; export interface Crumb { @@ -36,14 +36,3 @@ export const useNavigateToView = () => { export const useCrumbs = () => { return useContext(FolderContext)?.crumbs; }; - -export const usePushCrumb = () => { - const { setCrumbs } = useContext(FolderContext) || {}; - - return useCallback( - (crumb: Crumb) => { - setCrumbs?.((prevCrumbs) => [...prevCrumbs, crumb]); - }, - [setCrumbs] - ); -}; diff --git a/frontend/appflowy_web_app/src/application/services/js-services/storage/collab.ts b/frontend/appflowy_web_app/src/application/services/js-services/storage/collab.ts index b41f1861ab..6b315658f5 100644 --- a/frontend/appflowy_web_app/src/application/services/js-services/storage/collab.ts +++ b/frontend/appflowy_web_app/src/application/services/js-services/storage/collab.ts @@ -100,6 +100,7 @@ export async function batchCollabs( const res = await batchFetchCollab(workspaceId, params); + console.log('Fetched collab data:', res); for (const id of Object.keys(res)) { const type = params.find((param) => param.object_id === id)?.collab_type; const data = res[id]; diff --git a/frontend/appflowy_web_app/src/components/database/Database.cy.tsx b/frontend/appflowy_web_app/src/components/database/Database.cy.tsx deleted file mode 100644 index a88ca539ad..0000000000 --- a/frontend/appflowy_web_app/src/components/database/Database.cy.tsx +++ /dev/null @@ -1,123 +0,0 @@ -import { YDoc, YFolder, YjsEditorKey } from '@/application/collab.type'; -import { applyYDoc } from '@/application/ydoc/apply'; -import { FolderProvider } from '@/components/_shared/context-provider/FolderProvider'; -import { IdProvider } from '@/components/_shared/context-provider/IdProvider'; -import withAppWrapper from '@/components/app/withAppWrapper'; -import { useState } from 'react'; -import { Database } from './Database'; -import { DatabaseContextProvider } from './DatabaseContext'; -import * as Y from 'yjs'; -import '@/components/layout/layout.scss'; - -describe('', () => { - beforeEach(() => { - cy.viewport(1280, 720); - Object.defineProperty(window.navigator, 'language', { value: 'en-US' }); - Object.defineProperty(window.navigator, 'languages', { value: ['en-US'] }); - cy.mockDatabase(); - }); - - it('renders with a database', () => { - cy.fixture('folder').then((folderJson) => { - const doc = new Y.Doc(); - const state = new Uint8Array(folderJson.data.doc_state); - - applyYDoc(doc, state); - - const folder = doc.getMap(YjsEditorKey.data_section).get(YjsEditorKey.folder) as YFolder; - - cy.fixture(`database/4c658817-20db-4f56-b7f9-0637a22dfeb6`).then((database) => { - cy.fixture(`database/rows/4c658817-20db-4f56-b7f9-0637a22dfeb6`).then((rows) => { - const doc = new Y.Doc(); - const rootRowsDoc = new Y.Doc(); - const rowsFolder: Y.Map = rootRowsDoc.getMap(); - const databaseState = new Uint8Array(database.data.doc_state); - - applyYDoc(doc, databaseState); - - Object.keys(rows).forEach((key) => { - const data = rows[key]; - const rowDoc = new Y.Doc(); - - applyYDoc(rowDoc, new Uint8Array(data)); - rowsFolder.set(key, rowDoc); - }); - - const onNavigateToView = cy.stub(); - - const AppWrapper = withAppWrapper(() => { - return ( -
- -
- ); - }); - - cy.mount(); - - cy.get('[data-testid^=view-tab-]').should('have.length', 4); - cy.get('.database-grid').should('exist'); - - cy.get('[data-testid=view-tab-e410747b-5f2f-45a0-b2f7-890ad3001355]').click(); - cy.get('.database-board').should('exist'); - cy.wrap(onNavigateToView).should('have.been.calledOnceWith', 'e410747b-5f2f-45a0-b2f7-890ad3001355'); - - cy.wait(800); - cy.get('[data-testid=view-tab-7d2148fc-cace-4452-9c5c-96e52e6bf8b5]').click(); - cy.get('.database-grid').should('exist'); - cy.wrap(onNavigateToView).should('have.been.calledWith', '7d2148fc-cace-4452-9c5c-96e52e6bf8b5'); - - cy.wait(800); - cy.get('[data-testid=view-tab-2143e95d-5dcb-4e0f-bb2c-50944e6e019f]').click(); - cy.get('.database-calendar').should('exist'); - cy.wrap(onNavigateToView).should('have.been.calledWith', '2143e95d-5dcb-4e0f-bb2c-50944e6e019f'); - }); - }); - }); - }); -}); - -function TestDatabase({ - databaseDoc, - rows, - folder, - iidIndex, - initialViewId, - onNavigateToView, -}: { - databaseDoc: YDoc; - rows: Y.Map; - folder: YFolder; - iidIndex: string; - initialViewId: string; - onNavigateToView: (viewId: string) => void; -}) { - const [activeViewId, setActiveViewId] = useState(initialViewId); - - const handleNavigateToView = (viewId: string) => { - setActiveViewId(viewId); - onNavigateToView(viewId); - }; - - return ( - - - - - - - - ); -} diff --git a/frontend/appflowy_web_app/src/components/database/__tests__/Database.cy.tsx b/frontend/appflowy_web_app/src/components/database/__tests__/Database.cy.tsx new file mode 100644 index 0000000000..23793e9227 --- /dev/null +++ b/frontend/appflowy_web_app/src/components/database/__tests__/Database.cy.tsx @@ -0,0 +1,40 @@ +import { renderDatabase } from '@/components/database/__tests__/withTestingDatabase'; +import '@/components/layout/layout.scss'; + +describe('', () => { + beforeEach(() => { + cy.viewport(1280, 720); + Object.defineProperty(window.navigator, 'language', { value: 'en-US' }); + cy.mockDatabase(); + }); + + it('renders with a database', () => { + const onNavigateToView = cy.stub(); + + renderDatabase( + { + databaseId: '4c658817-20db-4f56-b7f9-0637a22dfeb6', + viewId: '7d2148fc-cace-4452-9c5c-96e52e6bf8b5', + onNavigateToView, + }, + () => { + cy.get('[data-testid^=view-tab-]').should('have.length', 4); + cy.get('.database-grid').should('exist'); + + cy.get('[data-testid=view-tab-e410747b-5f2f-45a0-b2f7-890ad3001355]').click(); + cy.get('.database-board').should('exist'); + cy.wrap(onNavigateToView).should('have.been.calledOnceWith', 'e410747b-5f2f-45a0-b2f7-890ad3001355'); + + cy.wait(800); + cy.get('[data-testid=view-tab-7d2148fc-cace-4452-9c5c-96e52e6bf8b5]').click(); + cy.get('.database-grid').should('exist'); + cy.wrap(onNavigateToView).should('have.been.calledWith', '7d2148fc-cace-4452-9c5c-96e52e6bf8b5'); + + cy.wait(800); + cy.get('[data-testid=view-tab-2143e95d-5dcb-4e0f-bb2c-50944e6e019f]').click(); + cy.get('.database-calendar').should('exist'); + cy.wrap(onNavigateToView).should('have.been.calledWith', '2143e95d-5dcb-4e0f-bb2c-50944e6e019f'); + } + ); + }); +}); diff --git a/frontend/appflowy_web_app/src/components/database/DatabaseRow.cy.tsx b/frontend/appflowy_web_app/src/components/database/__tests__/DatabaseRow.cy.tsx similarity index 95% rename from frontend/appflowy_web_app/src/components/database/DatabaseRow.cy.tsx rename to frontend/appflowy_web_app/src/components/database/__tests__/DatabaseRow.cy.tsx index e2d84d4a20..00255c4ed8 100644 --- a/frontend/appflowy_web_app/src/components/database/DatabaseRow.cy.tsx +++ b/frontend/appflowy_web_app/src/components/database/__tests__/DatabaseRow.cy.tsx @@ -3,8 +3,8 @@ import { applyYDoc } from '@/application/ydoc/apply'; import { FolderProvider } from '@/components/_shared/context-provider/FolderProvider'; import { IdProvider } from '@/components/_shared/context-provider/IdProvider'; import withAppWrapper from '@/components/app/withAppWrapper'; -import { DatabaseRow } from './DatabaseRow'; -import { DatabaseContextProvider } from './DatabaseContext'; +import { DatabaseRow } from 'src/components/database/DatabaseRow'; +import { DatabaseContextProvider } from 'src/components/database/DatabaseContext'; import * as Y from 'yjs'; import '@/components/layout/layout.scss'; diff --git a/frontend/appflowy_web_app/src/components/database/__tests__/DatabaseWithFilter.cy.tsx b/frontend/appflowy_web_app/src/components/database/__tests__/DatabaseWithFilter.cy.tsx new file mode 100644 index 0000000000..4c63443ad9 --- /dev/null +++ b/frontend/appflowy_web_app/src/components/database/__tests__/DatabaseWithFilter.cy.tsx @@ -0,0 +1,99 @@ +import { renderDatabase } from '@/components/database/__tests__/withTestingDatabase'; +import '@/components/layout/layout.scss'; + +describe(' with filters and sorts', () => { + beforeEach(() => { + cy.viewport(1280, 720); + Object.defineProperty(window.navigator, 'language', { value: 'en-US' }); + cy.mockDatabase(); + }); + + it('render a database with filters and sorts', () => { + const onNavigateToView = cy.stub(); + + renderDatabase( + { + onNavigateToView, + databaseId: '87bc006e-c1eb-47fd-9ac6-e39b17956369', + viewId: '7f233be4-1b4d-46b2-bcfc-f341b8d75267', + }, + () => { + cy.wait(1000); + cy.getTestingSelector('database-actions-filter').click(); + + cy.get('.database-conditions').then(($el) => { + cy.wait(500); + const height = $el.height(); + + expect(height).to.be.greaterThan(0); + }); + + cy.getTestingSelector('database-sort-condition').click(); + cy.wait(500); + cy.getTestingSelector('sort-condition').as('sortConditions').should('have.length', 2); + cy.get('@sortConditions').eq(0).contains('number'); + cy.get('@sortConditions').eq(0).contains('Ascending'); + cy.get('@sortConditions').eq(1).contains('Name'); + cy.get('@sortConditions').eq(1).contains('Descending'); + cy.clickOutside(); + cy.getTestingSelector('sort-condition-list').should('not.exist'); + + // the length of filters should be 6 + cy.getTestingSelector('database-filter-condition').as('filterConditions'); + cy.get('@filterConditions').should('have.length', 6); + // the first filter should be 'Name', the value should be 'contains', and the input should be 123 + cy.get('@filterConditions').eq(0).as('filterCondition'); + cy.get('@filterCondition').contains('Name'); + cy.get('@filterCondition').contains('123'); + cy.get('@filterCondition').click(); + cy.getTestingSelector('filter-menu-popover').should('be.visible'); + cy.getTestingSelector('filter-condition-type').contains('Contains'); + cy.get(`[data-testid="text-filter-input"] input`).should('have.value', '123'); + cy.clickOutside(); + // the second filter should be 'Type', the value should be 'is not empty' + cy.get('@filterConditions').eq(1).as('filterCondition'); + cy.get('@filterCondition').contains('Type'); + cy.get('@filterCondition').contains('is not empty'); + cy.get('@filterCondition').click(); + cy.clickOutside(); + // the third filter should be 'Done', the value should be 'is Checked' + cy.get('@filterConditions').eq(2).as('filterCondition'); + cy.get('@filterCondition').contains('Done'); + cy.get('@filterCondition').contains('is Checked'); + cy.get('@filterCondition').click(); + cy.clickOutside(); + // the fourth filter should be 'Number', the value should be 'is greater than', and the input should be 600 + cy.get('@filterConditions').eq(3).as('filterCondition'); + cy.get('@filterCondition').contains('number'); + cy.get('@filterCondition').contains('> 600'); + cy.get('@filterCondition').click(); + cy.getTestingSelector('filter-menu-popover').should('be.visible'); + cy.getTestingSelector('filter-condition-type').contains('Is greater than'); + cy.get(`[data-testid="number-filter-input"] input`).should('have.value', '600'); + cy.clickOutside(); + // the fifth filter should be 'multi type', the value should be 'Does not contain' + cy.get('@filterConditions').eq(4).as('filterCondition'); + cy.get('@filterCondition').contains('multi type'); + cy.get('@filterCondition').click(); + cy.getTestingSelector('filter-menu-popover').should('be.visible'); + cy.getTestingSelector('filter-condition-type').contains('Does not contain'); + cy.getTestingSelector('select-option-list').as('selectOptionList'); + cy.get('@selectOptionList').should('have.length', 2); + cy.get('@selectOptionList').eq(0).contains('option-2'); + cy.get('@selectOptionList').eq(1).contains('option-1'); + cy.get('@selectOptionList').eq(1).should('have.data', 'checked', true); + cy.clickOutside(); + // the sixth filter should be 'Checklist', the value should be 'is completed' + cy.get('@filterConditions').eq(5).as('filterCondition'); + cy.get('@filterCondition').contains('Checklist'); + cy.get('@filterCondition').contains('is complete'); + cy.get('@filterCondition').click(); + cy.clickOutside(); + + cy.getTestingSelector('view-tab-a734a068-e73d-4b4b-853c-4daffea389c0').click(); + cy.wait(800); + cy.getTestingSelector('view-tab-7f233be4-1b4d-46b2-bcfc-f341b8d75267').click(); + } + ); + }); +}); diff --git a/frontend/appflowy_web_app/src/components/database/__tests__/withTestingDatabase.tsx b/frontend/appflowy_web_app/src/components/database/__tests__/withTestingDatabase.tsx new file mode 100644 index 0000000000..d9e79811d1 --- /dev/null +++ b/frontend/appflowy_web_app/src/components/database/__tests__/withTestingDatabase.tsx @@ -0,0 +1,106 @@ +import { YDoc, YFolder, YjsEditorKey } from '@/application/collab.type'; +import { applyYDoc } from '@/application/ydoc/apply'; +import { FolderProvider } from '@/components/_shared/context-provider/FolderProvider'; +import { IdProvider } from '@/components/_shared/context-provider/IdProvider'; +import withAppWrapper from '@/components/app/withAppWrapper'; +import { DatabaseContextProvider } from '@/components/database/DatabaseContext'; +import { useState } from 'react'; +import * as Y from 'yjs'; +import { Database } from 'src/components/database/Database'; + +export function renderDatabase( + { + databaseId, + viewId, + onNavigateToView, + }: { + databaseId: string; + viewId: string; + onNavigateToView: (viewId: string) => void; + }, + onAfterRender?: () => void +) { + cy.fixture('folder').then((folderJson) => { + const doc = new Y.Doc(); + const state = new Uint8Array(folderJson.data.doc_state); + + applyYDoc(doc, state); + + const folder = doc.getMap(YjsEditorKey.data_section).get(YjsEditorKey.folder) as YFolder; + + cy.fixture(`database/${databaseId}`).then((database) => { + cy.fixture(`database/rows/${databaseId}`).then((rows) => { + const doc = new Y.Doc(); + const rootRowsDoc = new Y.Doc(); + const rowsFolder: Y.Map = rootRowsDoc.getMap(); + const databaseState = new Uint8Array(database.data.doc_state); + + applyYDoc(doc, databaseState); + + Object.keys(rows).forEach((key) => { + const data = rows[key]; + const rowDoc = new Y.Doc(); + + applyYDoc(rowDoc, new Uint8Array(data)); + rowsFolder.set(key, rowDoc); + }); + + const AppWrapper = withAppWrapper(() => { + return ( +
+ +
+ ); + }); + + cy.mount(); + onAfterRender?.(); + }); + }); + }); +} + +export function TestDatabase({ + databaseDoc, + rows, + folder, + iidIndex, + initialViewId, + onNavigateToView, +}: { + databaseDoc: YDoc; + rows: Y.Map; + folder: YFolder; + iidIndex: string; + initialViewId: string; + onNavigateToView: (viewId: string) => void; +}) { + const [activeViewId, setActiveViewId] = useState(initialViewId); + + const handleNavigateToView = (viewId: string) => { + setActiveViewId(viewId); + onNavigateToView(viewId); + }; + + return ( + + + + + + + + ); +} diff --git a/frontend/appflowy_web_app/src/components/database/components/conditions/DatabaseActions.tsx b/frontend/appflowy_web_app/src/components/database/components/conditions/DatabaseActions.tsx index a7559374c2..38c96edf10 100644 --- a/frontend/appflowy_web_app/src/components/database/components/conditions/DatabaseActions.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/conditions/DatabaseActions.tsx @@ -17,11 +17,13 @@ export function DatabaseActions() { onClick={() => { conditionsContext?.toggleExpanded(); }} + data-testid={'database-actions-filter'} color={filter.length > 0 ? 'primary' : 'inherit'} > {t('grid.settings.filter')} { conditionsContext?.toggleExpanded(); }} diff --git a/frontend/appflowy_web_app/src/components/database/components/field/select-option/SelectOptionList.tsx b/frontend/appflowy_web_app/src/components/database/components/field/select-option/SelectOptionList.tsx index 353ef5d349..4a1c6fff33 100644 --- a/frontend/appflowy_web_app/src/components/database/components/field/select-option/SelectOptionList.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/field/select-option/SelectOptionList.tsx @@ -16,8 +16,13 @@ export function SelectOptionList({ fieldId, selectedIds }: { fieldId: string; se const isSelected = selectedIds.includes(option.id); return ( -
- +
+ {isSelected && }
); diff --git a/frontend/appflowy_web_app/src/components/database/components/filters/Filter.tsx b/frontend/appflowy_web_app/src/components/database/components/filters/Filter.tsx index 3fe0c4daf3..844303d49b 100644 --- a/frontend/appflowy_web_app/src/components/database/components/filters/Filter.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/filters/Filter.tsx @@ -19,6 +19,7 @@ function Filter({ filterId }: { filterId: string }) { onClick={(e) => { setAnchorEl(e.currentTarget); }} + data-testid={'database-filter-condition'} className={ 'flex cursor-pointer flex-nowrap items-center gap-1 rounded-full border border-line-divider py-1 px-2 hover:border-fill-default hover:text-fill-default hover:shadow-sm' } @@ -39,6 +40,7 @@ function Filter({ filterId }: { filterId: string }) { onClose={() => { setAnchorEl(null); }} + data-testid={'filter-menu-popover'} slotProps={{ paper: { style: { diff --git a/frontend/appflowy_web_app/src/components/database/components/filters/filter-menu/FieldMenuTitle.tsx b/frontend/appflowy_web_app/src/components/database/components/filters/filter-menu/FieldMenuTitle.tsx index e5784b44f5..da7d9dd817 100644 --- a/frontend/appflowy_web_app/src/components/database/components/filters/filter-menu/FieldMenuTitle.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/filters/filter-menu/FieldMenuTitle.tsx @@ -10,7 +10,10 @@ function FieldMenuTitle({ fieldId, selectedConditionText }: { fieldId: string; s
-
+
{selectedConditionText}
diff --git a/frontend/appflowy_web_app/src/components/database/components/filters/filter-menu/NumberFilterMenu.tsx b/frontend/appflowy_web_app/src/components/database/components/filters/filter-menu/NumberFilterMenu.tsx index fdd8963ef2..6ed24cc05e 100644 --- a/frontend/appflowy_web_app/src/components/database/components/filters/filter-menu/NumberFilterMenu.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/filters/filter-menu/NumberFilterMenu.tsx @@ -58,6 +58,7 @@ function NumberFilterMenu({ filter }: { filter: NumberFilter }) { {displayTextField && ( +
{displayTextField && ( +
diff --git a/frontend/appflowy_web_app/src/components/database/components/sorts/Sorts.tsx b/frontend/appflowy_web_app/src/components/database/components/sorts/Sorts.tsx index a00aeea20c..4ae872f8ec 100644 --- a/frontend/appflowy_web_app/src/components/database/components/sorts/Sorts.tsx +++ b/frontend/appflowy_web_app/src/components/database/components/sorts/Sorts.tsx @@ -19,6 +19,7 @@ export function Sorts() { onClick={(e) => { setAnchorEl(e.currentTarget); }} + data-testid={'database-sort-condition'} className='flex cursor-pointer items-center gap-1 rounded-full border border-line-divider px-2 py-1 text-xs hover:border-fill-default hover:text-fill-default hover:shadow-sm' > diff --git a/frontend/appflowy_web_app/src/components/layout/Layout.hooks.ts b/frontend/appflowy_web_app/src/components/layout/Layout.hooks.ts index 0313015d3f..3ab11d17e9 100644 --- a/frontend/appflowy_web_app/src/components/layout/Layout.hooks.ts +++ b/frontend/appflowy_web_app/src/components/layout/Layout.hooks.ts @@ -73,7 +73,7 @@ export function useLayout() { return { viewId: view.get(YjsFolderKey.id), name: view.get(YjsFolderKey.name), - icon: icon || '', + icon: icon || view.get(YjsFolderKey.layout), }; }) .slice(1) diff --git a/frontend/appflowy_web_app/src/components/layout/breadcrumb/Item.tsx b/frontend/appflowy_web_app/src/components/layout/breadcrumb/Item.tsx index 9bad9f5eba..1f58950e58 100644 --- a/frontend/appflowy_web_app/src/components/layout/breadcrumb/Item.tsx +++ b/frontend/appflowy_web_app/src/components/layout/breadcrumb/Item.tsx @@ -1,6 +1,31 @@ +import { ViewLayout } from '@/application/collab.type'; import { Crumb, useNavigateToView } from '@/application/folder-yjs'; import React from 'react'; import { useTranslation } from 'react-i18next'; +import { ReactComponent as DocumentSvg } from '$icons/16x/document.svg'; +import { ReactComponent as GridSvg } from '$icons/16x/grid.svg'; +import { ReactComponent as BoardSvg } from '$icons/16x/board.svg'; +import { ReactComponent as CalendarSvg } from '$icons/16x/date.svg'; + +const renderCrumbIcon = (icon: string) => { + if (Number(icon) === ViewLayout.Grid) { + return ; + } + + if (Number(icon) === ViewLayout.Board) { + return ; + } + + if (Number(icon) === ViewLayout.Calendar) { + return ; + } + + if (Number(icon) === ViewLayout.Document) { + return ; + } + + return icon; +}; function Item({ crumb, disableClick = false }: { crumb: Crumb; disableClick?: boolean }) { const { viewId, icon, name } = crumb; @@ -16,7 +41,7 @@ function Item({ crumb, disableClick = false }: { crumb: Crumb; disableClick?: bo onNavigateToView?.(viewId); }} > - {icon} + {renderCrumbIcon(icon)} diff --git a/frontend/appflowy_web_app/vite.config.ts b/frontend/appflowy_web_app/vite.config.ts index bc69405ca3..451fe002fb 100644 --- a/frontend/appflowy_web_app/vite.config.ts +++ b/frontend/appflowy_web_app/vite.config.ts @@ -78,7 +78,7 @@ export default defineConfig({ port: !!process.env.TAURI_PLATFORM ? 5173 : process.env.PORT ? parseInt(process.env.PORT) : 3000, strictPort: true, watch: { - ignored: ['**/__tests__/**', '**/cypress/**', 'node_modules', '**/*.cy.tsx', '**/*.cy.ts', 'cypress'], + ignored: ['node_modules'], }, cors: false, }, @@ -143,6 +143,10 @@ export default defineConfig({ '@mui/icons-material/ErrorOutline', '@mui/icons-material/CheckCircleOutline', '@mui/icons-material/FunctionsOutlined', + 'react-katex', + // 'react-custom-scrollbars-2', + // 'react-window', + // 'react-virtualized-auto-sizer', ], }, }); From 76fde00cc464435f5c059a7f3cc0b3de343b8b37 Mon Sep 17 00:00:00 2001 From: Tianyu Yuan <62664574+paperplane110@users.noreply.github.com> Date: Fri, 7 Jun 2024 11:48:23 +0800 Subject: [PATCH 11/16] chore: update zh-CN translations (#5484) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: update translations with Fink 🐦 * chore: update translations with Fink 🐦 --- frontend/resources/translations/zh-CN.json | 59 +++++++++++++++++++++- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/frontend/resources/translations/zh-CN.json b/frontend/resources/translations/zh-CN.json index 72240f857a..f804a466b4 100644 --- a/frontend/resources/translations/zh-CN.json +++ b/frontend/resources/translations/zh-CN.json @@ -42,15 +42,29 @@ "emailHint": "邮箱", "passwordHint": "密码", "dontHaveAnAccount": "没有账户?", + "createAccount": "新建账户", "repeatPasswordEmptyError": "确认密码不能为空", "unmatchedPasswordError": "两次密码输入不一致", "syncPromptMessage": "同步数据可能需要一段时间,请不要关闭此页面", "or": "或", + "signInWithGoogle": "使用 Google 账户登录", + "signInWithGithub": "使用 Github 账户登录", + "signInWithDiscord": "使用 Discord 账户登录", + "signUpWithGoogle": "使用 Google 账户注册", + "signUpWithGithub": "使用 Github 账户注册", + "signUpWithDiscord": "使用 Discord 账户注册", "signInWith": "用其他方式登入:", "signInWithEmail": "使用邮箱登录", + "signInWithMagicLink": "使用魔法链接登录", + "signUpWithMagicLink": "使用魔法链接注册", "pleaseInputYourEmail": "请输入邮箱地址", + "settings": "设置", "magicLinkSent": "魔法链接已经发送到您的邮箱,请检查!", "invalidEmail": "请输入一个有效的邮箱地址", + "alreadyHaveAnAccount": "已经有账户了?", + "logIn": "登陆", + "generalError": "出现错误,请稍后再试", + "limitRateError": "出于安全原因,每60秒仅可以发送一次链接", "LogInWithGoogle": "使用 Google 登录", "LogInWithGithub": "使用 Github 登录", "LogInWithDiscord": "使用 Discord 登录", @@ -61,6 +75,7 @@ "chooseWorkspace": "选择您的工作区", "create": "新建工作区", "reset": "重置工作区", + "renameWorkspace": "重命名工作区", "resetWorkspacePrompt": "重置工作区将删除其中的所有页面和数据。您确定要重置工作区吗?您也可以联系技术支持团队来恢复工作区", "hint": "工作区", "notFoundError": "找不到工作区", @@ -127,7 +142,9 @@ "openNewTab": "在新选项卡中打开", "moveTo": "移动", "addToFavorites": "添加到收藏夹", - "copyLink": "复制链接" + "copyLink": "复制链接", + "changeIcon": "更改图表", + "collapseAllPages": "收起全部子页面" }, "blankPageTitle": "空白页", "newPageText": "新页面", @@ -135,6 +152,19 @@ "newGridText": "新建网格", "newCalendarText": "新日历", "newBoardText": "新建看板", + "chat": { + "newChat": "AI 对话", + "unsupportedCloudPrompt": "该功能仅在使用 AppFlowy Cloud 时可用", + "relatedQuestion": "相关问题", + "serverUnavailable": "服务暂时不可用,请稍后再试", + "clickToRetry": "点击重试", + "regenerateAnswer": "重新生成", + "question1": "如何使用 Kanban 来管理任务", + "question2": "介绍一下 GTD 工作法", + "question3": "为什么使用 Rust", + "question4": "使用现有食材制定一份菜谱", + "aiMistakePrompt": "AI 可能出错,请验证重要信息" + }, "trash": { "text": "回收站", "restoreAll": "全部恢复", @@ -228,7 +258,15 @@ "clickToHideFavorites": "单击隐藏收藏夹栏目", "addAPage": "添加页面", "addAPageToPrivate": "添加页面到私人空间", - "recent": "最近的" + "addAPageToWorkspace": "添加页面到工作空间", + "recent": "最近的", + "today": "今日", + "thisWeek": "本周", + "others": "其他", + "justNow": "现在", + "minutesAgo": "{count} 分钟以前", + "lastViewed": "最近一次查看", + "removeSuccess": "成功移除" }, "notifications": { "export": { @@ -244,6 +282,7 @@ }, "button": { "ok": "OK", + "confirm": "确认", "done": "完成", "cancel": "取消", "signIn": "登录", @@ -283,6 +322,7 @@ "signInGoogle": "使用 Google 账户登录", "signInGithub": "使用 Github 账户登录", "signInDiscord": "使用 Discord 账户登录", + "more": "更多", "Done": "完成", "Cancel": "取消", "OK": "确认" @@ -309,6 +349,21 @@ }, "settings": { "title": "设置", + "accountPage": { + "menuLabel": "我的账户", + "title": "我的账户", + "description": "自定义您的简介,管理账户安全信息和 AI API keys,或登陆您的账户", + "email": { + "title": "邮箱", + "actions": { + "change": "更改邮箱" + } + }, + "keys": { + "title": "AI API 密钥", + "openAILabel": "OpenAI API 密钥" + } + }, "menu": { "appearance": "外观", "language": "语言", From 86696b271e353329e0576126d3a4135397a1a1de Mon Sep 17 00:00:00 2001 From: "Kilu.He" <108015703+qinluhe@users.noreply.github.com> Date: Fri, 7 Jun 2024 16:37:07 +0800 Subject: [PATCH 12/16] chore: improvements to caching strategies (#5488) --- .../src/application/database-yjs/selector.ts | 2 - .../js-services/__tests__/cache.test.ts | 310 ++++++++++++++++++ .../js-services/__tests__/fetch.test.ts | 57 ++++ .../services/js-services/auth.service.ts | 4 +- .../js-services/{db/index.ts => cache/db.ts} | 14 +- .../services/js-services/cache/index.ts | 165 ++++++++++ .../services/js-services/cache/types.ts | 12 + .../services/js-services/database.service.ts | 135 ++++---- .../services/js-services/document.service.ts | 21 +- .../application/services/js-services/fetch.ts | 66 ++++ .../services/js-services/folder.service.ts | 20 +- .../js-services/{storage => session}/auth.ts | 0 .../js-services/{storage => session}/index.ts | 1 - .../js-services/{storage => session}/token.ts | 0 .../js-services/{storage => session}/user.ts | 0 .../services/js-services/storage/collab.ts | 118 ------- .../services/js-services/user.service.ts | 2 +- .../services/js-services/wasm/client_api.ts | 2 +- .../_shared/not-found/RecordNotFound.tsx | 2 +- .../src/components/database/Database.tsx | 1 - .../blocks/database/DatabaseBlock.tsx | 2 +- .../src/components/layout/breadcrumb/Item.tsx | 10 +- 22 files changed, 736 insertions(+), 208 deletions(-) create mode 100644 frontend/appflowy_web_app/src/application/services/js-services/__tests__/cache.test.ts create mode 100644 frontend/appflowy_web_app/src/application/services/js-services/__tests__/fetch.test.ts rename frontend/appflowy_web_app/src/application/services/js-services/{db/index.ts => cache/db.ts} (76%) create mode 100644 frontend/appflowy_web_app/src/application/services/js-services/cache/index.ts create mode 100644 frontend/appflowy_web_app/src/application/services/js-services/cache/types.ts create mode 100644 frontend/appflowy_web_app/src/application/services/js-services/fetch.ts rename frontend/appflowy_web_app/src/application/services/js-services/{storage => session}/auth.ts (100%) rename frontend/appflowy_web_app/src/application/services/js-services/{storage => session}/index.ts (73%) rename frontend/appflowy_web_app/src/application/services/js-services/{storage => session}/token.ts (100%) rename frontend/appflowy_web_app/src/application/services/js-services/{storage => session}/user.ts (100%) delete mode 100644 frontend/appflowy_web_app/src/application/services/js-services/storage/collab.ts diff --git a/frontend/appflowy_web_app/src/application/database-yjs/selector.ts b/frontend/appflowy_web_app/src/application/database-yjs/selector.ts index 49fceb885c..884c58516d 100644 --- a/frontend/appflowy_web_app/src/application/database-yjs/selector.ts +++ b/frontend/appflowy_web_app/src/application/database-yjs/selector.ts @@ -71,7 +71,6 @@ export function useDatabaseViewsSelector(iidIndex: string) { const [key] = viewItem; const view = folderViews?.get(key); - console.log('view', view?.get(YjsFolderKey.bid), iidIndex); if ( visibleViewsId.includes(key) && view && @@ -81,7 +80,6 @@ export function useDatabaseViewsSelector(iidIndex: string) { } } - console.log('viewsId', viewsId); setViewIds(viewsId); }; diff --git a/frontend/appflowy_web_app/src/application/services/js-services/__tests__/cache.test.ts b/frontend/appflowy_web_app/src/application/services/js-services/__tests__/cache.test.ts new file mode 100644 index 0000000000..9a7e3fcb9d --- /dev/null +++ b/frontend/appflowy_web_app/src/application/services/js-services/__tests__/cache.test.ts @@ -0,0 +1,310 @@ +import { CollabType } from '@/application/collab.type'; +import * as Y from 'yjs'; +import { withTestingYDoc } from '@/application/slate-yjs/__tests__/withTestingYjsEditor'; +import { expect } from '@jest/globals'; +import { getCollab, batchCollab, collabTypeToDBType } from '../cache'; +import { applyYDoc } from '@/application/ydoc/apply'; +import { getCollabDBName, openCollabDB } from '../cache/db'; +import { StrategyType } from '../cache/types'; + +jest.mock('@/application/ydoc/apply', () => ({ + applyYDoc: jest.fn(), +})); +jest.mock('../cache/db', () => ({ + openCollabDB: jest.fn(), + getCollabDBName: jest.fn(), +})); + +const emptyDoc = new Y.Doc(); +const normalDoc = withTestingYDoc('1'); +const mockFetcher = jest.fn(); +const mockBatchFetcher = jest.fn(); + +describe('Cache functions', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('getCollab', () => { + describe('with CACHE_ONLY strategy', () => { + it('should throw error when no cache', async () => { + (openCollabDB as jest.Mock).mockResolvedValue(emptyDoc); + (getCollabDBName as jest.Mock).mockReturnValue('testDB'); + + await expect( + getCollab( + mockFetcher, + { + collabId: 'id1', + collabType: CollabType.Document, + }, + StrategyType.CACHE_ONLY + ) + ).rejects.toThrow('No cache found'); + }); + it('should fetch collab with CACHE_ONLY strategy and existing cache', async () => { + (openCollabDB as jest.Mock).mockResolvedValue(normalDoc); + (getCollabDBName as jest.Mock).mockReturnValue('testDB'); + + const result = await getCollab( + mockFetcher, + { + collabId: 'id1', + collabType: CollabType.Document, + }, + StrategyType.CACHE_ONLY + ); + + expect(result).toBe(normalDoc); + expect(mockFetcher).not.toHaveBeenCalled(); + expect(applyYDoc).not.toHaveBeenCalled(); + }); + }); + + describe('with CACHE_FIRST strategy', () => { + it('should fetch collab with CACHE_FIRST strategy and existing cache', async () => { + (openCollabDB as jest.Mock).mockResolvedValue(normalDoc); + (getCollabDBName as jest.Mock).mockReturnValue('testDB'); + + mockFetcher.mockResolvedValue({ state: new Uint8Array() }); + + const result = await getCollab( + mockFetcher, + { + collabId: 'id1', + collabType: CollabType.Document, + }, + StrategyType.CACHE_FIRST + ); + + expect(result).toBe(normalDoc); + expect(mockFetcher).not.toHaveBeenCalled(); + expect(applyYDoc).not.toHaveBeenCalled(); + }); + + it('should fetch collab with CACHE_FIRST strategy and no cache', async () => { + (openCollabDB as jest.Mock).mockResolvedValue(emptyDoc); + (getCollabDBName as jest.Mock).mockReturnValue('testDB'); + + mockFetcher.mockResolvedValue({ state: new Uint8Array() }); + + const result = await getCollab( + mockFetcher, + { + collabId: 'id1', + collabType: CollabType.Document, + }, + StrategyType.CACHE_FIRST + ); + + expect(result).toBe(emptyDoc); + expect(mockFetcher).toHaveBeenCalled(); + expect(applyYDoc).toHaveBeenCalled(); + }); + }); + + describe('with CACHE_AND_NETWORK strategy', () => { + it('should fetch collab with CACHE_AND_NETWORK strategy and existing cache', async () => { + (openCollabDB as jest.Mock).mockResolvedValue(normalDoc); + (getCollabDBName as jest.Mock).mockReturnValue('testDB'); + + mockFetcher.mockResolvedValue({ state: new Uint8Array() }); + + const result = await getCollab( + mockFetcher, + { + collabId: 'id1', + collabType: CollabType.Document, + }, + StrategyType.CACHE_AND_NETWORK + ); + + expect(result).toBe(normalDoc); + expect(mockFetcher).toHaveBeenCalled(); + expect(applyYDoc).toHaveBeenCalled(); + }); + + it('should fetch collab with CACHE_AND_NETWORK strategy and no cache', async () => { + (openCollabDB as jest.Mock).mockResolvedValue(emptyDoc); + (getCollabDBName as jest.Mock).mockReturnValue('testDB'); + + mockFetcher.mockResolvedValue({ state: new Uint8Array() }); + + const result = await getCollab( + mockFetcher, + { + collabId: 'id1', + collabType: CollabType.Document, + }, + StrategyType.CACHE_AND_NETWORK + ); + + expect(result).toBe(emptyDoc); + expect(mockFetcher).toHaveBeenCalled(); + expect(applyYDoc).toHaveBeenCalled(); + }); + }); + + describe('with default strategy', () => { + it('should fetch collab with default strategy', async () => { + (openCollabDB as jest.Mock).mockResolvedValue(normalDoc); + (getCollabDBName as jest.Mock).mockReturnValue('testDB'); + + mockFetcher.mockResolvedValue({ state: new Uint8Array() }); + + const result = await getCollab( + mockFetcher, + { + collabId: 'id1', + collabType: CollabType.Document, + }, + StrategyType.NETWORK_ONLY + ); + + expect(result).toBe(normalDoc); + expect(mockFetcher).toHaveBeenCalled(); + expect(applyYDoc).toHaveBeenCalled(); + }); + }); + }); + + describe('batchCollab', () => { + describe('with CACHE_ONLY strategy', () => { + it('should batch fetch collabs with CACHE_ONLY strategy and no cache', async () => { + (openCollabDB as jest.Mock).mockResolvedValue(emptyDoc); + + (getCollabDBName as jest.Mock).mockReturnValue('testDB'); + + await expect( + batchCollab( + mockBatchFetcher, + [ + { + collabId: 'id1', + collabType: CollabType.Document, + }, + ], + StrategyType.CACHE_ONLY + ) + ).rejects.toThrow('No cache found'); + }); + + it('should batch fetch collabs with CACHE_ONLY strategy and existing cache', async () => { + (openCollabDB as jest.Mock).mockResolvedValue(normalDoc); + + (getCollabDBName as jest.Mock).mockReturnValue('testDB'); + + await batchCollab( + mockBatchFetcher, + [ + { + collabId: 'id1', + collabType: CollabType.Document, + }, + ], + StrategyType.CACHE_ONLY + ); + + expect(mockBatchFetcher).not.toHaveBeenCalled(); + }); + }); + + describe('with CACHE_FIRST strategy', () => { + it('should batch fetch collabs with CACHE_FIRST strategy and existing cache', async () => { + (openCollabDB as jest.Mock).mockResolvedValue(normalDoc); + + (getCollabDBName as jest.Mock).mockReturnValue('testDB'); + + await batchCollab( + mockBatchFetcher, + [ + { + collabId: 'id1', + collabType: CollabType.Document, + }, + ], + StrategyType.CACHE_FIRST + ); + + expect(mockBatchFetcher).not.toHaveBeenCalled(); + }); + + it('should batch fetch collabs with CACHE_FIRST strategy and no cache', async () => { + (openCollabDB as jest.Mock).mockResolvedValue(emptyDoc); + + (getCollabDBName as jest.Mock).mockReturnValue('testDB'); + mockBatchFetcher.mockResolvedValue({ id1: [1, 2, 3] }); + + await batchCollab( + mockBatchFetcher, + [ + { + collabId: 'id1', + collabType: CollabType.Document, + }, + ], + StrategyType.CACHE_FIRST + ); + + expect(mockBatchFetcher).toHaveBeenCalled(); + expect(applyYDoc).toHaveBeenCalled(); + }); + }); + + describe('with CACHE_AND_NETWORK strategy', () => { + it('should batch fetch collabs with CACHE_AND_NETWORK strategy', async () => { + (openCollabDB as jest.Mock).mockResolvedValue(normalDoc); + + (getCollabDBName as jest.Mock).mockReturnValue('testDB'); + mockBatchFetcher.mockResolvedValue({ id1: [1, 2, 3] }); + + await batchCollab( + mockBatchFetcher, + [ + { + collabId: 'id1', + collabType: CollabType.Document, + }, + ], + StrategyType.CACHE_AND_NETWORK + ); + + expect(mockBatchFetcher).toHaveBeenCalled(); + expect(applyYDoc).toHaveBeenCalled(); + }); + + it('should batch fetch collabs with CACHE_AND_NETWORK strategy and no cache', async () => { + (openCollabDB as jest.Mock).mockResolvedValue(emptyDoc); + + (getCollabDBName as jest.Mock).mockReturnValue('testDB'); + mockBatchFetcher.mockResolvedValue({ id1: [1, 2, 3] }); + + await batchCollab( + mockBatchFetcher, + [ + { + collabId: 'id1', + collabType: CollabType.Document, + }, + ], + StrategyType.CACHE_AND_NETWORK + ); + + expect(mockBatchFetcher).toHaveBeenCalled(); + expect(applyYDoc).toHaveBeenCalled(); + }); + }); + }); +}); + +describe('collabTypeToDBType', () => { + it('should return correct DB type', () => { + expect(collabTypeToDBType(CollabType.Document)).toBe('document'); + expect(collabTypeToDBType(CollabType.Folder)).toBe('folder'); + expect(collabTypeToDBType(CollabType.Database)).toBe('database'); + expect(collabTypeToDBType(CollabType.WorkspaceDatabase)).toBe('databases'); + expect(collabTypeToDBType(CollabType.DatabaseRow)).toBe('database_row'); + expect(collabTypeToDBType(CollabType.UserAwareness)).toBe('user_awareness'); + expect(collabTypeToDBType(CollabType.Empty)).toBe(''); + }); +}); diff --git a/frontend/appflowy_web_app/src/application/services/js-services/__tests__/fetch.test.ts b/frontend/appflowy_web_app/src/application/services/js-services/__tests__/fetch.test.ts new file mode 100644 index 0000000000..afdc418c2a --- /dev/null +++ b/frontend/appflowy_web_app/src/application/services/js-services/__tests__/fetch.test.ts @@ -0,0 +1,57 @@ +import { expect } from '@jest/globals'; +import { fetchCollab, batchFetchCollab } from '../fetch'; +import { CollabType } from '@/application/collab.type'; +import { APIService } from '@/application/services/js-services/wasm'; + +jest.mock('@/application/services/js-services/wasm', () => { + return { + APIService: { + getCollab: jest.fn(), + batchGetCollab: jest.fn(), + }, + }; +}); + +describe('Collab fetch functions with deduplication', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('fetchCollab', () => { + it('should fetch collab without duplicating requests', async () => { + const workspaceId = 'workspace1'; + const id = 'id1'; + const type = CollabType.Document; + const mockResponse = { data: 'mockData' }; + + (APIService.getCollab as jest.Mock).mockResolvedValue(mockResponse); + + const result1 = fetchCollab(workspaceId, id, type); + const result2 = fetchCollab(workspaceId, id, type); + + expect(result1).toBe(result2); + await expect(result1).resolves.toEqual(mockResponse); + expect(APIService.getCollab).toHaveBeenCalledTimes(1); + }); + }); + + describe('batchFetchCollab', () => { + it('should batch fetch collabs without duplicating requests', async () => { + const workspaceId = 'workspace1'; + const params = [ + { collabId: 'id1', collabType: CollabType.Document }, + { collabId: 'id2', collabType: CollabType.Folder }, + ]; + const mockResponse = { data: 'mockData' }; + + (APIService.batchGetCollab as jest.Mock).mockResolvedValue(mockResponse); + + const result1 = batchFetchCollab(workspaceId, params); + const result2 = batchFetchCollab(workspaceId, params); + + expect(result1).toBe(result2); + await expect(result1).resolves.toEqual(mockResponse); + expect(APIService.batchGetCollab).toHaveBeenCalledTimes(1); + }); + }); +}); diff --git a/frontend/appflowy_web_app/src/application/services/js-services/auth.service.ts b/frontend/appflowy_web_app/src/application/services/js-services/auth.service.ts index 7119497775..7f80c9f871 100644 --- a/frontend/appflowy_web_app/src/application/services/js-services/auth.service.ts +++ b/frontend/appflowy_web_app/src/application/services/js-services/auth.service.ts @@ -1,8 +1,8 @@ import { AuthService } from '@/application/services/services.type'; import { ProviderType, SignUpWithEmailPasswordParams } from '@/application/user.type'; import { APIService } from 'src/application/services/js-services/wasm'; -import { signInSuccess } from '@/application/services/js-services/storage/auth'; -import { invalidToken } from '@/application/services/js-services/storage'; +import { signInSuccess } from '@/application/services/js-services/session/auth'; +import { invalidToken } from 'src/application/services/js-services/session'; import { afterSignInDecorator } from '@/application/services/js-services/decorator'; export class JSAuthService implements AuthService { diff --git a/frontend/appflowy_web_app/src/application/services/js-services/db/index.ts b/frontend/appflowy_web_app/src/application/services/js-services/cache/db.ts similarity index 76% rename from frontend/appflowy_web_app/src/application/services/js-services/db/index.ts rename to frontend/appflowy_web_app/src/application/services/js-services/cache/db.ts index f17ac50531..a4d888498b 100644 --- a/frontend/appflowy_web_app/src/application/services/js-services/db/index.ts +++ b/frontend/appflowy_web_app/src/application/services/js-services/cache/db.ts @@ -1,9 +1,10 @@ import { YDoc } from '@/application/collab.type'; import { databasePrefix } from '@/application/constants'; -import { getAuthInfo } from '@/application/services/js-services/storage'; import { IndexeddbPersistence } from 'y-indexeddb'; import * as Y from 'yjs'; +const openedSet = new Set(); + /** * Open the collaboration database, and return a function to close it */ @@ -19,6 +20,10 @@ export async function openCollabDB(docName: string): Promise { }); provider.on('synced', () => { + if (!openedSet.has(name)) { + openedSet.add(name); + } + resolve(true); }); @@ -27,9 +32,10 @@ export async function openCollabDB(docName: string): Promise { return doc as YDoc; } -export function getDBName(id: string, type: string) { - const { uuid } = getAuthInfo() || {}; +export function getCollabDBName(id: string, type: string, uuid?: string) { + if (!uuid) { + return `${type}_${id}`; + } - if (!uuid) throw new Error('No user found'); return `${uuid}_${type}_${id}`; } diff --git a/frontend/appflowy_web_app/src/application/services/js-services/cache/index.ts b/frontend/appflowy_web_app/src/application/services/js-services/cache/index.ts new file mode 100644 index 0000000000..1f7fe670f1 --- /dev/null +++ b/frontend/appflowy_web_app/src/application/services/js-services/cache/index.ts @@ -0,0 +1,165 @@ +import { CollabType, YDoc, YjsEditorKey, YSharedRoot } from '@/application/collab.type'; +import { applyYDoc } from '@/application/ydoc/apply'; +import { getCollabDBName, openCollabDB } from './db'; +import { Fetcher, StrategyType } from './types'; + +export function collabTypeToDBType(type: CollabType) { + switch (type) { + case CollabType.Folder: + return 'folder'; + case CollabType.Document: + return 'document'; + case CollabType.Database: + return 'database'; + case CollabType.WorkspaceDatabase: + return 'databases'; + case CollabType.DatabaseRow: + return 'database_row'; + case CollabType.UserAwareness: + return 'user_awareness'; + default: + return ''; + } +} + +const collabSharedRootKeyMap = { + [CollabType.Folder]: YjsEditorKey.folder, + [CollabType.Document]: YjsEditorKey.document, + [CollabType.Database]: YjsEditorKey.database, + [CollabType.WorkspaceDatabase]: YjsEditorKey.workspace_database, + [CollabType.DatabaseRow]: YjsEditorKey.database_row, + [CollabType.UserAwareness]: YjsEditorKey.user_awareness, + [CollabType.Empty]: YjsEditorKey.empty, +}; + +export function hasCache(doc: YDoc, type: CollabType) { + const data = doc.getMap(YjsEditorKey.data_section) as YSharedRoot; + + return data.has(collabSharedRootKeyMap[type] as string); +} + +export async function getCollab( + fetcher: Fetcher<{ + state: Uint8Array; + }>, + { + collabId, + collabType, + uuid, + }: { + uuid?: string; + collabId: string; + collabType: CollabType; + }, + strategy: StrategyType = StrategyType.CACHE_AND_NETWORK +) { + const name = getCollabDBName(collabId, collabTypeToDBType(collabType), uuid); + const collab = await openCollabDB(name); + const exist = hasCache(collab, collabType); + + switch (strategy) { + case StrategyType.CACHE_ONLY: { + if (!exist) { + throw new Error('No cache found'); + } + + return collab; + } + + case StrategyType.CACHE_FIRST: { + if (!exist) { + await revalidateCollab(fetcher, collab); + } + + return collab; + } + + case StrategyType.CACHE_AND_NETWORK: { + if (!exist) { + await revalidateCollab(fetcher, collab); + } else { + void revalidateCollab(fetcher, collab); + } + + return collab; + } + + default: { + await revalidateCollab(fetcher, collab); + + return collab; + } + } +} + +async function revalidateCollab( + fetcher: Fetcher<{ + state: Uint8Array; + }>, + collab: YDoc +) { + const { state } = await fetcher(); + + applyYDoc(collab, state); +} + +export async function batchCollab( + batchFetcher: Fetcher>, + collabs: { + collabId: string; + collabType: CollabType; + uuid?: string; + }[], + strategy: StrategyType = StrategyType.CACHE_AND_NETWORK, + itemCallback?: (id: string, doc: YDoc) => void +) { + const collabMap = new Map(); + + for (const { collabId, collabType, uuid } of collabs) { + const name = getCollabDBName(collabId, collabTypeToDBType(collabType), uuid); + const collab = await openCollabDB(name); + const exist = hasCache(collab, collabType); + + collabMap.set(collabId, collab); + if (exist) { + itemCallback?.(collabId, collab); + } + } + + const notCacheIds = collabs.filter(({ collabId, collabType }) => { + const id = collabMap.get(collabId); + + if (!id) return false; + + return !hasCache(id, collabType); + }); + + if (strategy === StrategyType.CACHE_ONLY) { + if (notCacheIds.length > 0) { + throw new Error('No cache found'); + } + + return; + } + + if (strategy === StrategyType.CACHE_FIRST && notCacheIds.length === 0) { + return; + } + + const states = await batchFetcher(); + + for (const [collabId, data] of Object.entries(states)) { + const info = collabs.find((item) => item.collabId === collabId); + const collab = collabMap.get(collabId); + + if (!info || !collab) { + continue; + } + + const state = new Uint8Array(data); + + applyYDoc(collab, state); + + itemCallback?.(collabId, collab); + } +} diff --git a/frontend/appflowy_web_app/src/application/services/js-services/cache/types.ts b/frontend/appflowy_web_app/src/application/services/js-services/cache/types.ts new file mode 100644 index 0000000000..1c1a949723 --- /dev/null +++ b/frontend/appflowy_web_app/src/application/services/js-services/cache/types.ts @@ -0,0 +1,12 @@ +export enum StrategyType { + // Cache only: return the cache if it exists, otherwise throw an error + CACHE_ONLY = 'CACHE_ONLY', + // Cache first: return the cache if it exists, otherwise fetch from the network + CACHE_FIRST = 'CACHE_FIRST', + // Cache and network: return the cache if it exists, otherwise fetch from the network and update the cache + CACHE_AND_NETWORK = 'CACHE_AND_NETWORK', + // Network only: fetch from the network and update the cache + NETWORK_ONLY = 'NETWORK_ONLY', +} + +export type Fetcher = () => Promise; diff --git a/frontend/appflowy_web_app/src/application/services/js-services/database.service.ts b/frontend/appflowy_web_app/src/application/services/js-services/database.service.ts index b1dcfe8d0f..cf29b221dd 100644 --- a/frontend/appflowy_web_app/src/application/services/js-services/database.service.ts +++ b/frontend/appflowy_web_app/src/application/services/js-services/database.service.ts @@ -1,16 +1,16 @@ import { CollabType, YDatabase, YDoc, YjsDatabaseKey, YjsEditorKey } from '@/application/collab.type'; -import { - batchCollabs, - getCollabStorage, - getCollabStorageWithAPICall, - getCurrentWorkspace, -} from '@/application/services/js-services/storage'; +import { batchCollab, getCollab } from '@/application/services/js-services/cache'; +import { StrategyType } from '@/application/services/js-services/cache/types'; +import { batchFetchCollab, fetchCollab } from '@/application/services/js-services/fetch'; +import { getCurrentWorkspace } from 'src/application/services/js-services/session'; import { DatabaseService } from '@/application/services/services.type'; import * as Y from 'yjs'; export class JSDatabaseService implements DatabaseService { private loadedDatabaseId: Set = new Set(); + private loadedWorkspaceId: Set = new Set(); + private cacheDatabaseRowDocMap: Map = new Map(); constructor() { @@ -28,22 +28,30 @@ export class JSDatabaseService implements DatabaseService { throw new Error('Workspace database not found'); } - const workspaceDatabase = await getCollabStorageWithAPICall( - workspace.id, - workspace.workspaceDatabaseId, - CollabType.WorkspaceDatabase + const isLoaded = this.loadedWorkspaceId.has(workspace.id); + + const workspaceDatabase = await getCollab( + () => { + return fetchCollab(workspace.id, workspace.workspaceDatabaseId, CollabType.WorkspaceDatabase); + }, + { + collabId: workspace.workspaceDatabaseId, + collabType: CollabType.WorkspaceDatabase, + }, + isLoaded ? StrategyType.CACHE_FIRST : StrategyType.CACHE_AND_NETWORK ); + if (!isLoaded) { + this.loadedWorkspaceId.add(workspace.id); + } + return workspaceDatabase.getMap(YjsEditorKey.data_section).get(YjsEditorKey.workspace_database).toJSON() as { views: string[]; database_id: string; }[]; } - async openDatabase( - databaseId: string, - rowIds?: string[] - ): Promise<{ + async openDatabase(databaseId: string): Promise<{ databaseDoc: YDoc; rows: Y.Map; }> { @@ -68,13 +76,18 @@ export class JSDatabaseService implements DatabaseService { const rowsFolder: Y.Map = rootRowsDoc.getMap(); - let databaseDoc: YDoc | undefined = undefined; + const databaseDoc = await getCollab( + () => { + return fetchCollab(workspaceId, databaseId, CollabType.Database); + }, + { + collabId: databaseId, + collabType: CollabType.Database, + }, + isLoaded ? StrategyType.CACHE_FIRST : StrategyType.CACHE_AND_NETWORK + ); - if (isLoaded) { - databaseDoc = (await getCollabStorage(databaseId, CollabType.Database)).doc; - } else { - databaseDoc = await getCollabStorageWithAPICall(workspaceId, databaseId, CollabType.Database); - } + if (!isLoaded) this.loadedDatabaseId.add(databaseId); const database = databaseDoc.getMap(YjsEditorKey.data_section)?.get(YjsEditorKey.database) as YDatabase; const viewId = database.get(YjsDatabaseKey.metas)?.get(YjsDatabaseKey.iid)?.toString(); @@ -87,47 +100,50 @@ export class JSDatabaseService implements DatabaseService { throw new Error('Database rows not found'); } - const ids = rowIds ? rowIds : rowOrdersIds.map((item) => item.id); - - if (isLoaded) { - for (const id of ids) { - const { doc } = await getCollabStorage(id, CollabType.DatabaseRow); + const rowsParams = rowOrdersIds.map((item) => ({ + collabId: item.id, + collabType: CollabType.DatabaseRow, + })); + void batchCollab( + () => { + return batchFetchCollab(workspaceId, rowsParams); + }, + rowsParams, + isLoaded ? StrategyType.CACHE_FIRST : StrategyType.CACHE_AND_NETWORK, + (id: string, doc: YDoc) => { if (!rowsFolder.has(id)) { rowsFolder.set(id, doc); } } - } else { - void this.loadDatabaseRows(workspaceId, ids, (id, row) => { - if (!rowsFolder.has(id)) { - rowsFolder.set(id, row); - } - }); - } + ); - this.loadedDatabaseId.add(databaseId); + // Update rows if there are new rows added after the database has been loaded + rowOrders?.observe((event) => { + if (event.changes.added.size > 0) { + const rowIds = rowOrders.toJSON() as { + id: string; + }[]; - if (!rowIds) { - // Update rows if new rows are added - rowOrders?.observe((event) => { - if (event.changes.added.size > 0) { - const rowIds = rowOrders.toJSON() as { - id: string; - }[]; + const params = rowIds.map((item) => ({ + collabId: item.id, + collabType: CollabType.DatabaseRow, + })); - console.log('Update rows', rowIds); - void this.loadDatabaseRows( - workspaceId, - rowIds.map((item) => item.id), - (rowId: string, rowDoc) => { - if (!rowsFolder.has(rowId)) { - rowsFolder.set(rowId, rowDoc); - } + void batchCollab( + () => { + return batchFetchCollab(workspaceId, params); + }, + params, + StrategyType.CACHE_AND_NETWORK, + (id: string, doc: YDoc) => { + if (!rowsFolder.has(id)) { + rowsFolder.set(id, doc); } - ); - } - }); - } + } + ); + } + }); return { databaseDoc, @@ -135,21 +151,6 @@ export class JSDatabaseService implements DatabaseService { }; } - async loadDatabaseRows(workspaceId: string, rowIds: string[], rowCallback: (rowId: string, rowDoc: YDoc) => void) { - try { - await batchCollabs( - workspaceId, - rowIds.map((id) => ({ - object_id: id, - collab_type: CollabType.DatabaseRow, - })), - rowCallback - ); - } catch (e) { - console.error(e); - } - } - async closeDatabase(databaseId: string) { this.cacheDatabaseRowDocMap.delete(databaseId); } diff --git a/frontend/appflowy_web_app/src/application/services/js-services/document.service.ts b/frontend/appflowy_web_app/src/application/services/js-services/document.service.ts index cc3d3dd411..bcf73ae550 100644 --- a/frontend/appflowy_web_app/src/application/services/js-services/document.service.ts +++ b/frontend/appflowy_web_app/src/application/services/js-services/document.service.ts @@ -1,8 +1,13 @@ import { CollabOrigin, CollabType, YDoc } from '@/application/collab.type'; -import { getCollabStorageWithAPICall, getCurrentWorkspace } from '@/application/services/js-services/storage'; +import { getCollab } from '@/application/services/js-services/cache'; +import { StrategyType } from '@/application/services/js-services/cache/types'; +import { fetchCollab } from '@/application/services/js-services/fetch'; +import { getCurrentWorkspace } from 'src/application/services/js-services/session'; import { DocumentService } from '@/application/services/services.type'; export class JSDocumentService implements DocumentService { + private loaded: Set = new Set(); + constructor() { // } @@ -14,8 +19,20 @@ export class JSDocumentService implements DocumentService { throw new Error('Workspace database not found'); } - const doc = await getCollabStorageWithAPICall(workspace.id, docId, CollabType.Document); + const isLoaded = this.loaded.has(docId); + const doc = await getCollab( + () => { + return fetchCollab(workspace.id, docId, CollabType.Document); + }, + { + collabId: docId, + collabType: CollabType.Document, + }, + isLoaded ? StrategyType.CACHE_FIRST : StrategyType.CACHE_AND_NETWORK + ); + + if (!isLoaded) this.loaded.add(docId); const handleUpdate = (update: Uint8Array, origin: CollabOrigin) => { if (origin === CollabOrigin.LocalSync) { // Send the update to the server diff --git a/frontend/appflowy_web_app/src/application/services/js-services/fetch.ts b/frontend/appflowy_web_app/src/application/services/js-services/fetch.ts new file mode 100644 index 0000000000..7ae4dc8902 --- /dev/null +++ b/frontend/appflowy_web_app/src/application/services/js-services/fetch.ts @@ -0,0 +1,66 @@ +import { CollabType } from '@/application/collab.type'; +import { APIService } from '@/application/services/js-services/wasm'; + +const pendingRequests = new Map(); + +function generateRequestKey(url: string, params: T) { + if (!params) return url; + + try { + return `${url}_${JSON.stringify(params)}`; + } catch (_e) { + return `${url}_${params}`; + } +} + +// Deduplication fetch requests +// When multiple requests are made to the same URL with the same params, only one request is made +// and the result is shared with all the requests +function fetchWithDeduplication(url: string, params: Req, fetchFunction: () => Promise): Promise { + const requestKey = generateRequestKey(url, params); + + if (pendingRequests.has(requestKey)) { + return pendingRequests.get(requestKey); + } + + const fetchPromise = fetchFunction().finally(() => { + pendingRequests.delete(requestKey); + }); + + pendingRequests.set(requestKey, fetchPromise); + return fetchPromise; +} + +/** + * Fetch collab + * @param workspaceId + * @param id + * @param type [CollabType] + */ +export function fetchCollab(workspaceId: string, id: string, type: CollabType) { + const fetchFunction = () => APIService.getCollab(workspaceId, id, type); + + return fetchWithDeduplication(`fetchCollab_${workspaceId}`, { id, type }, fetchFunction); +} + +/** + * Batch fetch collab + * Usage: + * // load database rows + * const rows = await batchFetchCollab(workspaceId, databaseRows.map((row) => ({ collabId: row.id, collabType: CollabType.DatabaseRow }))); + * + * @param workspaceId + * @param params [{ collabId: string; collabType: CollabType }] + */ +export function batchFetchCollab(workspaceId: string, params: { collabId: string; collabType: CollabType }[]) { + const fetchFunction = () => + APIService.batchGetCollab( + workspaceId, + params.map(({ collabId, collabType }) => ({ + object_id: collabId, + collab_type: collabType, + })) + ); + + return fetchWithDeduplication(`batchFetchCollab_${workspaceId}`, params, fetchFunction); +} diff --git a/frontend/appflowy_web_app/src/application/services/js-services/folder.service.ts b/frontend/appflowy_web_app/src/application/services/js-services/folder.service.ts index c475cfa935..f145480c18 100644 --- a/frontend/appflowy_web_app/src/application/services/js-services/folder.service.ts +++ b/frontend/appflowy_web_app/src/application/services/js-services/folder.service.ts @@ -1,14 +1,30 @@ import { CollabOrigin, CollabType, YDoc } from '@/application/collab.type'; -import { getCollabStorageWithAPICall } from '@/application/services/js-services/storage'; +import { getCollab } from '@/application/services/js-services/cache'; +import { StrategyType } from '@/application/services/js-services/cache/types'; +import { fetchCollab } from '@/application/services/js-services/fetch'; import { FolderService } from '@/application/services/services.type'; export class JSFolderService implements FolderService { + private loaded: Set = new Set(); + constructor() { // } async openWorkspace(workspaceId: string): Promise { - const doc = await getCollabStorageWithAPICall(workspaceId, workspaceId, CollabType.Folder); + const isLoaded = this.loaded.has(workspaceId); + const doc = await getCollab( + () => { + return fetchCollab(workspaceId, workspaceId, CollabType.Folder); + }, + { + collabId: workspaceId, + collabType: CollabType.Folder, + }, + isLoaded ? StrategyType.CACHE_FIRST : StrategyType.CACHE_AND_NETWORK + ); + + if (!isLoaded) this.loaded.add(workspaceId); const handleUpdate = (update: Uint8Array, origin: CollabOrigin) => { if (origin === CollabOrigin.LocalSync) { // Send the update to the server diff --git a/frontend/appflowy_web_app/src/application/services/js-services/storage/auth.ts b/frontend/appflowy_web_app/src/application/services/js-services/session/auth.ts similarity index 100% rename from frontend/appflowy_web_app/src/application/services/js-services/storage/auth.ts rename to frontend/appflowy_web_app/src/application/services/js-services/session/auth.ts diff --git a/frontend/appflowy_web_app/src/application/services/js-services/storage/index.ts b/frontend/appflowy_web_app/src/application/services/js-services/session/index.ts similarity index 73% rename from frontend/appflowy_web_app/src/application/services/js-services/storage/index.ts rename to frontend/appflowy_web_app/src/application/services/js-services/session/index.ts index f0b9cab2d6..c618a85cfd 100644 --- a/frontend/appflowy_web_app/src/application/services/js-services/storage/index.ts +++ b/frontend/appflowy_web_app/src/application/services/js-services/session/index.ts @@ -1,4 +1,3 @@ export * from './token'; export * from './user'; -export * from './collab'; export * from './auth'; diff --git a/frontend/appflowy_web_app/src/application/services/js-services/storage/token.ts b/frontend/appflowy_web_app/src/application/services/js-services/session/token.ts similarity index 100% rename from frontend/appflowy_web_app/src/application/services/js-services/storage/token.ts rename to frontend/appflowy_web_app/src/application/services/js-services/session/token.ts diff --git a/frontend/appflowy_web_app/src/application/services/js-services/storage/user.ts b/frontend/appflowy_web_app/src/application/services/js-services/session/user.ts similarity index 100% rename from frontend/appflowy_web_app/src/application/services/js-services/storage/user.ts rename to frontend/appflowy_web_app/src/application/services/js-services/session/user.ts diff --git a/frontend/appflowy_web_app/src/application/services/js-services/storage/collab.ts b/frontend/appflowy_web_app/src/application/services/js-services/storage/collab.ts deleted file mode 100644 index 6b315658f5..0000000000 --- a/frontend/appflowy_web_app/src/application/services/js-services/storage/collab.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { CollabType, YDoc, YjsEditorKey, YSharedRoot } from '@/application/collab.type'; -import { getDBName, openCollabDB } from '@/application/services/js-services/db'; -import { APIService } from '@/application/services/js-services/wasm'; -import { applyYDoc } from '@/application/ydoc/apply'; - -export function fetchCollab(workspaceId: string, id: string, type: CollabType) { - return APIService.getCollab(workspaceId, id, type); -} - -export function batchFetchCollab(workspaceId: string, params: { object_id: string; collab_type: CollabType }[]) { - return APIService.batchGetCollab(workspaceId, params); -} - -function collabTypeToDBType(type: CollabType) { - switch (type) { - case CollabType.Folder: - return 'folder'; - case CollabType.Document: - return 'document'; - case CollabType.Database: - return 'database'; - case CollabType.WorkspaceDatabase: - return 'databases'; - case CollabType.DatabaseRow: - return 'database_row'; - case CollabType.UserAwareness: - return 'user_awareness'; - default: - return ''; - } -} - -const collabSharedRootKeyMap = { - [CollabType.Folder]: YjsEditorKey.folder, - [CollabType.Document]: YjsEditorKey.document, - [CollabType.Database]: YjsEditorKey.database, - [CollabType.WorkspaceDatabase]: YjsEditorKey.workspace_database, - [CollabType.DatabaseRow]: YjsEditorKey.database_row, - [CollabType.UserAwareness]: YjsEditorKey.user_awareness, - [CollabType.Empty]: YjsEditorKey.empty, -}; - -export async function getCollabStorage(id: string, type: CollabType) { - const name = getDBName(id, collabTypeToDBType(type)); - - const doc = await openCollabDB(name); - let localExist = false; - const existData = doc.share.has(YjsEditorKey.data_section); - - if (existData) { - const data = doc.getMap(YjsEditorKey.data_section) as YSharedRoot; - - localExist = data.has(collabSharedRootKeyMap[type] as string); - } - - return { - doc, - localExist, - }; -} - -export async function getCollabStorageWithAPICall(workspaceId: string, id: string, type: CollabType) { - const { doc, localExist } = await getCollabStorage(id, type); - const asyncApply = async () => { - const res = await fetchCollab(workspaceId, id, type); - - applyYDoc(doc, res.state); - }; - - // If the document exists locally, apply the state asynchronously, - // otherwise, apply the state synchronously - if (localExist) { - void asyncApply(); - } else { - await asyncApply(); - } - - return doc; -} - -export async function batchCollabs( - workspaceId: string, - params: { - object_id: string; - collab_type: CollabType; - }[], - rowCallback?: (id: string, doc: YDoc) => void -) { - console.log('Fetching collab data:', params); - // Create or get Y.Doc from local storage - for (const item of params) { - const { object_id, collab_type } = item; - - const { doc, localExist } = await getCollabStorage(object_id, collab_type); - - if (rowCallback && localExist) { - rowCallback(object_id, doc); - } - } - - const res = await batchFetchCollab(workspaceId, params); - - console.log('Fetched collab data:', res); - for (const id of Object.keys(res)) { - const type = params.find((param) => param.object_id === id)?.collab_type; - const data = res[id]; - - if (type === undefined || !data) { - continue; - } - - const { doc } = await getCollabStorage(id, type); - - applyYDoc(doc, new Uint8Array(data)); - - rowCallback?.(id, doc); - } -} diff --git a/frontend/appflowy_web_app/src/application/services/js-services/user.service.ts b/frontend/appflowy_web_app/src/application/services/js-services/user.service.ts index c4853f850d..ce912bd50f 100644 --- a/frontend/appflowy_web_app/src/application/services/js-services/user.service.ts +++ b/frontend/appflowy_web_app/src/application/services/js-services/user.service.ts @@ -8,7 +8,7 @@ import { invalidToken, setSignInUser, setUserWorkspace, -} from '@/application/services/js-services/storage'; +} from 'src/application/services/js-services/session'; import { asyncDataDecorator } from '@/application/services/js-services/decorator'; async function getUser() { diff --git a/frontend/appflowy_web_app/src/application/services/js-services/wasm/client_api.ts b/frontend/appflowy_web_app/src/application/services/js-services/wasm/client_api.ts index 6b50ca27e5..cd09cb74d1 100644 --- a/frontend/appflowy_web_app/src/application/services/js-services/wasm/client_api.ts +++ b/frontend/appflowy_web_app/src/application/services/js-services/wasm/client_api.ts @@ -2,7 +2,7 @@ import { CollabType } from '@/application/collab.type'; import { ClientAPI } from '@appflowyinc/client-api-wasm'; import { UserProfile, UserWorkspace } from '@/application/user.type'; import { AFCloudConfig } from '@/application/services/services.type'; -import { invalidToken, readTokenStr, writeToken } from '@/application/services/js-services/storage'; +import { invalidToken, readTokenStr, writeToken } from 'src/application/services/js-services/session'; let client: ClientAPI; diff --git a/frontend/appflowy_web_app/src/components/_shared/not-found/RecordNotFound.tsx b/frontend/appflowy_web_app/src/components/_shared/not-found/RecordNotFound.tsx index 76d0f7575c..a7ef1d2684 100644 --- a/frontend/appflowy_web_app/src/components/_shared/not-found/RecordNotFound.tsx +++ b/frontend/appflowy_web_app/src/components/_shared/not-found/RecordNotFound.tsx @@ -1,4 +1,4 @@ -import { getCurrentWorkspace } from '@/application/services/js-services/storage'; +import { getCurrentWorkspace } from 'src/application/services/js-services/session'; import { Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle } from '@mui/material'; import React from 'react'; import { useNavigate } from 'react-router-dom'; diff --git a/frontend/appflowy_web_app/src/components/database/Database.tsx b/frontend/appflowy_web_app/src/components/database/Database.tsx index 6c7c3a4868..0c590462f9 100644 --- a/frontend/appflowy_web_app/src/components/database/Database.tsx +++ b/frontend/appflowy_web_app/src/components/database/Database.tsx @@ -12,7 +12,6 @@ export const Database = memo( viewId: string; onNavigateToView: (viewId: string) => void; }) => { - console.log('Database', viewId, iidIndex); return (
diff --git a/frontend/appflowy_web_app/src/components/editor/components/blocks/database/DatabaseBlock.tsx b/frontend/appflowy_web_app/src/components/editor/components/blocks/database/DatabaseBlock.tsx index a563557ab7..1e6bbb151a 100644 --- a/frontend/appflowy_web_app/src/components/editor/components/blocks/database/DatabaseBlock.tsx +++ b/frontend/appflowy_web_app/src/components/editor/components/blocks/database/DatabaseBlock.tsx @@ -1,6 +1,6 @@ import { ReactComponent as ExpandMoreIcon } from '$icons/16x/full_view.svg'; import { useNavigateToView } from '@/application/folder-yjs'; -import { getCurrentWorkspace } from '@/application/services/js-services/storage'; +import { getCurrentWorkspace } from 'src/application/services/js-services/session'; import { IdProvider } from '@/components/_shared/context-provider/IdProvider'; import { Database } from '@/components/database'; import { useGetDatabaseId, useLoadDatabase } from '@/components/database/Database.hooks'; diff --git a/frontend/appflowy_web_app/src/components/layout/breadcrumb/Item.tsx b/frontend/appflowy_web_app/src/components/layout/breadcrumb/Item.tsx index 1f58950e58..7d857ac893 100644 --- a/frontend/appflowy_web_app/src/components/layout/breadcrumb/Item.tsx +++ b/frontend/appflowy_web_app/src/components/layout/breadcrumb/Item.tsx @@ -9,19 +9,19 @@ import { ReactComponent as CalendarSvg } from '$icons/16x/date.svg'; const renderCrumbIcon = (icon: string) => { if (Number(icon) === ViewLayout.Grid) { - return ; + return ; } if (Number(icon) === ViewLayout.Board) { - return ; + return ; } if (Number(icon) === ViewLayout.Calendar) { - return ; + return ; } if (Number(icon) === ViewLayout.Document) { - return ; + return ; } return icon; @@ -41,7 +41,7 @@ function Item({ crumb, disableClick = false }: { crumb: Crumb; disableClick?: bo onNavigateToView?.(viewId); }} > - {renderCrumbIcon(icon)} + {renderCrumbIcon(icon)} From 94060a0a9983765d2007c625eb30429e1d2ffd2d Mon Sep 17 00:00:00 2001 From: "Kilu.He" <108015703+qinluhe@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:42:09 +0800 Subject: [PATCH 13/16] fix: generate default document data from document id (#5430) * fix: generate default document data from document id * fix: update version --- frontend/appflowy_tauri/src-tauri/Cargo.lock | 15 ++++++++------- frontend/appflowy_tauri/src-tauri/Cargo.toml | 14 +++++++------- frontend/appflowy_web_app/src-tauri/Cargo.lock | 15 ++++++++------- frontend/appflowy_web_app/src-tauri/Cargo.toml | 14 +++++++------- frontend/rust-lib/Cargo.lock | 15 ++++++++------- frontend/rust-lib/Cargo.toml | 14 +++++++------- frontend/rust-lib/flowy-document/src/manager.rs | 12 +++++++----- .../tests/document/document_redo_undo_test.rs | 2 +- .../tests/document/document_test.rs | 8 ++++---- .../flowy-document/tests/document/util.rs | 2 +- .../src/migrations/document_empty_content.rs | 2 +- 11 files changed, 59 insertions(+), 54 deletions(-) diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.lock b/frontend/appflowy_tauri/src-tauri/Cargo.lock index 6a94085951..9dae4b3b63 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.lock +++ b/frontend/appflowy_tauri/src-tauri/Cargo.lock @@ -877,7 +877,7 @@ dependencies = [ [[package]] name = "collab" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "async-trait", @@ -901,7 +901,7 @@ dependencies = [ [[package]] name = "collab-database" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "async-trait", @@ -931,7 +931,7 @@ dependencies = [ [[package]] name = "collab-document" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "collab", @@ -945,12 +945,13 @@ dependencies = [ "tokio", "tokio-stream", "tracing", + "uuid", ] [[package]] name = "collab-entity" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "bytes", @@ -965,7 +966,7 @@ dependencies = [ [[package]] name = "collab-folder" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "chrono", @@ -1003,7 +1004,7 @@ dependencies = [ [[package]] name = "collab-plugins" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "async-stream", @@ -1084,7 +1085,7 @@ dependencies = [ [[package]] name = "collab-user" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "collab", diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.toml b/frontend/appflowy_tauri/src-tauri/Cargo.toml index ea09264aad..6bb9cb9db6 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.toml +++ b/frontend/appflowy_tauri/src-tauri/Cargo.toml @@ -106,10 +106,10 @@ default = ["custom-protocol"] custom-protocol = ["tauri/custom-protocol"] [patch.crates-io] -collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } +collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } diff --git a/frontend/appflowy_web_app/src-tauri/Cargo.lock b/frontend/appflowy_web_app/src-tauri/Cargo.lock index 43806f61fb..12d5ca3b63 100644 --- a/frontend/appflowy_web_app/src-tauri/Cargo.lock +++ b/frontend/appflowy_web_app/src-tauri/Cargo.lock @@ -860,7 +860,7 @@ dependencies = [ [[package]] name = "collab" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "async-trait", @@ -884,7 +884,7 @@ dependencies = [ [[package]] name = "collab-database" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "async-trait", @@ -914,7 +914,7 @@ dependencies = [ [[package]] name = "collab-document" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "collab", @@ -928,12 +928,13 @@ dependencies = [ "tokio", "tokio-stream", "tracing", + "uuid", ] [[package]] name = "collab-entity" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "bytes", @@ -948,7 +949,7 @@ dependencies = [ [[package]] name = "collab-folder" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "chrono", @@ -986,7 +987,7 @@ dependencies = [ [[package]] name = "collab-plugins" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "async-stream", @@ -1067,7 +1068,7 @@ dependencies = [ [[package]] name = "collab-user" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "collab", diff --git a/frontend/appflowy_web_app/src-tauri/Cargo.toml b/frontend/appflowy_web_app/src-tauri/Cargo.toml index 8625530b8c..6f03972195 100644 --- a/frontend/appflowy_web_app/src-tauri/Cargo.toml +++ b/frontend/appflowy_web_app/src-tauri/Cargo.toml @@ -107,10 +107,10 @@ default = ["custom-protocol"] custom-protocol = ["tauri/custom-protocol"] [patch.crates-io] -collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } +collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } diff --git a/frontend/rust-lib/Cargo.lock b/frontend/rust-lib/Cargo.lock index e3570807f0..abc72ec7c5 100644 --- a/frontend/rust-lib/Cargo.lock +++ b/frontend/rust-lib/Cargo.lock @@ -754,7 +754,7 @@ dependencies = [ [[package]] name = "collab" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "async-trait", @@ -778,7 +778,7 @@ dependencies = [ [[package]] name = "collab-database" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "async-trait", @@ -808,7 +808,7 @@ dependencies = [ [[package]] name = "collab-document" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "collab", @@ -822,12 +822,13 @@ dependencies = [ "tokio", "tokio-stream", "tracing", + "uuid", ] [[package]] name = "collab-entity" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "bytes", @@ -842,7 +843,7 @@ dependencies = [ [[package]] name = "collab-folder" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "chrono", @@ -880,7 +881,7 @@ dependencies = [ [[package]] name = "collab-plugins" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "async-stream", @@ -961,7 +962,7 @@ dependencies = [ [[package]] name = "collab-user" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "collab", diff --git a/frontend/rust-lib/Cargo.toml b/frontend/rust-lib/Cargo.toml index 966240ac22..39dccadd26 100644 --- a/frontend/rust-lib/Cargo.toml +++ b/frontend/rust-lib/Cargo.toml @@ -132,10 +132,10 @@ rocksdb = { git = "https://github.com/LucasXu0/rust-rocksdb", rev = "21cf4a23ec1 # To switch to the local path, run: # scripts/tool/update_collab_source.sh # ⚠️⚠️⚠️️ -collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } +collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } diff --git a/frontend/rust-lib/flowy-document/src/manager.rs b/frontend/rust-lib/flowy-document/src/manager.rs index fb3b203b4e..9edaccc796 100644 --- a/frontend/rust-lib/flowy-document/src/manager.rs +++ b/frontend/rust-lib/flowy-document/src/manager.rs @@ -119,11 +119,13 @@ impl DocumentManager { format!("document {} already exists", doc_id), )) } else { - let doc_state = - doc_state_from_document_data(doc_id, data.unwrap_or_else(default_document_data)) - .await? - .doc_state - .to_vec(); + let doc_state = doc_state_from_document_data( + doc_id, + data.unwrap_or_else(|| default_document_data(doc_id)), + ) + .await? + .doc_state + .to_vec(); let collab = self .collab_for_document(uid, doc_id, DataSource::DocStateV1(doc_state), false) .await?; diff --git a/frontend/rust-lib/flowy-document/tests/document/document_redo_undo_test.rs b/frontend/rust-lib/flowy-document/tests/document/document_redo_undo_test.rs index fc8268fd71..ad2fa54e34 100644 --- a/frontend/rust-lib/flowy-document/tests/document/document_redo_undo_test.rs +++ b/frontend/rust-lib/flowy-document/tests/document/document_redo_undo_test.rs @@ -10,7 +10,7 @@ async fn undo_redo_test() { let test = DocumentTest::new(); let doc_id: String = gen_document_id(); - let data = default_document_data(); + let data = default_document_data(&doc_id); // create a document _ = test diff --git a/frontend/rust-lib/flowy-document/tests/document/document_test.rs b/frontend/rust-lib/flowy-document/tests/document/document_test.rs index 754cba2ef0..084e58693e 100644 --- a/frontend/rust-lib/flowy-document/tests/document/document_test.rs +++ b/frontend/rust-lib/flowy-document/tests/document/document_test.rs @@ -12,7 +12,7 @@ async fn restore_document() { // create a document let doc_id: String = gen_document_id(); - let data = default_document_data(); + let data = default_document_data(&doc_id); let uid = test.user_service.user_id().unwrap(); test .create_document(uid, &doc_id, Some(data.clone())) @@ -54,7 +54,7 @@ async fn document_apply_insert_action() { let test = DocumentTest::new(); let uid = test.user_service.user_id().unwrap(); let doc_id: String = gen_document_id(); - let data = default_document_data(); + let data = default_document_data(&doc_id); // create a document _ = test.create_document(uid, &doc_id, Some(data.clone())).await; @@ -108,7 +108,7 @@ async fn document_apply_update_page_action() { let test = DocumentTest::new(); let doc_id: String = gen_document_id(); let uid = test.user_service.user_id().unwrap(); - let data = default_document_data(); + let data = default_document_data(&doc_id); // create a document _ = test.create_document(uid, &doc_id, Some(data.clone())).await; @@ -152,7 +152,7 @@ async fn document_apply_update_action() { let test = DocumentTest::new(); let uid = test.user_service.user_id().unwrap(); let doc_id: String = gen_document_id(); - let data = default_document_data(); + let data = default_document_data(&doc_id); // create a document _ = test.create_document(uid, &doc_id, Some(data.clone())).await; diff --git a/frontend/rust-lib/flowy-document/tests/document/util.rs b/frontend/rust-lib/flowy-document/tests/document/util.rs index b08a7ec079..12ad16f44c 100644 --- a/frontend/rust-lib/flowy-document/tests/document/util.rs +++ b/frontend/rust-lib/flowy-document/tests/document/util.rs @@ -115,7 +115,7 @@ pub fn setup_log() { pub async fn create_and_open_empty_document() -> (DocumentTest, Arc, String) { let test = DocumentTest::new(); let doc_id: String = gen_document_id(); - let data = default_document_data(); + let data = default_document_data(&doc_id); let uid = test.user_service.user_id().unwrap(); // create a document test diff --git a/frontend/rust-lib/flowy-user/src/migrations/document_empty_content.rs b/frontend/rust-lib/flowy-user/src/migrations/document_empty_content.rs index bdcd2e5a59..cf59bac68c 100644 --- a/frontend/rust-lib/flowy-user/src/migrations/document_empty_content.rs +++ b/frontend/rust-lib/flowy-user/src/migrations/document_empty_content.rs @@ -93,7 +93,7 @@ where vec![], false, ))); - let document = Document::create_with_data(collab, default_document_data())?; + let document = Document::create_with_data(collab, default_document_data(&view.id))?; let encode = document .get_collab() .lock() From bb3e9d5bd8c9c91583e8c8efdf8fd75fab8573c7 Mon Sep 17 00:00:00 2001 From: "Nathan.fooo" <86001920+appflowy@users.noreply.github.com> Date: Sun, 9 Jun 2024 14:02:32 +0800 Subject: [PATCH 14/16] feat: Stream chat message (#5498) * chore: stream message * chore: stream message * chore: fix streaming * chore: fix clippy --- .../application/chat_ai_message_bloc.dart | 115 ++++- .../ai_chat/application/chat_bloc.dart | 419 ++++++++++++------ .../application/chat_message_listener.dart | 16 +- .../chat_related_question_bloc.dart | 103 ----- .../lib/plugins/ai_chat/chat_page.dart | 150 ++++--- ...ai_message.dart => ai_message_bubble.dart} | 42 +- .../ai_chat/presentation/chat_input.dart | 108 +++-- .../ai_chat/presentation/chat_loading.dart | 18 +- .../presentation/chat_related_question.dart | 36 -- .../presentation/chat_stream_text_field.dart | 10 + .../chat_streaming_error_message.dart | 157 ++++--- .../presentation/chat_welcome_page.dart | 46 +- .../presentation/message/ai_text_message.dart | 295 ++++++++++++ .../message/user_text_message.dart | 60 +++ ..._message.dart => user_message_bubble.dart} | 0 frontend/appflowy_flutter/pubspec.lock | 18 +- frontend/appflowy_flutter/pubspec.yaml | 2 + .../chat_test/chat_load_message_test.dart | 16 + .../test/bloc_test/chat_test/util.dart | 44 ++ frontend/appflowy_flutter/test/util.dart | 10 - frontend/appflowy_tauri/src-tauri/Cargo.lock | 47 +- frontend/appflowy_tauri/src-tauri/Cargo.toml | 2 +- frontend/appflowy_web/wasm-libs/Cargo.lock | 28 +- frontend/appflowy_web/wasm-libs/Cargo.toml | 2 +- .../appflowy_web_app/src-tauri/Cargo.lock | 43 +- .../appflowy_web_app/src-tauri/Cargo.toml | 2 +- .../flowy_icons/16x/ai_stream_stop.svg | 1 + frontend/rust-lib/Cargo.lock | 52 ++- frontend/rust-lib/Cargo.toml | 5 +- .../event-integration-test/src/chat_event.rs | 2 +- frontend/rust-lib/flowy-chat-pub/src/cloud.rs | 26 +- frontend/rust-lib/flowy-chat/Cargo.toml | 4 +- frontend/rust-lib/flowy-chat/src/chat.rs | 319 +++++++------ frontend/rust-lib/flowy-chat/src/entities.rs | 33 +- .../rust-lib/flowy-chat/src/event_handler.rs | 31 +- frontend/rust-lib/flowy-chat/src/event_map.rs | 14 +- frontend/rust-lib/flowy-chat/src/manager.rs | 20 +- .../rust-lib/flowy-chat/src/notification.rs | 6 +- .../src/persistence/chat_message_sql.rs | 35 -- .../src/deps_resolve/folder_deps.rs | 1 + .../flowy-core/src/integrate/trait_impls.rs | 55 +++ .../flowy-server/src/af_cloud/impls/chat.rs | 78 +++- .../rust-lib/flowy-server/src/default_impl.rs | 35 +- frontend/rust-lib/lib-infra/Cargo.toml | 9 +- .../rust-lib/lib-infra/src/isolate_stream.rs | 44 ++ frontend/rust-lib/lib-infra/src/lib.rs | 2 + 46 files changed, 1691 insertions(+), 870 deletions(-) delete mode 100644 frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_related_question_bloc.dart rename frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/{chat_ai_message.dart => ai_message_bubble.dart} (83%) create mode 100644 frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_stream_text_field.dart create mode 100644 frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/message/ai_text_message.dart create mode 100644 frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/message/user_text_message.dart rename frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/{chat_user_message.dart => user_message_bubble.dart} (100%) create mode 100644 frontend/appflowy_flutter/test/bloc_test/chat_test/chat_load_message_test.dart create mode 100644 frontend/appflowy_flutter/test/bloc_test/chat_test/util.dart create mode 100644 frontend/resources/flowy_icons/16x/ai_stream_stop.svg create mode 100644 frontend/rust-lib/lib-infra/src/isolate_stream.rs diff --git a/frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_ai_message_bloc.dart b/frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_ai_message_bloc.dart index 2c5c8f5b0e..a806a5c97d 100644 --- a/frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_ai_message_bloc.dart +++ b/frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_ai_message_bloc.dart @@ -1,42 +1,131 @@ -import 'package:appflowy_backend/protobuf/flowy-document/protobuf.dart'; -import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'; +import 'dart:async'; + +import 'package:appflowy/plugins/ai_chat/application/chat_bloc.dart'; +import 'package:appflowy_backend/dispatch/dispatch.dart'; +import 'package:appflowy_backend/log.dart'; +import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart'; +import 'package:fixnum/fixnum.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_chat_types/flutter_chat_types.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'chat_ai_message_bloc.freezed.dart'; class ChatAIMessageBloc extends Bloc { ChatAIMessageBloc({ - required Message message, + dynamic message, + required this.chatId, + required this.questionId, }) : super(ChatAIMessageState.initial(message)) { + if (state.stream != null) { + _subscription = state.stream!.listen((text) { + if (isClosed) { + return; + } + + if (text.startsWith("data:")) { + add(ChatAIMessageEvent.newText(text.substring(5))); + } else if (text.startsWith("error:")) { + add(ChatAIMessageEvent.receiveError(text.substring(5))); + } + }); + + if (state.stream!.error != null) { + Future.delayed(const Duration(milliseconds: 300), () { + if (!isClosed) { + add(ChatAIMessageEvent.receiveError(state.stream!.error!)); + } + }); + } + } + on( (event, emit) async { await event.when( initial: () async {}, - update: (userProfile, deviceId, states) {}, + newText: (newText) { + emit(state.copyWith(text: state.text + newText, error: null)); + }, + receiveError: (error) { + emit(state.copyWith(error: error)); + }, + retry: () { + if (questionId is! Int64) { + Log.error("Question id is not Int64: $questionId"); + return; + } + emit( + state.copyWith( + retryState: const LoadingState.loading(), + error: null, + ), + ); + + final payload = ChatMessageIdPB( + chatId: chatId, + messageId: questionId, + ); + ChatEventGetAnswerForQuestion(payload).send().then((result) { + if (!isClosed) { + result.fold( + (answer) { + add(ChatAIMessageEvent.retryResult(answer.content)); + }, + (err) { + Log.error("Failed to get answer: $err"); + add(ChatAIMessageEvent.receiveError(err.toString())); + }, + ); + } + }); + }, + retryResult: (String text) { + emit( + state.copyWith( + text: text, + error: null, + retryState: const LoadingState.finish(), + ), + ); + }, ); }, ); } + + @override + Future close() { + _subscription?.cancel(); + return super.close(); + } + + StreamSubscription? _subscription; + final String chatId; + final Int64? questionId; } @freezed class ChatAIMessageEvent with _$ChatAIMessageEvent { const factory ChatAIMessageEvent.initial() = Initial; - const factory ChatAIMessageEvent.update( - UserProfilePB userProfile, - String deviceId, - DocumentAwarenessStatesPB states, - ) = Update; + const factory ChatAIMessageEvent.newText(String text) = _NewText; + const factory ChatAIMessageEvent.receiveError(String error) = _ReceiveError; + const factory ChatAIMessageEvent.retry() = _Retry; + const factory ChatAIMessageEvent.retryResult(String text) = _RetryResult; } @freezed class ChatAIMessageState with _$ChatAIMessageState { const factory ChatAIMessageState({ - required Message message, + AnswerStream? stream, + String? error, + required String text, + required LoadingState retryState, }) = _ChatAIMessageState; - factory ChatAIMessageState.initial(Message message) => - ChatAIMessageState(message: message); + factory ChatAIMessageState.initial(dynamic text) { + return ChatAIMessageState( + text: text is String ? text : "", + stream: text is AnswerStream ? text : null, + retryState: const LoadingState.finish(), + ); + } } diff --git a/frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_bloc.dart b/frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_bloc.dart index 17eaad8c92..6adc99ad87 100644 --- a/frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_bloc.dart +++ b/frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_bloc.dart @@ -1,6 +1,12 @@ +import 'dart:async'; +import 'dart:collection'; +import 'dart:ffi'; +import 'dart:isolate'; + import 'package:appflowy_backend/dispatch/dispatch.dart'; import 'package:appflowy_backend/log.dart'; import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart'; +import 'package:appflowy_backend/protobuf/flowy-error/code.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart'; @@ -11,10 +17,8 @@ import 'package:flutter_chat_types/flutter_chat_types.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:nanoid/nanoid.dart'; import 'chat_message_listener.dart'; - part 'chat_bloc.freezed.dart'; -const canRetryKey = "canRetry"; const sendMessageErrorKey = "sendMessageError"; class ChatBloc extends Bloc { @@ -26,78 +30,31 @@ class ChatBloc extends Bloc { super( ChatState.initial(view, userProfile), ) { + _startListening(); _dispatch(); - - listener.start( - chatMessageCallback: _handleChatMessage, - lastUserSentMessageCallback: (message) { - if (!isClosed) { - add(ChatEvent.didSentUserMessage(message)); - } - }, - chatErrorMessageCallback: (err) { - if (!isClosed) { - Log.error("chat error: ${err.errorMessage}"); - final metadata = OnetimeShotType.serverStreamError.toMap(); - if (state.lastSentMessage != null) { - metadata[canRetryKey] = "true"; - } - final error = CustomMessage( - metadata: metadata, - author: const User(id: "system"), - id: 'system', - ); - add(ChatEvent.streaming([error])); - add(const ChatEvent.didFinishStreaming()); - } - }, - latestMessageCallback: (list) { - if (!isClosed) { - final messages = list.messages.map(_createChatMessage).toList(); - add(ChatEvent.didLoadLatestMessages(messages)); - } - }, - prevMessageCallback: (list) { - if (!isClosed) { - final messages = list.messages.map(_createChatMessage).toList(); - add(ChatEvent.didLoadPreviousMessages(messages, list.hasMore)); - } - }, - finishAnswerQuestionCallback: () { - if (!isClosed) { - add(const ChatEvent.didFinishStreaming()); - if (state.lastSentMessage != null) { - final payload = ChatMessageIdPB( - chatId: chatId, - messageId: state.lastSentMessage!.messageId, - ); - // When user message was sent to the server, we start gettting related question - ChatEventGetRelatedQuestion(payload).send().then((result) { - if (!isClosed) { - result.fold( - (list) { - add( - ChatEvent.didReceiveRelatedQuestion(list.items), - ); - }, - (err) { - Log.error("Failed to get related question: $err"); - }, - ); - } - }); - } - } - }, - ); } final ChatMessageListener listener; final String chatId; + /// The last streaming message id + String lastStreamMessageId = ''; + + /// Using a temporary map to associate the real message ID with the last streaming message ID. + /// + /// When a message is streaming, it does not have a real message ID. To maintain the relationship + /// between the real message ID and the last streaming message ID, we use this map to store the associations. + /// + /// This map will be updated when receiving a message from the server and its author type + /// is 3 (AI response). + final HashMap temporaryMessageIDMap = HashMap(); + @override - Future close() { - listener.stop(); + Future close() async { + if (state.answerStream != null) { + await state.answerStream?.dispose(); + } + await listener.stop(); return super.close(); } @@ -114,8 +71,9 @@ class ChatBloc extends Bloc { }, startLoadingPrevMessage: () async { Int64? beforeMessageId; - if (state.messages.isNotEmpty) { - beforeMessageId = Int64.parseInt(state.messages.last.id); + final oldestMessage = _getOlderstMessage(); + if (oldestMessage != null) { + beforeMessageId = Int64.parseInt(oldestMessage.id); } _loadPrevMessage(beforeMessageId); emit( @@ -126,8 +84,13 @@ class ChatBloc extends Bloc { }, didLoadPreviousMessages: (List messages, bool hasMore) { Log.debug("did load previous messages: ${messages.length}"); - final uniqueMessages = {...state.messages, ...messages}.toList() + final onetimeMessages = _getOnetimeMessages(); + final allMessages = _perminentMessages(); + final uniqueMessages = {...allMessages, ...messages}.toList() ..sort((a, b) => b.id.compareTo(a.id)); + + uniqueMessages.insertAll(0, onetimeMessages); + emit( state.copyWith( messages: uniqueMessages, @@ -137,8 +100,12 @@ class ChatBloc extends Bloc { ); }, didLoadLatestMessages: (List messages) { - final uniqueMessages = {...state.messages, ...messages}.toList() + final onetimeMessages = _getOnetimeMessages(); + final allMessages = _perminentMessages(); + final uniqueMessages = {...allMessages, ...messages}.toList() ..sort((a, b) => b.id.compareTo(a.id)); + uniqueMessages.insertAll(0, onetimeMessages); + emit( state.copyWith( messages: uniqueMessages, @@ -146,55 +113,43 @@ class ChatBloc extends Bloc { ), ); }, - streaming: (List messages) { + streaming: (Message message) { final allMessages = _perminentMessages(); - allMessages.insertAll(0, messages); - emit(state.copyWith(messages: allMessages)); - }, - didFinishStreaming: () { + allMessages.insert(0, message); emit( state.copyWith( - answerQuestionStatus: const LoadingState.finish(), + messages: allMessages, + streamingStatus: const LoadingState.loading(), ), ); }, - sendMessage: (String message) async { - await _handleSentMessage(message, emit); - - // Create a loading indicator - final loadingMessage = - _loadingMessage(state.userProfile.id.toString()); - final allMessages = List.from(state.messages) - ..insert(0, loadingMessage); - + didFinishStreaming: () { + emit( + state.copyWith(streamingStatus: const LoadingState.finish()), + ); + }, + receveMessage: (Message message) { + final allMessages = _perminentMessages(); + // remove message with the same id + allMessages.removeWhere((element) => element.id == message.id); + allMessages.insert(0, message); + emit( + state.copyWith( + messages: allMessages, + ), + ); + }, + sendMessage: (String message) { + _startStreamingMessage(message, emit); + final allMessages = _perminentMessages(); emit( state.copyWith( lastSentMessage: null, messages: allMessages, - answerQuestionStatus: const LoadingState.loading(), relatedQuestions: [], ), ); }, - retryGenerate: () { - if (state.lastSentMessage == null) { - return; - } - final payload = ChatMessageIdPB( - chatId: chatId, - messageId: state.lastSentMessage!.messageId, - ); - ChatEventGetAnswerForQuestion(payload).send().then((result) { - if (!isClosed) { - result.fold( - (answer) => _handleChatMessage(answer), - (err) { - Log.error("Failed to get answer: $err"); - }, - ); - } - }); - }, didReceiveRelatedQuestion: (List questions) { final allMessages = _perminentMessages(); final message = CustomMessage( @@ -224,11 +179,104 @@ class ChatBloc extends Bloc { ), ); }, + didUpdateAnswerStream: (AnswerStream stream) { + emit(state.copyWith(answerStream: stream)); + }, + stopStream: () async { + if (state.answerStream == null) { + return; + } + + final payload = StopStreamPB(chatId: chatId); + await ChatEventStopStream(payload).send(); + final allMessages = _perminentMessages(); + if (state.streamingStatus != const LoadingState.finish()) { + // If the streaming is not started, remove the message from the list + if (!state.answerStream!.hasStarted) { + allMessages.removeWhere( + (element) => element.id == lastStreamMessageId, + ); + lastStreamMessageId = ""; + } + + // when stop stream, we will set the answer stream to null. Which means the streaming + // is finished or canceled. + emit( + state.copyWith( + messages: allMessages, + answerStream: null, + streamingStatus: const LoadingState.finish(), + ), + ); + } + }, ); }, ); } + void _startListening() { + listener.start( + chatMessageCallback: (pb) { + if (!isClosed) { + // 3 mean message response from AI + if (pb.authorType == 3 && lastStreamMessageId.isNotEmpty) { + temporaryMessageIDMap[pb.messageId.toString()] = + lastStreamMessageId; + lastStreamMessageId = ""; + } + + final message = _createTextMessage(pb); + add(ChatEvent.receveMessage(message)); + } + }, + chatErrorMessageCallback: (err) { + if (!isClosed) { + Log.error("chat error: ${err.errorMessage}"); + add(const ChatEvent.didFinishStreaming()); + } + }, + latestMessageCallback: (list) { + if (!isClosed) { + final messages = list.messages.map(_createTextMessage).toList(); + add(ChatEvent.didLoadLatestMessages(messages)); + } + }, + prevMessageCallback: (list) { + if (!isClosed) { + final messages = list.messages.map(_createTextMessage).toList(); + add(ChatEvent.didLoadPreviousMessages(messages, list.hasMore)); + } + }, + finishStreamingCallback: () { + if (!isClosed) { + add(const ChatEvent.didFinishStreaming()); + // The answer strema will bet set to null after the streaming is finished or canceled. + // so if the answer stream is null, we will not get related question. + if (state.lastSentMessage != null && state.answerStream != null) { + final payload = ChatMessageIdPB( + chatId: chatId, + messageId: state.lastSentMessage!.messageId, + ); + // When user message was sent to the server, we start gettting related question + ChatEventGetRelatedQuestion(payload).send().then((result) { + if (!isClosed) { + result.fold( + (list) { + add(ChatEvent.didReceiveRelatedQuestion(list.items)); + }, + (err) { + Log.error("Failed to get related question: $err"); + }, + ); + } + }); + } + } + }, + ); + } + // Returns the list of messages that are not include one-time messages. List _perminentMessages() { final allMessages = state.messages.where((element) { @@ -238,6 +286,22 @@ class ChatBloc extends Bloc { return allMessages; } + List _getOnetimeMessages() { + final messages = state.messages.where((element) { + return (element.metadata?.containsKey(onetimeShotType) == true); + }).toList(); + + return messages; + } + + Message? _getOlderstMessage() { + // get the last message that is not a one-time message + final message = state.messages.lastWhereOrNull((element) { + return !(element.metadata?.containsKey(onetimeShotType) == true); + }); + return message; + } + void _loadPrevMessage(Int64? beforeMessageId) { final payload = LoadPrevChatMessagePB( chatId: state.view.id, @@ -247,68 +311,91 @@ class ChatBloc extends Bloc { ChatEventLoadPrevMessage(payload).send(); } - Future _handleSentMessage( + Future _startStreamingMessage( String message, Emitter emit, ) async { - final payload = SendChatPayloadPB( + if (state.answerStream != null) { + await state.answerStream?.dispose(); + } + + final answerStream = AnswerStream(); + add(ChatEvent.didUpdateAnswerStream(answerStream)); + + final payload = StreamChatPayloadPB( chatId: state.view.id, message: message, messageType: ChatMessageTypePB.User, + textStreamPort: Int64(answerStream.nativePort), ); - final result = await ChatEventSendMessage(payload).send(); + + // Stream message to the server + final result = await ChatEventStreamMessage(payload).send(); result.fold( - (_) {}, + (ChatMessagePB question) { + if (!isClosed) { + add(ChatEvent.didSentUserMessage(question)); + + final questionMessageId = question.messageId; + final message = _createTextMessage(question); + add(ChatEvent.receveMessage(message)); + + final streamAnswer = + _createStreamMessage(answerStream, questionMessageId); + add(ChatEvent.streaming(streamAnswer)); + } + }, (err) { if (!isClosed) { Log.error("Failed to send message: ${err.msg}"); final metadata = OnetimeShotType.invalidSendMesssage.toMap(); - metadata[sendMessageErrorKey] = err.msg; + if (err.code != ErrorCode.Internal) { + metadata[sendMessageErrorKey] = err.msg; + } + final error = CustomMessage( metadata: metadata, author: const User(id: "system"), id: 'system', ); - add(ChatEvent.streaming([error])); + add(ChatEvent.receveMessage(error)); } }, ); } - void _handleChatMessage(ChatMessagePB pb) { - if (!isClosed) { - final message = _createChatMessage(pb); - final messages = pb.hasFollowing - ? [_loadingMessage(0.toString()), message] - : [message]; - add(ChatEvent.streaming(messages)); - } - } + Message _createStreamMessage(AnswerStream stream, Int64 questionMessageId) { + final streamMessageId = nanoid(); + lastStreamMessageId = streamMessageId; - Message _loadingMessage(String id) { - return CustomMessage( - author: User(id: id), - metadata: OnetimeShotType.loading.toMap(), - // fake id - id: nanoid(), + return TextMessage( + author: User(id: nanoid()), + metadata: { + "$AnswerStream": stream, + "question": questionMessageId, + "chatId": chatId, + }, + id: streamMessageId, + text: '', ); } - Message _createChatMessage(ChatMessagePB message) { - final messageId = message.messageId.toString(); + Message _createTextMessage(ChatMessagePB message) { + String messageId = message.messageId.toString(); + + /// If the message id is in the temporary map, we will use the previous fake message id + if (temporaryMessageIDMap.containsKey(messageId)) { + messageId = temporaryMessageIDMap[messageId]!; + } + return TextMessage( author: User(id: message.authorId), id: messageId, text: message.content, createdAt: message.createdAt.toInt(), - repliedMessage: _getReplyMessage(state.messages, messageId), ); } - - Message? _getReplyMessage(List messages, String messageId) { - return messages.firstWhereOrNull((element) => element?.id == messageId); - } } @freezed @@ -322,15 +409,20 @@ class ChatEvent with _$ChatEvent { ) = _DidLoadPreviousMessages; const factory ChatEvent.didLoadLatestMessages(List messages) = _DidLoadMessages; - const factory ChatEvent.streaming(List messages) = _DidStreamMessage; + const factory ChatEvent.streaming(Message message) = _StreamingMessage; + const factory ChatEvent.receveMessage(Message message) = _ReceiveMessage; + const factory ChatEvent.didFinishStreaming() = _FinishStreamingMessage; const factory ChatEvent.didReceiveRelatedQuestion( List questions, ) = _DidReceiveRelatedQueston; const factory ChatEvent.clearReleatedQuestion() = _ClearRelatedQuestion; - const factory ChatEvent.retryGenerate() = _RetryGenerate; const factory ChatEvent.didSentUserMessage(ChatMessagePB message) = _DidSendUserMessage; + const factory ChatEvent.didUpdateAnswerStream( + AnswerStream stream, + ) = _DidUpdateAnswerStream; + const factory ChatEvent.stopStream() = _StopStream; } @freezed @@ -347,13 +439,14 @@ class ChatState with _$ChatState { required LoadingState loadingPreviousStatus, // When sending a user message, the status will be set as loading. // After the message is sent, the status will be set as finished. - required LoadingState answerQuestionStatus, + required LoadingState streamingStatus, // Indicate whether there are more previous messages to load. required bool hasMorePrevMessage, // The related questions that are received after the user message is sent. required List relatedQuestions, // The last user message that is sent to the server. ChatMessagePB? lastSentMessage, + AnswerStream? answerStream, }) = _ChatState; factory ChatState.initial(ViewPB view, UserProfilePB userProfile) => @@ -363,7 +456,7 @@ class ChatState with _$ChatState { userProfile: userProfile, initialLoadingStatus: const LoadingState.finish(), loadingPreviousStatus: const LoadingState.finish(), - answerQuestionStatus: const LoadingState.finish(), + streamingStatus: const LoadingState.finish(), hasMorePrevMessage: true, relatedQuestions: [], ); @@ -377,10 +470,8 @@ class LoadingState with _$LoadingState { enum OnetimeShotType { unknown, - loading, - serverStreamError, relatedQuestion, - invalidSendMesssage + invalidSendMesssage, } const onetimeShotType = "OnetimeShotType"; @@ -388,10 +479,6 @@ const onetimeShotType = "OnetimeShotType"; extension OnetimeMessageTypeExtension on OnetimeShotType { static OnetimeShotType fromString(String value) { switch (value) { - case 'OnetimeShotType.loading': - return OnetimeShotType.loading; - case 'OnetimeShotType.serverStreamError': - return OnetimeShotType.serverStreamError; case 'OnetimeShotType.relatedQuestion': return OnetimeShotType.relatedQuestion; case 'OnetimeShotType.invalidSendMesssage': @@ -402,7 +489,7 @@ extension OnetimeMessageTypeExtension on OnetimeShotType { } } - Map toMap() { + Map toMap() { return { onetimeShotType: toString(), }; @@ -421,3 +508,43 @@ OnetimeShotType? onetimeMessageTypeFromMeta(Map? metadata) { } return null; } + +typedef AnswerStreamElement = String; + +class AnswerStream { + AnswerStream() { + _port.handler = _controller.add; + _subscription = _controller.stream.listen( + (event) { + if (event.startsWith("data:")) { + _hasStarted = true; + } else if (event.startsWith("error:")) { + _error = event.substring(5); + } + }, + ); + } + + final RawReceivePort _port = RawReceivePort(); + final StreamController _controller = + StreamController.broadcast(); + late StreamSubscription _subscription; + bool _hasStarted = false; + String? _error; + + int get nativePort => _port.sendPort.nativePort; + bool get hasStarted => _hasStarted; + String? get error => _error; + + Future dispose() async { + await _controller.close(); + await _subscription.cancel(); + _port.close(); + } + + StreamSubscription listen( + void Function(AnswerStreamElement event)? onData, + ) { + return _controller.stream.listen(onData); + } +} diff --git a/frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_message_listener.dart b/frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_message_listener.dart index 3b40c18d36..a26acd916f 100644 --- a/frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_message_listener.dart +++ b/frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_message_listener.dart @@ -28,26 +28,23 @@ class ChatMessageListener { ChatNotificationParser? _parser; ChatMessageCallback? chatMessageCallback; - ChatMessageCallback? lastUserSentMessageCallback; ChatErrorMessageCallback? chatErrorMessageCallback; LatestMessageCallback? latestMessageCallback; PrevMessageCallback? prevMessageCallback; - void Function()? finishAnswerQuestionCallback; + void Function()? finishStreamingCallback; void start({ ChatMessageCallback? chatMessageCallback, ChatErrorMessageCallback? chatErrorMessageCallback, LatestMessageCallback? latestMessageCallback, PrevMessageCallback? prevMessageCallback, - ChatMessageCallback? lastUserSentMessageCallback, - void Function()? finishAnswerQuestionCallback, + void Function()? finishStreamingCallback, }) { this.chatMessageCallback = chatMessageCallback; this.chatErrorMessageCallback = chatErrorMessageCallback; this.latestMessageCallback = latestMessageCallback; this.prevMessageCallback = prevMessageCallback; - this.lastUserSentMessageCallback = lastUserSentMessageCallback; - this.finishAnswerQuestionCallback = finishAnswerQuestionCallback; + this.finishStreamingCallback = finishStreamingCallback; } void _callback( @@ -59,9 +56,6 @@ class ChatMessageListener { case ChatNotification.DidReceiveChatMessage: chatMessageCallback?.call(ChatMessagePB.fromBuffer(r)); break; - case ChatNotification.LastUserSentMessage: - lastUserSentMessageCallback?.call(ChatMessagePB.fromBuffer(r)); - break; case ChatNotification.StreamChatMessageError: chatErrorMessageCallback?.call(ChatMessageErrorPB.fromBuffer(r)); break; @@ -71,8 +65,8 @@ class ChatMessageListener { case ChatNotification.DidLoadPrevChatMessage: prevMessageCallback?.call(ChatMessageListPB.fromBuffer(r)); break; - case ChatNotification.FinishAnswerQuestion: - finishAnswerQuestionCallback?.call(); + case ChatNotification.FinishStreaming: + finishStreamingCallback?.call(); break; default: break; diff --git a/frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_related_question_bloc.dart b/frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_related_question_bloc.dart deleted file mode 100644 index d6db6afc37..0000000000 --- a/frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_related_question_bloc.dart +++ /dev/null @@ -1,103 +0,0 @@ -import 'package:appflowy/plugins/ai_chat/application/chat_message_listener.dart'; -import 'package:appflowy_backend/dispatch/dispatch.dart'; -import 'package:appflowy_backend/log.dart'; -import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'chat_related_question_bloc.freezed.dart'; - -class ChatRelatedMessageBloc - extends Bloc { - ChatRelatedMessageBloc({ - required String chatId, - }) : listener = ChatMessageListener(chatId: chatId), - super(ChatRelatedMessageState.initial()) { - on( - (event, emit) async { - await event.when( - initial: () async { - listener.start( - lastUserSentMessageCallback: (message) { - if (!isClosed) { - add(ChatRelatedMessageEvent.updateLastSentMessage(message)); - } - }, - ); - }, - didReceiveRelatedQuestion: (List questions) { - Log.debug("Related questions: $questions"); - emit( - state.copyWith( - relatedQuestions: questions, - ), - ); - }, - updateLastSentMessage: (ChatMessagePB message) { - final payload = - ChatMessageIdPB(chatId: chatId, messageId: message.messageId); - ChatEventGetRelatedQuestion(payload).send().then((result) { - if (!isClosed) { - result.fold( - (list) { - add( - ChatRelatedMessageEvent.didReceiveRelatedQuestion( - list.items, - ), - ); - }, - (err) { - Log.error("Failed to get related question: $err"); - }, - ); - } - }); - - emit( - state.copyWith( - lastSentMessage: message, - relatedQuestions: [], - ), - ); - }, - clear: () { - emit( - state.copyWith( - relatedQuestions: [], - ), - ); - }, - ); - }, - ); - } - - final ChatMessageListener listener; - @override - Future close() { - listener.stop(); - return super.close(); - } -} - -@freezed -class ChatRelatedMessageEvent with _$ChatRelatedMessageEvent { - const factory ChatRelatedMessageEvent.initial() = Initial; - const factory ChatRelatedMessageEvent.updateLastSentMessage( - ChatMessagePB message, - ) = _LastSentMessage; - const factory ChatRelatedMessageEvent.didReceiveRelatedQuestion( - List questions, - ) = _RelatedQuestion; - const factory ChatRelatedMessageEvent.clear() = _Clear; -} - -@freezed -class ChatRelatedMessageState with _$ChatRelatedMessageState { - const factory ChatRelatedMessageState({ - ChatMessagePB? lastSentMessage, - @Default([]) List relatedQuestions, - }) = _ChatRelatedMessageState; - - factory ChatRelatedMessageState.initial() => const ChatRelatedMessageState(); -} diff --git a/frontend/appflowy_flutter/lib/plugins/ai_chat/chat_page.dart b/frontend/appflowy_flutter/lib/plugins/ai_chat/chat_page.dart index 3e6142c3ec..1a7393a0a9 100644 --- a/frontend/appflowy_flutter/lib/plugins/ai_chat/chat_page.dart +++ b/frontend/appflowy_flutter/lib/plugins/ai_chat/chat_page.dart @@ -1,9 +1,8 @@ import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/plugins/ai_chat/application/chat_bloc.dart'; -import 'package:appflowy/plugins/ai_chat/presentation/chat_ai_message.dart'; -import 'package:appflowy/plugins/ai_chat/presentation/chat_streaming_error_message.dart'; +import 'package:appflowy/plugins/ai_chat/presentation/ai_message_bubble.dart'; import 'package:appflowy/plugins/ai_chat/presentation/chat_related_question.dart'; -import 'package:appflowy/plugins/ai_chat/presentation/chat_user_message.dart'; +import 'package:appflowy/plugins/ai_chat/presentation/user_message_bubble.dart'; import 'package:appflowy/workspace/presentation/home/toast.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'; @@ -19,11 +18,12 @@ import 'package:flutter_chat_ui/flutter_chat_ui.dart' show Chat; import 'package:flutter_chat_types/flutter_chat_types.dart' as types; import 'presentation/chat_input.dart'; -import 'presentation/chat_loading.dart'; import 'presentation/chat_popmenu.dart'; import 'presentation/chat_theme.dart'; import 'presentation/chat_user_invalid_message.dart'; import 'presentation/chat_welcome_page.dart'; +import 'presentation/message/ai_text_message.dart'; +import 'presentation/message/user_text_message.dart'; class AIChatUILayout { static EdgeInsets get chatPadding => @@ -108,7 +108,6 @@ class _AIChatPageState extends State { customBottomWidget: buildChatInput(blocContext), user: _user, theme: buildTheme(context), - customMessageBuilder: _customMessageBuilder, onEndReached: () async { if (state.hasMorePrevMessage && state.loadingPreviousStatus != @@ -138,6 +137,13 @@ class _AIChatPageState extends State { }, ), messageWidthRatio: AIChatUILayout.messageWidthRatio, + textMessageBuilder: ( + textMessage, { + required messageWidth, + required showName, + }) { + return _buildAITextMessage(blocContext, textMessage); + }, bubbleBuilder: ( child, { required message, @@ -149,46 +155,7 @@ class _AIChatPageState extends State { child: child, ); } else { - final messageType = onetimeMessageTypeFromMeta( - message.metadata, - ); - if (messageType == OnetimeShotType.serverStreamError) { - return ChatStreamingError( - message: message, - onRetryPressed: () { - blocContext - .read() - .add(const ChatEvent.retryGenerate()); - }, - ); - } - - if (messageType == OnetimeShotType.invalidSendMesssage) { - return ChatInvalidUserMessage( - message: message, - ); - } - - if (messageType == OnetimeShotType.relatedQuestion) { - return RelatedQuestionList( - onQuestionSelected: (question) { - blocContext - .read() - .add(ChatEvent.sendMessage(question)); - blocContext - .read() - .add(const ChatEvent.clearReleatedQuestion()); - }, - chatId: widget.view.id, - relatedQuestions: state.relatedQuestions, - ); - } - - return ChatAIMessageBubble( - message: message, - customMessageType: messageType, - child: child, - ); + return _buildAIBubble(message, blocContext, state, child); } }, ); @@ -199,10 +166,67 @@ class _AIChatPageState extends State { ); } + Widget _buildAITextMessage(BuildContext context, TextMessage message) { + final isAuthor = message.author.id == _user.id; + if (isAuthor) { + return ChatTextMessageWidget( + user: message.author, + messageUserId: message.id, + text: message.text, + ); + } else { + final stream = message.metadata?["$AnswerStream"]; + final questionId = message.metadata?["question"]; + return ChatAITextMessageWidget( + user: message.author, + messageUserId: message.id, + text: stream is AnswerStream ? stream : message.text, + key: ValueKey(message.id), + questionId: questionId, + chatId: widget.view.id, + ); + } + } + + Widget _buildAIBubble( + Message message, + BuildContext blocContext, + ChatState state, + Widget child, + ) { + final messageType = onetimeMessageTypeFromMeta( + message.metadata, + ); + + if (messageType == OnetimeShotType.invalidSendMesssage) { + return ChatInvalidUserMessage( + message: message, + ); + } + + if (messageType == OnetimeShotType.relatedQuestion) { + return RelatedQuestionList( + onQuestionSelected: (question) { + blocContext.read().add(ChatEvent.sendMessage(question)); + blocContext + .read() + .add(const ChatEvent.clearReleatedQuestion()); + }, + chatId: widget.view.id, + relatedQuestions: state.relatedQuestions, + ); + } + + return ChatAIMessageBubble( + message: message, + customMessageType: messageType, + child: child, + ); + } + Widget buildBubble(Message message, Widget child) { final isAuthor = message.author.id == _user.id; const borderRadius = BorderRadius.all(Radius.circular(6)); - final childWithPadding = isAuthor ? Padding( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), @@ -261,33 +285,25 @@ class _AIChatPageState extends State { } } - Widget _customMessageBuilder( - types.CustomMessage message, { - required int messageWidth, - }) { - // iteration custom message type - final messageType = onetimeMessageTypeFromMeta(message.metadata); - if (messageType == null) { - return const SizedBox.shrink(); - } - - switch (messageType) { - case OnetimeShotType.loading: - return const ChatAILoading(); - default: - return const SizedBox.shrink(); - } - } - Widget buildChatInput(BuildContext context) { return ClipRect( child: Padding( padding: AIChatUILayout.safeAreaInsets(context), child: Column( children: [ - ChatInput( - chatId: widget.view.id, - onSendPressed: (message) => onSendPressed(context, message.text), + BlocSelector( + selector: (state) => state.streamingStatus, + builder: (context, state) { + return ChatInput( + chatId: widget.view.id, + onSendPressed: (message) => + onSendPressed(context, message.text), + isStreaming: state != const LoadingState.finish(), + onStopStreaming: () { + context.read().add(const ChatEvent.stopStream()); + }, + ); + }, ), const VSpace(6), Opacity( diff --git a/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_ai_message.dart b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/ai_message_bubble.dart similarity index 83% rename from frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_ai_message.dart rename to frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/ai_message_bubble.dart index 7a19360490..8246378bda 100644 --- a/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_ai_message.dart +++ b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/ai_message_bubble.dart @@ -1,6 +1,5 @@ import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; -import 'package:appflowy/plugins/ai_chat/application/chat_ai_message_bloc.dart'; import 'package:appflowy/plugins/ai_chat/application/chat_bloc.dart'; import 'package:appflowy/plugins/ai_chat/presentation/chat_avatar.dart'; import 'package:appflowy/plugins/ai_chat/presentation/chat_input.dart'; @@ -13,7 +12,6 @@ import 'package:flowy_infra_ui/style_widget/icon_button.dart'; import 'package:flowy_infra_ui/widget/flowy_tooltip.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_chat_types/flutter_chat_types.dart'; import 'package:styled_widget/styled_widget.dart'; @@ -35,30 +33,22 @@ class ChatAIMessageBubble extends StatelessWidget { Widget build(BuildContext context) { const padding = EdgeInsets.symmetric(horizontal: _leftPadding); final childWithPadding = Padding(padding: padding, child: child); + final widget = isMobile + ? _wrapPopMenu(childWithPadding) + : _wrapHover(childWithPadding); - return BlocProvider( - create: (context) => ChatAIMessageBloc(message: message), - child: BlocBuilder( - builder: (context, state) { - final widget = isMobile - ? _wrapPopMenu(childWithPadding) - : _wrapHover(childWithPadding); - - return Row( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const ChatBorderedCircleAvatar( - child: FlowySvg( - FlowySvgs.flowy_ai_chat_logo_s, - size: Size.square(24), - ), - ), - Expanded(child: widget), - ], - ); - }, - ), + return Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const ChatBorderedCircleAvatar( + child: FlowySvg( + FlowySvgs.flowy_ai_chat_logo_s, + size: Size.square(24), + ), + ), + Expanded(child: widget), + ], ); } @@ -118,7 +108,7 @@ class _ChatAIMessageHoverState extends State { borderRadius: Corners.s6Border, ), child: Padding( - padding: const EdgeInsets.only(bottom: 40), + padding: const EdgeInsets.only(bottom: 30), child: widget.child, ), ), diff --git a/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_input.dart b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_input.dart index b33c59d640..93bf80b4a5 100644 --- a/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_input.dart +++ b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_input.dart @@ -18,13 +18,17 @@ class ChatInput extends StatefulWidget { required this.onSendPressed, required this.chatId, this.options = const InputOptions(), + required this.isStreaming, + required this.onStopStreaming, }); final bool? isAttachmentUploading; final VoidCallback? onAttachmentPressed; final void Function(types.PartialText) onSendPressed; + final void Function() onStopStreaming; final InputOptions options; final String chatId; + final bool isStreaming; @override State createState() => _ChatInputState(); @@ -68,26 +72,23 @@ class _ChatInputState extends State { void _handleSendButtonVisibilityModeChange() { _textController.removeListener(_handleTextControllerChange); - if (widget.options.sendButtonVisibilityMode == - SendButtonVisibilityMode.hidden) { - _sendButtonVisible = false; - } else if (widget.options.sendButtonVisibilityMode == - SendButtonVisibilityMode.editing) { - _sendButtonVisible = _textController.text.trim() != ''; - _textController.addListener(_handleTextControllerChange); - } else { - _sendButtonVisible = true; - } + _sendButtonVisible = + _textController.text.trim() != '' || widget.isStreaming; + _textController.addListener(_handleTextControllerChange); } void _handleSendPressed() { - final trimmedText = _textController.text.trim(); - if (trimmedText != '') { - final partialText = types.PartialText(text: trimmedText); - widget.onSendPressed(partialText); + if (widget.isStreaming) { + widget.onStopStreaming(); + } else { + final trimmedText = _textController.text.trim(); + if (trimmedText != '') { + final partialText = types.PartialText(text: trimmedText); + widget.onSendPressed(partialText); - if (widget.options.inputClearMode == InputClearMode.always) { - _textController.clear(); + if (widget.options.inputClearMode == InputClearMode.always) { + _textController.clear(); + } } } } @@ -138,6 +139,7 @@ class _ChatInputState extends State { padding: textPadding, child: TextField( controller: _textController, + readOnly: widget.isStreaming, focusNode: _inputFocusNode, decoration: InputDecoration( border: InputBorder.none, @@ -153,7 +155,6 @@ class _ChatInputState extends State { autocorrect: widget.options.autocorrect, autofocus: widget.options.autofocus, enableSuggestions: widget.options.enableSuggestions, - spellCheckConfiguration: const SpellCheckConfiguration(), keyboardType: widget.options.keyboardType, textCapitalization: TextCapitalization.sentences, maxLines: 10, @@ -173,8 +174,14 @@ class _ChatInputState extends State { visible: _sendButtonVisible, child: Padding( padding: buttonPadding, - child: SendButton( - onPressed: _handleSendPressed, + child: AccessoryButton( + onSendPressed: () { + _handleSendPressed(); + }, + onStopStreaming: () { + widget.onStopStreaming(); + }, + isStreaming: widget.isStreaming, ), ), ), @@ -184,10 +191,7 @@ class _ChatInputState extends State { @override void didUpdateWidget(covariant ChatInput oldWidget) { super.didUpdateWidget(oldWidget); - if (widget.options.sendButtonVisibilityMode != - oldWidget.options.sendButtonVisibilityMode) { - _handleSendButtonVisibilityModeChange(); - } + _handleSendButtonVisibilityModeChange(); } @override @@ -211,7 +215,6 @@ class InputOptions { this.keyboardType = TextInputType.multiline, this.onTextChanged, this.onTextFieldTap, - this.sendButtonVisibilityMode = SendButtonVisibilityMode.editing, this.textEditingController, this.autocorrect = true, this.autofocus = false, @@ -231,11 +234,6 @@ class InputOptions { /// Will be called on [TextField] tap. final VoidCallback? onTextFieldTap; - /// Controls the visibility behavior of the [SendButton] based on the - /// [TextField] state inside the [ChatInput] widget. - /// Defaults to [SendButtonVisibilityMode.editing]. - final SendButtonVisibilityMode sendButtonVisibilityMode; - /// Custom [TextEditingController]. If not provided, defaults to the /// [InputTextFieldController], which extends [TextEditingController] and has /// additional fatures like markdown support. If you want to keep additional @@ -260,24 +258,46 @@ class InputOptions { final isMobile = defaultTargetPlatform == TargetPlatform.android || defaultTargetPlatform == TargetPlatform.iOS; -class SendButton extends StatelessWidget { - const SendButton({required this.onPressed, super.key}); +class AccessoryButton extends StatelessWidget { + const AccessoryButton({ + required this.onSendPressed, + required this.onStopStreaming, + required this.isStreaming, + super.key, + }); - final void Function() onPressed; + final void Function() onSendPressed; + final void Function() onStopStreaming; + final bool isStreaming; @override Widget build(BuildContext context) { - return FlowyIconButton( - width: 36, - fillColor: AFThemeExtension.of(context).lightGreyHover, - hoverColor: AFThemeExtension.of(context).lightGreyHover, - radius: BorderRadius.circular(18), - icon: FlowySvg( - FlowySvgs.send_s, - size: const Size.square(24), - color: Theme.of(context).colorScheme.primary, - ), - onPressed: onPressed, - ); + if (isStreaming) { + return FlowyIconButton( + width: 36, + icon: FlowySvg( + FlowySvgs.ai_stream_stop_s, + size: const Size.square(28), + color: Theme.of(context).colorScheme.primary, + ), + onPressed: onStopStreaming, + radius: BorderRadius.circular(18), + fillColor: AFThemeExtension.of(context).lightGreyHover, + hoverColor: AFThemeExtension.of(context).lightGreyHover, + ); + } else { + return FlowyIconButton( + width: 36, + fillColor: AFThemeExtension.of(context).lightGreyHover, + hoverColor: AFThemeExtension.of(context).lightGreyHover, + radius: BorderRadius.circular(18), + icon: FlowySvg( + FlowySvgs.send_s, + size: const Size.square(24), + color: Theme.of(context).colorScheme.primary, + ), + onPressed: onSendPressed, + ); + } } } diff --git a/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_loading.dart b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_loading.dart index 4b5c984382..9c4bd64cb6 100644 --- a/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_loading.dart +++ b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_loading.dart @@ -53,15 +53,15 @@ class ContentPlaceholder extends StatelessWidget { ), ], ), - Container( - width: 140, - height: 16.0, - margin: const EdgeInsets.only(bottom: 8.0), - decoration: BoxDecoration( - color: AFThemeExtension.of(context).lightGreyHover, - borderRadius: BorderRadius.circular(4.0), - ), - ), + // Container( + // width: 140, + // height: 16.0, + // margin: const EdgeInsets.only(bottom: 8.0), + // decoration: BoxDecoration( + // color: AFThemeExtension.of(context).lightGreyHover, + // borderRadius: BorderRadius.circular(4.0), + // ), + // ), ], ), ); diff --git a/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_related_question.dart b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_related_question.dart index 0cf2398f68..a37a0824ed 100644 --- a/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_related_question.dart +++ b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_related_question.dart @@ -1,47 +1,11 @@ import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; -import 'package:appflowy/plugins/ai_chat/application/chat_related_question_bloc.dart'; import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -class RelatedQuestionPage extends StatefulWidget { - const RelatedQuestionPage({ - required this.chatId, - required this.onQuestionSelected, - super.key, - }); - - final String chatId; - final Function(String) onQuestionSelected; - - @override - State createState() => _RelatedQuestionPageState(); -} - -class _RelatedQuestionPageState extends State { - @override - Widget build(BuildContext context) { - return BlocProvider( - create: (context) => ChatRelatedMessageBloc(chatId: widget.chatId) - ..add( - const ChatRelatedMessageEvent.initial(), - ), - child: BlocBuilder( - builder: (blocContext, state) { - return RelatedQuestionList( - chatId: widget.chatId, - onQuestionSelected: widget.onQuestionSelected, - relatedQuestions: state.relatedQuestions, - ); - }, - ), - ); - } -} class RelatedQuestionList extends StatelessWidget { const RelatedQuestionList({ diff --git a/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_stream_text_field.dart b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_stream_text_field.dart new file mode 100644 index 0000000000..7589a1b634 --- /dev/null +++ b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_stream_text_field.dart @@ -0,0 +1,10 @@ +import 'package:flutter/widgets.dart'; + +class StreamTextField extends StatelessWidget { + const StreamTextField({super.key}); + + @override + Widget build(BuildContext context) { + return const Placeholder(); + } +} diff --git a/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_streaming_error_message.dart b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_streaming_error_message.dart index c0552a7e8e..1f825d3355 100644 --- a/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_streaming_error_message.dart +++ b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_streaming_error_message.dart @@ -1,84 +1,83 @@ -import 'package:appflowy/generated/locale_keys.g.dart'; -import 'package:appflowy/plugins/ai_chat/application/chat_bloc.dart'; -import 'package:easy_localization/easy_localization.dart'; -import 'package:flowy_infra_ui/flowy_infra_ui.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_chat_types/flutter_chat_types.dart'; +// import 'package:appflowy/generated/locale_keys.g.dart'; +// import 'package:easy_localization/easy_localization.dart'; +// import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +// import 'package:flutter/material.dart'; +// import 'package:flutter_chat_types/flutter_chat_types.dart'; -class ChatStreamingError extends StatelessWidget { - const ChatStreamingError({ - required this.message, - required this.onRetryPressed, - super.key, - }); +// class ChatStreamingError extends StatelessWidget { +// const ChatStreamingError({ +// required this.message, +// required this.onRetryPressed, +// super.key, +// }); - final void Function() onRetryPressed; - final Message message; - @override - Widget build(BuildContext context) { - final canRetry = message.metadata?[canRetryKey] != null; +// final void Function() onRetryPressed; +// final Message message; +// @override +// Widget build(BuildContext context) { +// final canRetry = message.metadata?[canRetryKey] != null; - if (canRetry) { - return Column( - children: [ - const Divider(height: 4, thickness: 1), - const VSpace(16), - Center( - child: Column( - children: [ - _aiUnvaliable(), - const VSpace(10), - _retryButton(), - ], - ), - ), - ], - ); - } else { - return Center( - child: Column( - children: [ - const Divider(height: 20, thickness: 1), - Padding( - padding: const EdgeInsets.all(8.0), - child: FlowyText( - LocaleKeys.chat_serverUnavailable.tr(), - fontSize: 14, - ), - ), - ], - ), - ); - } - } +// if (canRetry) { +// return Column( +// children: [ +// const Divider(height: 4, thickness: 1), +// const VSpace(16), +// Center( +// child: Column( +// children: [ +// _aiUnvaliable(), +// const VSpace(10), +// _retryButton(), +// ], +// ), +// ), +// ], +// ); +// } else { +// return Center( +// child: Column( +// children: [ +// const Divider(height: 20, thickness: 1), +// Padding( +// padding: const EdgeInsets.all(8.0), +// child: FlowyText( +// LocaleKeys.chat_serverUnavailable.tr(), +// fontSize: 14, +// ), +// ), +// ], +// ), +// ); +// } +// } - FlowyButton _retryButton() { - return FlowyButton( - radius: BorderRadius.circular(20), - useIntrinsicWidth: true, - text: Padding( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - child: FlowyText( - LocaleKeys.chat_regenerateAnswer.tr(), - fontSize: 14, - ), - ), - onTap: onRetryPressed, - iconPadding: 0, - leftIcon: const Icon( - Icons.refresh, - size: 20, - ), - ); - } +// FlowyButton _retryButton() { +// return FlowyButton( +// radius: BorderRadius.circular(20), +// useIntrinsicWidth: true, +// text: Padding( +// padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), +// child: FlowyText( +// LocaleKeys.chat_regenerateAnswer.tr(), +// fontSize: 14, +// ), +// ), +// onTap: onRetryPressed, +// iconPadding: 0, +// leftIcon: const Icon( +// Icons.refresh, +// size: 20, +// ), +// ); +// } - Padding _aiUnvaliable() { - return Padding( - padding: const EdgeInsets.all(8.0), - child: FlowyText( - LocaleKeys.chat_aiServerUnavailable.tr(), - fontSize: 14, - ), - ); - } -} +// Padding _aiUnvaliable() { +// return Padding( +// padding: const EdgeInsets.all(8.0), +// child: FlowyText( +// LocaleKeys.chat_aiServerUnavailable.tr(), +// fontSize: 14, +// ), +// ); +// } +// } diff --git a/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_welcome_page.dart b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_welcome_page.dart index 1014b9ef5e..5aceca2025 100644 --- a/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_welcome_page.dart +++ b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_welcome_page.dart @@ -20,29 +20,33 @@ class ChatWelcomePage extends StatelessWidget { ]; @override Widget build(BuildContext context) { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const FlowySvg( - FlowySvgs.flowy_ai_chat_logo_s, - size: Size.square(44), - ), - const SizedBox(height: 40), - GridView.builder( - shrinkWrap: true, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: isMobile ? 2 : 4, - crossAxisSpacing: 6, - mainAxisSpacing: 6, - childAspectRatio: 16.0 / 9.0, + return AnimatedOpacity( + opacity: 1.0, + duration: const Duration(seconds: 3), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const FlowySvg( + FlowySvgs.flowy_ai_chat_logo_s, + size: Size.square(44), ), - itemCount: items.length, - itemBuilder: (context, index) => WelcomeQuestion( - question: items[index], - onSelected: onSelectedQuestion, + const SizedBox(height: 40), + GridView.builder( + shrinkWrap: true, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: isMobile ? 2 : 4, + crossAxisSpacing: 6, + mainAxisSpacing: 6, + childAspectRatio: 16.0 / 9.0, + ), + itemCount: items.length, + itemBuilder: (context, index) => WelcomeQuestion( + question: items[index], + onSelected: onSelectedQuestion, + ), ), - ), - ], + ], + ), ); } } diff --git a/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/message/ai_text_message.dart b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/message/ai_text_message.dart new file mode 100644 index 0000000000..d2fa1b155c --- /dev/null +++ b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/message/ai_text_message.dart @@ -0,0 +1,295 @@ +import 'package:appflowy/generated/locale_keys.g.dart'; +import 'package:appflowy/plugins/ai_chat/application/chat_ai_message_bloc.dart'; +import 'package:appflowy/plugins/ai_chat/application/chat_bloc.dart'; +import 'package:appflowy/plugins/ai_chat/presentation/chat_loading.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:fixnum/fixnum.dart'; +import 'package:flowy_infra/theme_extension.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_chat_types/flutter_chat_types.dart'; +import 'package:markdown_widget/markdown_widget.dart'; + +class ChatAITextMessageWidget extends StatelessWidget { + const ChatAITextMessageWidget({ + super.key, + required this.user, + required this.messageUserId, + required this.text, + required this.questionId, + required this.chatId, + }); + + final User user; + final String messageUserId; + final dynamic text; + final Int64? questionId; + final String chatId; + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => ChatAIMessageBloc( + message: text, + chatId: chatId, + questionId: questionId, + )..add(const ChatAIMessageEvent.initial()), + child: BlocBuilder( + builder: (context, state) { + if (state.error != null) { + return StreamingError( + onRetryPressed: () { + context.read().add( + const ChatAIMessageEvent.retry(), + ); + }, + ); + } + + if (state.retryState == const LoadingState.loading()) { + return const ChatAILoading(); + } + + if (state.text.isEmpty) { + return const ChatAILoading(); + } else { + return _textWidgetBuilder(user, context, state.text); + } + }, + ), + ); + } + + Widget _textWidgetBuilder( + User user, + BuildContext context, + String text, + ) { + return MarkdownWidget( + data: text, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + config: configFromContext(context), + ); + } + + MarkdownConfig configFromContext(BuildContext context) { + return MarkdownConfig( + configs: [ + HrConfig(color: AFThemeExtension.of(context).textColor), + ChatH1Config( + style: TextStyle( + color: AFThemeExtension.of(context).textColor, + fontSize: 24, + fontWeight: FontWeight.bold, + height: 1.5, + ), + dividerColor: AFThemeExtension.of(context).lightGreyHover, + ), + ChatH2Config( + style: TextStyle( + color: AFThemeExtension.of(context).textColor, + fontSize: 20, + fontWeight: FontWeight.bold, + height: 1.5, + ), + dividerColor: AFThemeExtension.of(context).lightGreyHover, + ), + ChatH3Config( + style: TextStyle( + color: AFThemeExtension.of(context).textColor, + fontSize: 18, + fontWeight: FontWeight.bold, + height: 1.5, + ), + dividerColor: AFThemeExtension.of(context).lightGreyHover, + ), + H4Config( + style: TextStyle( + color: AFThemeExtension.of(context).textColor, + fontSize: 16, + fontWeight: FontWeight.bold, + height: 1.5, + ), + ), + H5Config( + style: TextStyle( + color: AFThemeExtension.of(context).textColor, + fontSize: 14, + fontWeight: FontWeight.bold, + height: 1.5, + ), + ), + H6Config( + style: TextStyle( + color: AFThemeExtension.of(context).textColor, + fontSize: 12, + fontWeight: FontWeight.bold, + height: 1.5, + ), + ), + PreConfig( + padding: const EdgeInsets.all(14), + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surfaceContainerHighest, + borderRadius: const BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + PConfig( + textStyle: TextStyle( + color: AFThemeExtension.of(context).textColor, + fontSize: 16, + fontWeight: FontWeight.w500, + height: 1.5, + ), + ), + CodeConfig( + style: TextStyle( + color: AFThemeExtension.of(context).textColor, + fontSize: 16, + fontWeight: FontWeight.w500, + height: 1.5, + ), + ), + BlockquoteConfig.darkConfig, + ], + ); + } +} + +class ChatH1Config extends HeadingConfig { + const ChatH1Config({ + this.style = const TextStyle( + fontSize: 32, + height: 40 / 32, + fontWeight: FontWeight.bold, + ), + required this.dividerColor, + }); + + @override + final TextStyle style; + final Color dividerColor; + + @override + String get tag => MarkdownTag.h1.name; + + @override + HeadingDivider? get divider => HeadingDivider( + space: 10, + color: dividerColor, + height: 10, + ); +} + +///config class for h2 +class ChatH2Config extends HeadingConfig { + const ChatH2Config({ + this.style = const TextStyle( + fontSize: 24, + height: 30 / 24, + fontWeight: FontWeight.bold, + ), + required this.dividerColor, + }); + @override + final TextStyle style; + final Color dividerColor; + + @override + String get tag => MarkdownTag.h2.name; + + @override + HeadingDivider? get divider => HeadingDivider( + space: 10, + color: dividerColor, + height: 10, + ); +} + +class ChatH3Config extends HeadingConfig { + const ChatH3Config({ + this.style = const TextStyle( + fontSize: 24, + height: 30 / 24, + fontWeight: FontWeight.bold, + ), + required this.dividerColor, + }); + + @override + final TextStyle style; + final Color dividerColor; + + @override + String get tag => MarkdownTag.h3.name; + + @override + HeadingDivider? get divider => HeadingDivider( + space: 10, + color: dividerColor, + height: 10, + ); +} + +class StreamingError extends StatelessWidget { + const StreamingError({ + required this.onRetryPressed, + super.key, + }); + + final void Function() onRetryPressed; + @override + Widget build(BuildContext context) { + return Column( + children: [ + const Divider(height: 4, thickness: 1), + const VSpace(16), + Center( + child: Column( + children: [ + _aiUnvaliable(), + const VSpace(10), + _retryButton(), + ], + ), + ), + ], + ); + } + + FlowyButton _retryButton() { + return FlowyButton( + radius: BorderRadius.circular(20), + useIntrinsicWidth: true, + text: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + child: FlowyText( + LocaleKeys.chat_regenerateAnswer.tr(), + fontSize: 14, + ), + ), + onTap: onRetryPressed, + iconPadding: 0, + leftIcon: const Icon( + Icons.refresh, + size: 20, + ), + ); + } + + Padding _aiUnvaliable() { + return Padding( + padding: const EdgeInsets.all(8.0), + child: FlowyText( + LocaleKeys.chat_aiServerUnavailable.tr(), + fontSize: 14, + ), + ); + } +} diff --git a/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/message/user_text_message.dart b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/message/user_text_message.dart new file mode 100644 index 0000000000..ba5254408d --- /dev/null +++ b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/message/user_text_message.dart @@ -0,0 +1,60 @@ +import 'package:flowy_infra/theme_extension.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_chat_types/flutter_chat_types.dart'; + +class ChatTextMessageWidget extends StatelessWidget { + const ChatTextMessageWidget({ + super.key, + required this.user, + required this.messageUserId, + required this.text, + }); + + final User user; + final String messageUserId; + final String text; + + @override + Widget build(BuildContext context) { + return _textWidgetBuilder(user, context, text); + } + + Widget _textWidgetBuilder( + User user, + BuildContext context, + String text, + ) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextMessageText( + text: text, + ), + ], + ); + } +} + +/// Widget to reuse the markdown capabilities, e.g., for previews. +class TextMessageText extends StatelessWidget { + const TextMessageText({ + super.key, + required this.text, + }); + + /// Text that is shown as markdown. + final String text; + + @override + Widget build(BuildContext context) { + return FlowyText( + text, + fontSize: 16, + fontWeight: FontWeight.w500, + lineHeight: 1.5, + maxLines: 2000, + color: AFThemeExtension.of(context).textColor, + ); + } +} diff --git a/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_user_message.dart b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/user_message_bubble.dart similarity index 100% rename from frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_user_message.dart rename to frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/user_message_bubble.dart diff --git a/frontend/appflowy_flutter/pubspec.lock b/frontend/appflowy_flutter/pubspec.lock index 7938fb37c4..cb14d7a654 100644 --- a/frontend/appflowy_flutter/pubspec.lock +++ b/frontend/appflowy_flutter/pubspec.lock @@ -680,6 +680,14 @@ packages: url: "https://github.com/LucasXu0/emoji_mart.git" source: git version: "1.0.2" + flutter_highlight: + dependency: transitive + description: + name: flutter_highlight + sha256: "7b96333867aa07e122e245c033b8ad622e4e3a42a1a2372cbb098a2541d8782c" + url: "https://pub.dev" + source: hosted + version: "0.7.0" flutter_link_previewer: dependency: transitive description: @@ -1066,7 +1074,7 @@ packages: source: hosted version: "0.6.0" isolates: - dependency: transitive + dependency: "direct main" description: name: isolates sha256: ce89e4141b27b877326d3715be2dceac7a7ba89f3229785816d2d318a75ddf28 @@ -1209,6 +1217,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.2.2" + markdown_widget: + dependency: "direct main" + description: + name: markdown_widget + sha256: "216dced98962d7699a265344624bc280489d739654585ee881c95563a3252fac" + url: "https://pub.dev" + source: hosted + version: "2.3.2+6" matcher: dependency: transitive description: diff --git a/frontend/appflowy_flutter/pubspec.yaml b/frontend/appflowy_flutter/pubspec.yaml index cf352947c8..29750bedb1 100644 --- a/frontend/appflowy_flutter/pubspec.yaml +++ b/frontend/appflowy_flutter/pubspec.yaml @@ -141,6 +141,8 @@ dependencies: auto_size_text_field: ^2.2.3 reorderable_tabbar: ^1.0.6 shimmer: ^3.0.0 + isolates: ^3.0.3+8 + markdown_widget: ^2.3.2+6 # Window Manager for MacOS and Linux window_manager: ^0.3.9 diff --git a/frontend/appflowy_flutter/test/bloc_test/chat_test/chat_load_message_test.dart b/frontend/appflowy_flutter/test/bloc_test/chat_test/chat_load_message_test.dart new file mode 100644 index 0000000000..134a429a6b --- /dev/null +++ b/frontend/appflowy_flutter/test/bloc_test/chat_test/chat_load_message_test.dart @@ -0,0 +1,16 @@ +import 'package:flutter_test/flutter_test.dart'; + +import 'util.dart'; + +void main() { + // ignore: unused_local_variable + late AppFlowyChatTest chatTest; + + setUpAll(() async { + chatTest = await AppFlowyChatTest.ensureInitialized(); + }); + + test('send message', () async { + // final context = await chatTest.createChat(); + }); +} diff --git a/frontend/appflowy_flutter/test/bloc_test/chat_test/util.dart b/frontend/appflowy_flutter/test/bloc_test/chat_test/util.dart new file mode 100644 index 0000000000..29d98416b5 --- /dev/null +++ b/frontend/appflowy_flutter/test/bloc_test/chat_test/util.dart @@ -0,0 +1,44 @@ +import 'package:appflowy/plugins/ai_chat/chat.dart'; +import 'package:appflowy/workspace/application/view/view_service.dart'; +import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; + +import '../../util.dart'; + +class AppFlowyChatTest { + AppFlowyChatTest({required this.unitTest}); + + final AppFlowyUnitTest unitTest; + + static Future ensureInitialized() async { + final inner = await AppFlowyUnitTest.ensureInitialized(); + return AppFlowyChatTest(unitTest: inner); + } + + Future createChat() async { + final app = await unitTest.createWorkspace(); + final builder = AIChatPluginBuilder(); + return ViewBackendService.createView( + parentViewId: app.id, + name: "Test Chat", + layoutType: builder.layoutType, + openAfterCreate: true, + ).then((result) { + return result.fold( + (view) async { + return view; + }, + (error) { + throw Exception(); + }, + ); + }); + } +} + +Future boardResponseFuture() { + return Future.delayed(boardResponseDuration()); +} + +Duration boardResponseDuration({int milliseconds = 200}) { + return Duration(milliseconds: milliseconds); +} diff --git a/frontend/appflowy_flutter/test/util.dart b/frontend/appflowy_flutter/test/util.dart index 65303cb789..21c1020a71 100644 --- a/frontend/appflowy_flutter/test/util.dart +++ b/frontend/appflowy_flutter/test/util.dart @@ -58,7 +58,6 @@ class AppFlowyUnitTest { } WorkspacePB get currentWorkspace => workspace; - Future _loadWorkspace() async { final result = await userService.getCurrentWorkspace(); result.fold( @@ -83,15 +82,6 @@ class AppFlowyUnitTest { (error) => throw Exception(error), ); } - - Future> loadApps() async { - final result = await workspaceService.getPublicViews(); - - return result.fold( - (apps) => apps, - (error) => throw Exception(error), - ); - } } void _pathProviderInitialized() { diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.lock b/frontend/appflowy_tauri/src-tauri/Cargo.lock index 9dae4b3b63..46320ba2b9 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.lock +++ b/frontend/appflowy_tauri/src-tauri/Cargo.lock @@ -117,6 +117,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "allo-isolate" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b6d794345b06592d0ebeed8e477e41b71e5a0a49df4fc0e4184d5938b99509" +dependencies = [ + "atomic", + "pin-project", +] + [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -162,7 +172,7 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "app-error" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "bincode", @@ -182,7 +192,7 @@ dependencies = [ [[package]] name = "appflowy-ai-client" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "bytes", @@ -289,6 +299,12 @@ dependencies = [ "system-deps 6.1.1", ] +[[package]] +name = "atomic" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" + [[package]] name = "atomic_refcell" version = "0.1.10" @@ -756,7 +772,7 @@ dependencies = [ [[package]] name = "client-api" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "again", "anyhow", @@ -803,7 +819,7 @@ dependencies = [ [[package]] name = "client-websocket" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "futures-channel", "futures-util", @@ -1043,7 +1059,7 @@ dependencies = [ [[package]] name = "collab-rt-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "bincode", @@ -1068,7 +1084,7 @@ dependencies = [ [[package]] name = "collab-rt-protocol" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "async-trait", @@ -1425,7 +1441,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] name = "database-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "app-error", @@ -1817,6 +1833,7 @@ dependencies = [ name = "flowy-chat" version = "0.1.0" dependencies = [ + "allo-isolate", "bytes", "dashmap", "flowy-chat-pub", @@ -1828,6 +1845,7 @@ dependencies = [ "futures", "lib-dispatch", "lib-infra", + "log", "protobuf", "strum_macros 0.21.1", "tokio", @@ -2835,7 +2853,7 @@ dependencies = [ [[package]] name = "gotrue" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "futures-util", @@ -2852,7 +2870,7 @@ dependencies = [ [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "app-error", @@ -3284,7 +3302,7 @@ dependencies = [ [[package]] name = "infra" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "reqwest", @@ -3525,11 +3543,13 @@ dependencies = [ name = "lib-infra" version = "0.1.0" dependencies = [ + "allo-isolate", "anyhow", "async-trait", "atomic_refcell", "bytes", "chrono", + "futures", "futures-core", "md5", "pin-project", @@ -3643,9 +3663,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "loom" @@ -5772,7 +5792,7 @@ dependencies = [ [[package]] name = "shared-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "app-error", @@ -5783,6 +5803,7 @@ dependencies = [ "database-entity", "futures", "gotrue-entity", + "log", "pin-project", "reqwest", "serde", diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.toml b/frontend/appflowy_tauri/src-tauri/Cargo.toml index 6bb9cb9db6..cac7634e62 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.toml +++ b/frontend/appflowy_tauri/src-tauri/Cargo.toml @@ -52,7 +52,7 @@ collab-user = { version = "0.2" } # Run the script: # scripts/tool/update_client_api_rev.sh new_rev_id # ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "3f55cea9ca386875a1668ef30600c83cd6a1ffe2" } +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" } [dependencies] serde_json.workspace = true diff --git a/frontend/appflowy_web/wasm-libs/Cargo.lock b/frontend/appflowy_web/wasm-libs/Cargo.lock index 15c6119e02..31ad62bb38 100644 --- a/frontend/appflowy_web/wasm-libs/Cargo.lock +++ b/frontend/appflowy_web/wasm-libs/Cargo.lock @@ -216,7 +216,7 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "app-error" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "bincode", @@ -236,7 +236,7 @@ dependencies = [ [[package]] name = "appflowy-ai-client" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "bytes", @@ -562,7 +562,7 @@ dependencies = [ [[package]] name = "client-api" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "again", "anyhow", @@ -609,7 +609,7 @@ dependencies = [ [[package]] name = "client-websocket" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "futures-channel", "futures-util", @@ -787,7 +787,7 @@ dependencies = [ [[package]] name = "collab-rt-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "bincode", @@ -812,7 +812,7 @@ dependencies = [ [[package]] name = "collab-rt-protocol" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "async-trait", @@ -1026,7 +1026,7 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] name = "database-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "app-error", @@ -1881,7 +1881,7 @@ dependencies = [ [[package]] name = "gotrue" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "futures-util", @@ -1898,7 +1898,7 @@ dependencies = [ [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "app-error", @@ -2199,7 +2199,7 @@ dependencies = [ [[package]] name = "infra" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "reqwest", @@ -2339,6 +2339,7 @@ dependencies = [ "atomic_refcell", "bytes", "chrono", + "futures", "futures-core", "md5", "pin-project", @@ -2427,9 +2428,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "mac" @@ -3900,7 +3901,7 @@ dependencies = [ [[package]] name = "shared-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "app-error", @@ -3911,6 +3912,7 @@ dependencies = [ "database-entity", "futures", "gotrue-entity", + "log", "pin-project", "reqwest", "serde", diff --git a/frontend/appflowy_web/wasm-libs/Cargo.toml b/frontend/appflowy_web/wasm-libs/Cargo.toml index 2f0c25023a..4029f36c85 100644 --- a/frontend/appflowy_web/wasm-libs/Cargo.toml +++ b/frontend/appflowy_web/wasm-libs/Cargo.toml @@ -55,7 +55,7 @@ yrs = "0.18.8" # Run the script: # scripts/tool/update_client_api_rev.sh new_rev_id # ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "3f55cea9ca386875a1668ef30600c83cd6a1ffe2" } +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" } diff --git a/frontend/appflowy_web_app/src-tauri/Cargo.lock b/frontend/appflowy_web_app/src-tauri/Cargo.lock index 12d5ca3b63..4c77b63af4 100644 --- a/frontend/appflowy_web_app/src-tauri/Cargo.lock +++ b/frontend/appflowy_web_app/src-tauri/Cargo.lock @@ -108,6 +108,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "allo-isolate" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b6d794345b06592d0ebeed8e477e41b71e5a0a49df4fc0e4184d5938b99509" +dependencies = [ + "atomic", + "pin-project", +] + [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -153,7 +163,7 @@ checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "app-error" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "bincode", @@ -173,7 +183,7 @@ dependencies = [ [[package]] name = "appflowy-ai-client" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "bytes", @@ -299,6 +309,12 @@ dependencies = [ "system-deps 6.2.2", ] +[[package]] +name = "atomic" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" + [[package]] name = "atomic_refcell" version = "0.1.13" @@ -730,7 +746,7 @@ dependencies = [ [[package]] name = "client-api" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "again", "anyhow", @@ -777,7 +793,7 @@ dependencies = [ [[package]] name = "client-websocket" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "futures-channel", "futures-util", @@ -1026,7 +1042,7 @@ dependencies = [ [[package]] name = "collab-rt-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "bincode", @@ -1051,7 +1067,7 @@ dependencies = [ [[package]] name = "collab-rt-protocol" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "async-trait", @@ -1412,7 +1428,7 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] name = "database-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "app-error", @@ -1854,6 +1870,7 @@ dependencies = [ name = "flowy-chat" version = "0.1.0" dependencies = [ + "allo-isolate", "bytes", "dashmap", "flowy-chat-pub", @@ -1865,6 +1882,7 @@ dependencies = [ "futures", "lib-dispatch", "lib-infra", + "log", "protobuf", "strum_macros 0.21.1", "tokio", @@ -2909,7 +2927,7 @@ dependencies = [ [[package]] name = "gotrue" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "futures-util", @@ -2926,7 +2944,7 @@ dependencies = [ [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "app-error", @@ -3363,7 +3381,7 @@ dependencies = [ [[package]] name = "infra" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "reqwest", @@ -3609,11 +3627,13 @@ dependencies = [ name = "lib-infra" version = "0.1.0" dependencies = [ + "allo-isolate", "anyhow", "async-trait", "atomic_refcell", "bytes", "chrono", + "futures", "futures-core", "md5", "pin-project", @@ -5867,7 +5887,7 @@ dependencies = [ [[package]] name = "shared-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "app-error", @@ -5878,6 +5898,7 @@ dependencies = [ "database-entity", "futures", "gotrue-entity", + "log", "pin-project", "reqwest", "serde", diff --git a/frontend/appflowy_web_app/src-tauri/Cargo.toml b/frontend/appflowy_web_app/src-tauri/Cargo.toml index 6f03972195..be1e6b69f5 100644 --- a/frontend/appflowy_web_app/src-tauri/Cargo.toml +++ b/frontend/appflowy_web_app/src-tauri/Cargo.toml @@ -52,7 +52,7 @@ collab-user = { version = "0.2" } # Run the script: # scripts/tool/update_client_api_rev.sh new_rev_id # ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "3f55cea9ca386875a1668ef30600c83cd6a1ffe2" } +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" } [dependencies] serde_json.workspace = true diff --git a/frontend/resources/flowy_icons/16x/ai_stream_stop.svg b/frontend/resources/flowy_icons/16x/ai_stream_stop.svg new file mode 100644 index 0000000000..55c7355ab7 --- /dev/null +++ b/frontend/resources/flowy_icons/16x/ai_stream_stop.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/rust-lib/Cargo.lock b/frontend/rust-lib/Cargo.lock index abc72ec7c5..c79dab339a 100644 --- a/frontend/rust-lib/Cargo.lock +++ b/frontend/rust-lib/Cargo.lock @@ -163,7 +163,7 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "app-error" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "bincode", @@ -183,7 +183,7 @@ dependencies = [ [[package]] name = "appflowy-ai-client" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "bytes", @@ -664,7 +664,7 @@ dependencies = [ [[package]] name = "client-api" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "again", "anyhow", @@ -711,7 +711,7 @@ dependencies = [ [[package]] name = "client-websocket" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "futures-channel", "futures-util", @@ -920,7 +920,7 @@ dependencies = [ [[package]] name = "collab-rt-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "bincode", @@ -945,7 +945,7 @@ dependencies = [ [[package]] name = "collab-rt-protocol" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "async-trait", @@ -1165,7 +1165,7 @@ dependencies = [ "cssparser-macros", "dtoa-short", "itoa", - "phf 0.8.0", + "phf 0.11.2", "smallvec", ] @@ -1265,7 +1265,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] name = "database-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "app-error", @@ -1652,6 +1652,7 @@ dependencies = [ name = "flowy-chat" version = "0.1.0" dependencies = [ + "allo-isolate", "bytes", "dashmap", "flowy-chat-pub", @@ -1663,6 +1664,7 @@ dependencies = [ "futures", "lib-dispatch", "lib-infra", + "log", "protobuf", "strum_macros 0.21.1", "tokio", @@ -2521,7 +2523,7 @@ dependencies = [ [[package]] name = "gotrue" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "futures-util", @@ -2538,7 +2540,7 @@ dependencies = [ [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "app-error", @@ -2903,7 +2905,7 @@ dependencies = [ [[package]] name = "infra" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "reqwest", @@ -3045,6 +3047,7 @@ dependencies = [ name = "lib-infra" version = "0.1.0" dependencies = [ + "allo-isolate", "anyhow", "async-trait", "atomic_refcell", @@ -3156,9 +3159,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "loom" @@ -3778,7 +3781,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" dependencies = [ - "phf_macros", + "phf_macros 0.8.0", "phf_shared 0.8.0", "proc-macro-hack", ] @@ -3798,6 +3801,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ + "phf_macros 0.11.2", "phf_shared 0.11.2", ] @@ -3865,6 +3869,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator 0.11.2", + "phf_shared 0.11.2", + "proc-macro2", + "quote", + "syn 2.0.47", +] + [[package]] name = "phf_shared" version = "0.8.0" @@ -4068,7 +4085,7 @@ checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2" dependencies = [ "bytes", "heck 0.4.1", - "itertools 0.10.5", + "itertools 0.11.0", "log", "multimap", "once_cell", @@ -4089,7 +4106,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.11.0", "proc-macro2", "quote", "syn 2.0.47", @@ -4986,7 +5003,7 @@ dependencies = [ [[package]] name = "shared-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=3f55cea9ca386875a1668ef30600c83cd6a1ffe2#3f55cea9ca386875a1668ef30600c83cd6a1ffe2" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d0467e7e2e8ee4b925556b5510fb6ed7322dde8c#d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" dependencies = [ "anyhow", "app-error", @@ -4997,6 +5014,7 @@ dependencies = [ "database-entity", "futures", "gotrue-entity", + "log", "pin-project", "reqwest", "serde", diff --git a/frontend/rust-lib/Cargo.toml b/frontend/rust-lib/Cargo.toml index 39dccadd26..6282fab3c6 100644 --- a/frontend/rust-lib/Cargo.toml +++ b/frontend/rust-lib/Cargo.toml @@ -29,7 +29,8 @@ members = [ "build-tool/flowy-codegen", "build-tool/flowy-derive", "flowy-search-pub", - "flowy-chat", "flowy-chat-pub", + "flowy-chat", + "flowy-chat-pub", ] resolver = "2" @@ -93,7 +94,7 @@ yrs = "0.18.8" # Run the script.add_workspace_members: # scripts/tool/update_client_api_rev.sh new_rev_id # ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "3f55cea9ca386875a1668ef30600c83cd6a1ffe2" } +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "d0467e7e2e8ee4b925556b5510fb6ed7322dde8c" } [profile.dev] opt-level = 1 diff --git a/frontend/rust-lib/event-integration-test/src/chat_event.rs b/frontend/rust-lib/event-integration-test/src/chat_event.rs index ca2c4911f3..60e8ba65b1 100644 --- a/frontend/rust-lib/event-integration-test/src/chat_event.rs +++ b/frontend/rust-lib/event-integration-test/src/chat_event.rs @@ -43,7 +43,7 @@ impl EventIntegrationTest { }; EventBuilder::new(self.clone()) - .event(ChatEvent::SendMessage) + .event(ChatEvent::StreamMessage) .payload(payload) .async_send() .await; diff --git a/frontend/rust-lib/flowy-chat-pub/src/cloud.rs b/frontend/rust-lib/flowy-chat-pub/src/cloud.rs index 51de79422a..f8b81c250a 100644 --- a/frontend/rust-lib/flowy-chat-pub/src/cloud.rs +++ b/frontend/rust-lib/flowy-chat-pub/src/cloud.rs @@ -1,4 +1,4 @@ -pub use client_api::entity::ai_dto::{RelatedQuestion, RepeatedRelatedQuestion}; +pub use client_api::entity::ai_dto::{RelatedQuestion, RepeatedRelatedQuestion, StringOrMessage}; pub use client_api::entity::{ ChatAuthorType, ChatMessage, ChatMessageType, MessageCursor, QAChatMessage, RepeatedChatMessage, }; @@ -9,6 +9,7 @@ use lib_infra::async_trait::async_trait; use lib_infra::future::FutureResult; pub type ChatMessageStream = BoxStream<'static, Result>; +pub type StreamAnswer = BoxStream<'static, Result>; #[async_trait] pub trait ChatCloudService: Send + Sync + 'static { fn create_chat( @@ -26,6 +27,29 @@ pub trait ChatCloudService: Send + Sync + 'static { message_type: ChatMessageType, ) -> Result; + fn send_question( + &self, + workspace_id: &str, + chat_id: &str, + message: &str, + message_type: ChatMessageType, + ) -> FutureResult; + + fn save_answer( + &self, + workspace_id: &str, + chat_id: &str, + message: &str, + question_id: i64, + ) -> FutureResult; + + async fn stream_answer( + &self, + workspace_id: &str, + chat_id: &str, + message_id: i64, + ) -> Result; + fn get_chat_messages( &self, workspace_id: &str, diff --git a/frontend/rust-lib/flowy-chat/Cargo.toml b/frontend/rust-lib/flowy-chat/Cargo.toml index e1a7175442..0698a593d1 100644 --- a/frontend/rust-lib/flowy-chat/Cargo.toml +++ b/frontend/rust-lib/flowy-chat/Cargo.toml @@ -19,12 +19,14 @@ strum_macros = "0.21" protobuf.workspace = true bytes.workspace = true validator = { version = "0.16.0", features = ["derive"] } -lib-infra = { workspace = true } +lib-infra = { workspace = true, features = ["isolate_flutter"] } flowy-chat-pub.workspace = true dashmap = "5.5" flowy-sqlite = { workspace = true } tokio.workspace = true futures.workspace = true +allo-isolate = { version = "^0.1", features = ["catch-unwind"] } +log = "0.4.21" [build-dependencies] flowy-codegen.workspace = true diff --git a/frontend/rust-lib/flowy-chat/src/chat.rs b/frontend/rust-lib/flowy-chat/src/chat.rs index 70e36df27d..0f81c92c28 100644 --- a/frontend/rust-lib/flowy-chat/src/chat.rs +++ b/frontend/rust-lib/flowy-chat/src/chat.rs @@ -3,18 +3,18 @@ use crate::entities::{ }; use crate::manager::ChatUserService; use crate::notification::{send_notification, ChatNotification}; -use crate::persistence::{ - insert_answer_message, insert_chat_messages, select_chat_messages, ChatMessageTable, -}; +use crate::persistence::{insert_chat_messages, select_chat_messages, ChatMessageTable}; +use allo_isolate::Isolate; use flowy_chat_pub::cloud::{ - ChatAuthorType, ChatCloudService, ChatMessage, ChatMessageType, MessageCursor, + ChatCloudService, ChatMessage, ChatMessageType, MessageCursor, StringOrMessage, }; use flowy_error::{FlowyError, FlowyResult}; use flowy_sqlite::DBConnection; -use futures::StreamExt; -use std::sync::atomic::AtomicI64; +use futures::{SinkExt, StreamExt}; +use lib_infra::isolate_stream::IsolateSink; +use std::sync::atomic::{AtomicBool, AtomicI64}; use std::sync::Arc; -use tokio::sync::RwLock; +use tokio::sync::{Mutex, RwLock}; use tracing::{error, instrument, trace}; enum PrevMessageState { @@ -30,6 +30,8 @@ pub struct Chat { cloud_service: Arc, prev_message_state: Arc>, latest_message_id: Arc, + stop_stream: Arc, + steam_buffer: Arc>, } impl Chat { @@ -46,6 +48,8 @@ impl Chat { user_service, prev_message_state: Arc::new(RwLock::new(PrevMessageState::HasMore)), latest_message_id: Default::default(), + stop_stream: Arc::new(AtomicBool::new(false)), + steam_buffer: Arc::new(Mutex::new("".to_string())), } } @@ -63,27 +67,133 @@ impl Chat { } } + pub async fn stop_stream_message(&self) { + self + .stop_stream + .store(true, std::sync::atomic::Ordering::SeqCst); + } + #[instrument(level = "info", skip_all, err)] - pub async fn send_chat_message( + pub async fn stream_chat_message( &self, message: &str, message_type: ChatMessageType, - ) -> Result<(), FlowyError> { + text_stream_port: i64, + ) -> Result { if message.len() > 2000 { return Err(FlowyError::text_too_long().with_context("Exceeds maximum message 2000 length")); } + // clear + self + .stop_stream + .store(false, std::sync::atomic::Ordering::SeqCst); + self.steam_buffer.lock().await.clear(); + let stream_buffer = self.steam_buffer.clone(); let uid = self.user_service.user_id()?; let workspace_id = self.user_service.workspace_id()?; - stream_send_chat_messages( - uid, - workspace_id, - self.chat_id.clone(), - message.to_string(), - message_type, - self.cloud_service.clone(), - self.user_service.clone(), - ); + + let question = self + .cloud_service + .send_question(&workspace_id, &self.chat_id, message, message_type) + .await + .map_err(|err| { + error!("Failed to send question: {}", err); + FlowyError::server_error() + })?; + + save_chat_message( + self.user_service.sqlite_connection(uid)?, + &self.chat_id, + vec![question.clone()], + )?; + + let stop_stream = self.stop_stream.clone(); + let chat_id = self.chat_id.clone(); + let question_id = question.message_id; + let cloud_service = self.cloud_service.clone(); + let user_service = self.user_service.clone(); + tokio::spawn(async move { + let mut text_sink = IsolateSink::new(Isolate::new(text_stream_port)); + match cloud_service + .stream_answer(&workspace_id, &chat_id, question_id) + .await + { + Ok(mut stream) => { + while let Some(message) = stream.next().await { + match message { + Ok(message) => match message { + StringOrMessage::Left(s) => { + if stop_stream.load(std::sync::atomic::Ordering::Relaxed) { + send_notification(&chat_id, ChatNotification::FinishStreaming).send(); + trace!("[Chat] stop streaming message"); + let answer = cloud_service + .save_answer( + &workspace_id, + &chat_id, + &stream_buffer.lock().await, + question_id, + ) + .await?; + Self::save_answer(uid, &chat_id, &user_service, answer)?; + break; + } + stream_buffer.lock().await.push_str(&s); + let _ = text_sink.send(format!("data:{}", s)).await; + }, + StringOrMessage::Right(answer) => { + trace!("[Chat] received final answer: {:?}", answer); + send_notification(&chat_id, ChatNotification::FinishStreaming).send(); + Self::save_answer(uid, &chat_id, &user_service, answer)?; + }, + }, + Err(err) => { + error!("[Chat] failed to stream answer: {}", err); + let _ = text_sink.send(format!("error:{}", err)).await; + let pb = ChatMessageErrorPB { + chat_id: chat_id.clone(), + error_message: err.to_string(), + }; + send_notification(&chat_id, ChatNotification::StreamChatMessageError) + .payload(pb) + .send(); + break; + }, + } + } + }, + Err(err) => { + let pb = ChatMessageErrorPB { + chat_id: chat_id.clone(), + error_message: err.to_string(), + }; + send_notification(&chat_id, ChatNotification::StreamChatMessageError) + .payload(pb) + .send(); + }, + } + Ok::<(), FlowyError>(()) + }); + + let question_pb = ChatMessagePB::from(question); + Ok(question_pb) + } + + fn save_answer( + uid: i64, + chat_id: &str, + user_service: &Arc, + answer: ChatMessage, + ) -> Result<(), FlowyError> { + save_chat_message( + user_service.sqlite_connection(uid)?, + chat_id, + vec![answer.clone()], + )?; + let pb = ChatMessagePB::from(answer); + send_notification(chat_id, ChatNotification::DidReceiveChatMessage) + .payload(pb) + .send(); Ok(()) } @@ -106,7 +216,7 @@ impl Chat { before_message_id: Option, ) -> Result { trace!( - "Loading old messages: chat_id={}, limit={}, before_message_id={:?}", + "[Chat] Loading messages from disk: chat_id={}, limit={}, before_message_id={:?}", self.chat_id, limit, before_message_id @@ -116,13 +226,16 @@ impl Chat { .await?; // If the number of messages equals the limit, then no need to load more messages from remote - let has_more = !messages.is_empty(); if messages.len() == limit as usize { - return Ok(ChatMessageListPB { + let pb = ChatMessageListPB { messages, - has_more, + has_more: true, total: 0, - }); + }; + send_notification(&self.chat_id, ChatNotification::DidLoadPrevChatMessage) + .payload(pb.clone()) + .send(); + return Ok(pb); } if matches!( @@ -140,7 +253,7 @@ impl Chat { Ok(ChatMessageListPB { messages, - has_more, + has_more: true, total: 0, }) } @@ -151,7 +264,7 @@ impl Chat { after_message_id: Option, ) -> Result { trace!( - "Loading new messages: chat_id={}, limit={}, after_message_id={:?}", + "[Chat] Loading new messages: chat_id={}, limit={}, after_message_id={:?}", self.chat_id, limit, after_message_id, @@ -161,7 +274,7 @@ impl Chat { .await?; trace!( - "Loaded local chat messages: chat_id={}, messages={}", + "[Chat] Loaded local chat messages: chat_id={}, messages={}", self.chat_id, messages.len() ); @@ -185,7 +298,7 @@ impl Chat { after_message_id: Option, ) -> FlowyResult<()> { trace!( - "Loading chat messages from remote: chat_id={}, limit={}, before_message_id={:?}, after_message_id={:?}", + "[Chat] start loading messages from remote: chat_id={}, limit={}, before_message_id={:?}, after_message_id={:?}", self.chat_id, limit, before_message_id, @@ -228,9 +341,11 @@ impl Chat { let pb = ChatMessageListPB::from(resp); trace!( - "Loaded chat messages from remote: chat_id={}, messages={}", + "[Chat] Loaded messages from remote: chat_id={}, messages={}, hasMore: {}, cursor:{:?}", chat_id, - pb.messages.len() + pb.messages.len(), + pb.has_more, + cursor, ); if matches!(cursor, MessageCursor::BeforeMessageId(_)) { if pb.has_more { @@ -265,7 +380,7 @@ impl Chat { .await?; trace!( - "Related messages: chat_id={}, message_id={}, messages:{:?}", + "[Chat] related messages: chat_id={}, message_id={}, messages:{:?}", self.chat_id, message_id, resp.items @@ -275,20 +390,19 @@ impl Chat { #[instrument(level = "debug", skip_all, err)] pub async fn generate_answer(&self, question_message_id: i64) -> FlowyResult { + trace!( + "[Chat] generate answer: chat_id={}, question_message_id={}", + self.chat_id, + question_message_id + ); let workspace_id = self.user_service.workspace_id()?; - let resp = self + let answer = self .cloud_service .generate_answer(&workspace_id, &self.chat_id, question_message_id) .await?; - save_answer( - self.user_service.sqlite_connection(self.uid)?, - &self.chat_id, - resp.clone(), - question_message_id, - )?; - - let pb = ChatMessagePB::from(resp); + Self::save_answer(self.uid, &self.chat_id, &self.user_service, answer.clone())?; + let pb = ChatMessagePB::from(answer); Ok(pb) } @@ -314,7 +428,6 @@ impl Chat { created_at: record.created_at, author_type: record.author_type, author_id: record.author_id, - has_following: false, reply_message_id: record.reply_message_id, }) .collect::>(); @@ -323,114 +436,6 @@ impl Chat { } } -fn stream_send_chat_messages( - uid: i64, - workspace_id: String, - chat_id: String, - message_content: String, - message_type: ChatMessageType, - cloud_service: Arc, - user_service: Arc, -) { - tokio::spawn(async move { - trace!( - "Sending chat message: chat_id={}, message={}, type={:?}", - chat_id, - message_content, - message_type - ); - - let mut messages = Vec::with_capacity(2); - let stream_result = cloud_service - .send_chat_message(&workspace_id, &chat_id, &message_content, message_type) - .await; - - // By default, stream only returns two messages: - // 1. user message - // 2. ai response message - match stream_result { - Ok(mut stream) => { - while let Some(result) = stream.next().await { - match result { - Ok(message) => { - let mut pb = ChatMessagePB::from(message.clone()); - if matches!(message.author.author_type, ChatAuthorType::Human) { - pb.has_following = true; - send_notification(&chat_id, ChatNotification::LastUserSentMessage) - .payload(pb.clone()) - .send(); - } - - // - send_notification(&chat_id, ChatNotification::DidReceiveChatMessage) - .payload(pb) - .send(); - messages.push(message); - }, - Err(err) => { - error!("stream chat message error: {}", err); - let pb = ChatMessageErrorPB { - chat_id: chat_id.clone(), - content: message_content.clone(), - error_message: "Service Temporarily Unavailable".to_string(), - }; - send_notification(&chat_id, ChatNotification::StreamChatMessageError) - .payload(pb) - .send(); - break; - }, - } - } - }, - Err(err) => { - error!("Failed to send chat message: {}", err); - let pb = ChatMessageErrorPB { - chat_id: chat_id.clone(), - content: message_content.clone(), - error_message: err.to_string(), - }; - send_notification(&chat_id, ChatNotification::StreamChatMessageError) - .payload(pb) - .send(); - return; - }, - } - - if messages.is_empty() { - return; - } - - trace!( - "Saving chat messages to local disk: chat_id={}, messages:{:?}", - chat_id, - messages - ); - - // Insert chat messages to local disk - if let Err(err) = user_service.sqlite_connection(uid).and_then(|conn| { - let records = messages - .into_iter() - .map(|message| ChatMessageTable { - message_id: message.message_id, - chat_id: chat_id.clone(), - content: message.content, - created_at: message.created_at.timestamp(), - author_type: message.author.author_type as i64, - author_id: message.author.author_id.to_string(), - reply_message_id: message.reply_message_id, - }) - .collect::>(); - insert_chat_messages(conn, &records)?; - - // Mark chat as finished - send_notification(&chat_id, ChatNotification::FinishAnswerQuestion).send(); - Ok(()) - }) { - error!("Failed to save chat messages: {}", err); - } - }); -} - fn save_chat_message( conn: DBConnection, chat_id: &str, @@ -451,21 +456,3 @@ fn save_chat_message( insert_chat_messages(conn, &records)?; Ok(()) } -fn save_answer( - conn: DBConnection, - chat_id: &str, - message: ChatMessage, - question_message_id: i64, -) -> FlowyResult<()> { - let record = ChatMessageTable { - message_id: message.message_id, - chat_id: chat_id.to_string(), - content: message.content, - created_at: message.created_at.timestamp(), - author_type: message.author.author_type as i64, - author_id: message.author.author_id.to_string(), - reply_message_id: message.reply_message_id, - }; - insert_answer_message(conn, question_message_id, record)?; - Ok(()) -} diff --git a/frontend/rust-lib/flowy-chat/src/entities.rs b/frontend/rust-lib/flowy-chat/src/entities.rs index e01c2aaad1..4ef687c3c4 100644 --- a/frontend/rust-lib/flowy-chat/src/entities.rs +++ b/frontend/rust-lib/flowy-chat/src/entities.rs @@ -19,6 +19,30 @@ pub struct SendChatPayloadPB { pub message_type: ChatMessageTypePB, } +#[derive(Default, ProtoBuf, Validate, Clone, Debug)] +pub struct StreamChatPayloadPB { + #[pb(index = 1)] + #[validate(custom = "required_not_empty_str")] + pub chat_id: String, + + #[pb(index = 2)] + #[validate(custom = "required_not_empty_str")] + pub message: String, + + #[pb(index = 3)] + pub message_type: ChatMessageTypePB, + + #[pb(index = 4)] + pub text_stream_port: i64, +} + +#[derive(Default, ProtoBuf, Validate, Clone, Debug)] +pub struct StopStreamPB { + #[pb(index = 1)] + #[validate(custom = "required_not_empty_str")] + pub chat_id: String, +} + #[derive(Debug, Default, Clone, ProtoBuf_Enum, PartialEq, Eq, Copy)] pub enum ChatMessageTypePB { #[default] @@ -97,10 +121,7 @@ pub struct ChatMessagePB { #[pb(index = 5)] pub author_id: String, - #[pb(index = 6)] - pub has_following: bool, - - #[pb(index = 7, one_of)] + #[pb(index = 6, one_of)] pub reply_message_id: Option, } @@ -110,9 +131,6 @@ pub struct ChatMessageErrorPB { pub chat_id: String, #[pb(index = 2)] - pub content: String, - - #[pb(index = 3)] pub error_message: String, } @@ -124,7 +142,6 @@ impl From for ChatMessagePB { created_at: chat_message.created_at.timestamp(), author_type: chat_message.author.author_type as i64, author_id: chat_message.author.author_id.to_string(), - has_following: false, reply_message_id: None, } } diff --git a/frontend/rust-lib/flowy-chat/src/event_handler.rs b/frontend/rust-lib/flowy-chat/src/event_handler.rs index 959c0398b4..1d4499c6b2 100644 --- a/frontend/rust-lib/flowy-chat/src/event_handler.rs +++ b/frontend/rust-lib/flowy-chat/src/event_handler.rs @@ -18,10 +18,10 @@ fn upgrade_chat_manager( } #[tracing::instrument(level = "debug", skip_all, err)] -pub(crate) async fn send_chat_message_handler( - data: AFPluginData, +pub(crate) async fn stream_chat_message_handler( + data: AFPluginData, chat_manager: AFPluginState>, -) -> Result<(), FlowyError> { +) -> DataResult { let chat_manager = upgrade_chat_manager(chat_manager)?; let data = data.into_inner(); data.validate()?; @@ -30,10 +30,16 @@ pub(crate) async fn send_chat_message_handler( ChatMessageTypePB::System => ChatMessageType::System, ChatMessageTypePB::User => ChatMessageType::User, }; - chat_manager - .send_chat_message(&data.chat_id, &data.message, message_type) + + let question = chat_manager + .stream_chat_message( + &data.chat_id, + &data.message, + message_type, + data.text_stream_port, + ) .await?; - Ok(()) + data_result_ok(question) } #[tracing::instrument(level = "debug", skip_all, err)] @@ -91,3 +97,16 @@ pub(crate) async fn get_answer_handler( .await?; data_result_ok(message) } + +#[tracing::instrument(level = "debug", skip_all, err)] +pub(crate) async fn stop_stream_handler( + data: AFPluginData, + chat_manager: AFPluginState>, +) -> Result<(), FlowyError> { + let data = data.into_inner(); + data.validate()?; + + let chat_manager = upgrade_chat_manager(chat_manager)?; + chat_manager.stop_stream(&data.chat_id).await?; + Ok(()) +} diff --git a/frontend/rust-lib/flowy-chat/src/event_map.rs b/frontend/rust-lib/flowy-chat/src/event_map.rs index 9fae853459..e3b7828936 100644 --- a/frontend/rust-lib/flowy-chat/src/event_map.rs +++ b/frontend/rust-lib/flowy-chat/src/event_map.rs @@ -12,11 +12,12 @@ pub fn init(chat_manager: Weak) -> AFPlugin { AFPlugin::new() .name("Flowy-Chat") .state(chat_manager) - .event(ChatEvent::SendMessage, send_chat_message_handler) + .event(ChatEvent::StreamMessage, stream_chat_message_handler) .event(ChatEvent::LoadPrevMessage, load_prev_message_handler) .event(ChatEvent::LoadNextMessage, load_next_message_handler) .event(ChatEvent::GetRelatedQuestion, get_related_question_handler) .event(ChatEvent::GetAnswerForQuestion, get_answer_handler) + .event(ChatEvent::StopStream, stop_stream_handler) } #[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)] @@ -29,12 +30,15 @@ pub enum ChatEvent { #[event(input = "LoadNextChatMessagePB", output = "ChatMessageListPB")] LoadNextMessage = 1, - #[event(input = "SendChatPayloadPB")] - SendMessage = 2, + #[event(input = "StreamChatPayloadPB", output = "ChatMessagePB")] + StreamMessage = 2, + + #[event(input = "StopStreamPB")] + StopStream = 3, #[event(input = "ChatMessageIdPB", output = "RepeatedRelatedQuestionPB")] - GetRelatedQuestion = 3, + GetRelatedQuestion = 4, #[event(input = "ChatMessageIdPB", output = "ChatMessagePB")] - GetAnswerForQuestion = 4, + GetAnswerForQuestion = 5, } diff --git a/frontend/rust-lib/flowy-chat/src/manager.rs b/frontend/rust-lib/flowy-chat/src/manager.rs index b2cc679eb2..b72cdfb87d 100644 --- a/frontend/rust-lib/flowy-chat/src/manager.rs +++ b/frontend/rust-lib/flowy-chat/src/manager.rs @@ -7,7 +7,7 @@ use flowy_error::{FlowyError, FlowyResult}; use flowy_sqlite::DBConnection; use lib_infra::util::timestamp; use std::sync::Arc; -use tracing::{instrument, trace}; +use tracing::trace; pub trait ChatUserService: Send + Sync + 'static { fn user_id(&self) -> Result; @@ -79,16 +79,18 @@ impl ChatManager { Ok(chat) } - #[instrument(level = "info", skip_all, err)] - pub async fn send_chat_message( + pub async fn stream_chat_message( &self, chat_id: &str, message: &str, message_type: ChatMessageType, - ) -> Result<(), FlowyError> { + text_stream_port: i64, + ) -> Result { let chat = self.get_or_create_chat_instance(chat_id).await?; - chat.send_chat_message(message, message_type).await?; - Ok(()) + let question = chat + .stream_chat_message(message, message_type, text_stream_port) + .await?; + Ok(question) } pub async fn get_or_create_chat_instance(&self, chat_id: &str) -> Result, FlowyError> { @@ -168,6 +170,12 @@ impl ChatManager { let resp = chat.generate_answer(question_message_id).await?; Ok(resp) } + + pub async fn stop_stream(&self, chat_id: &str) -> Result<(), FlowyError> { + let chat = self.get_or_create_chat_instance(chat_id).await?; + chat.stop_stream_message().await; + Ok(()) + } } fn save_chat(conn: DBConnection, chat_id: &str) -> FlowyResult<()> { diff --git a/frontend/rust-lib/flowy-chat/src/notification.rs b/frontend/rust-lib/flowy-chat/src/notification.rs index 830c464a72..12f0470784 100644 --- a/frontend/rust-lib/flowy-chat/src/notification.rs +++ b/frontend/rust-lib/flowy-chat/src/notification.rs @@ -11,8 +11,7 @@ pub enum ChatNotification { DidLoadPrevChatMessage = 2, DidReceiveChatMessage = 3, StreamChatMessageError = 4, - FinishAnswerQuestion = 5, - LastUserSentMessage = 6, + FinishStreaming = 5, } impl std::convert::From for i32 { @@ -27,8 +26,7 @@ impl std::convert::From for ChatNotification { 2 => ChatNotification::DidLoadPrevChatMessage, 3 => ChatNotification::DidReceiveChatMessage, 4 => ChatNotification::StreamChatMessageError, - 5 => ChatNotification::FinishAnswerQuestion, - 6 => ChatNotification::LastUserSentMessage, + 5 => ChatNotification::FinishStreaming, _ => ChatNotification::Unknown, } } diff --git a/frontend/rust-lib/flowy-chat/src/persistence/chat_message_sql.rs b/frontend/rust-lib/flowy-chat/src/persistence/chat_message_sql.rs index 3e65123c27..6d9202def0 100644 --- a/frontend/rust-lib/flowy-chat/src/persistence/chat_message_sql.rs +++ b/frontend/rust-lib/flowy-chat/src/persistence/chat_message_sql.rs @@ -45,41 +45,6 @@ pub fn insert_chat_messages( Ok(()) } -pub fn insert_answer_message( - mut conn: DBConnection, - question_message_id: i64, - message: ChatMessageTable, -) -> FlowyResult<()> { - conn.immediate_transaction(|conn| { - // Step 1: Get the message with the given question_message_id - let question_message = dsl::chat_message_table - .filter(chat_message_table::message_id.eq(question_message_id)) - .first::(conn)?; - - // Step 2: Use reply_message_id from the retrieved message to delete the existing message - if let Some(reply_id) = question_message.reply_message_id { - diesel::delete(dsl::chat_message_table.filter(chat_message_table::message_id.eq(reply_id))) - .execute(conn)?; - } - - // Step 3: Insert the new message - let _ = insert_into(chat_message_table::table) - .values(message) - .on_conflict(chat_message_table::message_id) - .do_update() - .set(( - chat_message_table::content.eq(excluded(chat_message_table::content)), - chat_message_table::created_at.eq(excluded(chat_message_table::created_at)), - chat_message_table::author_type.eq(excluded(chat_message_table::author_type)), - chat_message_table::author_id.eq(excluded(chat_message_table::author_id)), - chat_message_table::reply_message_id.eq(excluded(chat_message_table::reply_message_id)), - )) - .execute(conn)?; - Ok::<(), FlowyError>(()) - })?; - - Ok(()) -} pub fn select_chat_messages( mut conn: DBConnection, chat_id_val: &str, diff --git a/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs b/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs index 5c383d204a..e3a86d4fc7 100644 --- a/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs +++ b/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs @@ -30,6 +30,7 @@ use tokio::sync::RwLock; use crate::integrate::server::ServerProvider; pub struct FolderDepsResolver(); +#[allow(clippy::too_many_arguments)] impl FolderDepsResolver { pub async fn resolve( authenticate_user: Weak, diff --git a/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs b/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs index 2e672dec6c..98f08761e6 100644 --- a/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs +++ b/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs @@ -18,6 +18,7 @@ use collab_integrate::collab_builder::{ }; use flowy_chat_pub::cloud::{ ChatCloudService, ChatMessage, ChatMessageStream, MessageCursor, RepeatedChatMessage, + StreamAnswer, }; use flowy_database_pub::cloud::{ CollabDocStateByOid, DatabaseCloudService, DatabaseSnapshot, SummaryRowContent, @@ -476,6 +477,60 @@ impl ChatCloudService for ServerProvider { .await } + fn send_question( + &self, + workspace_id: &str, + chat_id: &str, + message: &str, + message_type: ChatMessageType, + ) -> FutureResult { + let workspace_id = workspace_id.to_string(); + let chat_id = chat_id.to_string(); + let message = message.to_string(); + let server = self.get_server(); + + FutureResult::new(async move { + server? + .chat_service() + .send_question(&workspace_id, &chat_id, &message, message_type) + .await + }) + } + + fn save_answer( + &self, + workspace_id: &str, + chat_id: &str, + message: &str, + question_id: i64, + ) -> FutureResult { + let workspace_id = workspace_id.to_string(); + let chat_id = chat_id.to_string(); + let message = message.to_string(); + let server = self.get_server(); + FutureResult::new(async move { + server? + .chat_service() + .save_answer(&workspace_id, &chat_id, &message, question_id) + .await + }) + } + + async fn stream_answer( + &self, + workspace_id: &str, + chat_id: &str, + message_id: i64, + ) -> Result { + let workspace_id = workspace_id.to_string(); + let chat_id = chat_id.to_string(); + let server = self.get_server()?; + server + .chat_service() + .stream_answer(&workspace_id, &chat_id, message_id) + .await + } + fn get_chat_messages( &self, workspace_id: &str, diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/impls/chat.rs b/frontend/rust-lib/flowy-server/src/af_cloud/impls/chat.rs index cc484a9346..09469f5b35 100644 --- a/frontend/rust-lib/flowy-server/src/af_cloud/impls/chat.rs +++ b/frontend/rust-lib/flowy-server/src/af_cloud/impls/chat.rs @@ -1,9 +1,12 @@ use crate::af_cloud::AFServer; use client_api::entity::ai_dto::RepeatedRelatedQuestion; use client_api::entity::{ - CreateChatMessageParams, CreateChatParams, MessageCursor, RepeatedChatMessage, + CreateAnswerMessageParams, CreateChatMessageParams, CreateChatParams, MessageCursor, + RepeatedChatMessage, +}; +use flowy_chat_pub::cloud::{ + ChatCloudService, ChatMessage, ChatMessageStream, ChatMessageType, StreamAnswer, }; -use flowy_chat_pub::cloud::{ChatCloudService, ChatMessage, ChatMessageStream, ChatMessageType}; use flowy_error::FlowyError; use futures_util::StreamExt; use lib_infra::async_trait::async_trait; @@ -50,22 +53,81 @@ where message: &str, message_type: ChatMessageType, ) -> Result { - let workspace_id = workspace_id.to_string(); - let chat_id = chat_id.to_string(); - let message = message.to_string(); let try_get_client = self.inner.try_get_client(); let params = CreateChatMessageParams { - content: message, + content: message.to_string(), message_type, }; let stream = try_get_client? - .create_chat_message(&workspace_id, &chat_id, params) + .create_chat_qa_message(workspace_id, chat_id, params) .await .map_err(FlowyError::from)?; Ok(stream.boxed()) } + fn send_question( + &self, + workspace_id: &str, + chat_id: &str, + message: &str, + message_type: ChatMessageType, + ) -> FutureResult { + let workspace_id = workspace_id.to_string(); + let chat_id = chat_id.to_string(); + let try_get_client = self.inner.try_get_client(); + let params = CreateChatMessageParams { + content: message.to_string(), + message_type, + }; + + FutureResult::new(async move { + let message = try_get_client? + .create_question(&workspace_id, &chat_id, params) + .await + .map_err(FlowyError::from)?; + Ok(message) + }) + } + + fn save_answer( + &self, + workspace_id: &str, + chat_id: &str, + message: &str, + question_id: i64, + ) -> FutureResult { + let workspace_id = workspace_id.to_string(); + let chat_id = chat_id.to_string(); + let try_get_client = self.inner.try_get_client(); + let params = CreateAnswerMessageParams { + content: message.to_string(), + question_message_id: question_id, + }; + + FutureResult::new(async move { + let message = try_get_client? + .create_answer(&workspace_id, &chat_id, params) + .await + .map_err(FlowyError::from)?; + Ok(message) + }) + } + + async fn stream_answer( + &self, + workspace_id: &str, + chat_id: &str, + message_id: i64, + ) -> Result { + let try_get_client = self.inner.try_get_client(); + let stream = try_get_client? + .stream_answer(workspace_id, chat_id, message_id) + .await + .map_err(FlowyError::from)?; + Ok(stream.boxed()) + } + fn get_chat_messages( &self, workspace_id: &str, @@ -119,7 +181,7 @@ where FutureResult::new(async move { let resp = try_get_client? - .generate_question_answer(&workspace_id, &chat_id, question_message_id) + .get_answer(&workspace_id, &chat_id, question_message_id) .await .map_err(FlowyError::from)?; Ok(resp) diff --git a/frontend/rust-lib/flowy-server/src/default_impl.rs b/frontend/rust-lib/flowy-server/src/default_impl.rs index 654bffcb1c..90d9bf15a7 100644 --- a/frontend/rust-lib/flowy-server/src/default_impl.rs +++ b/frontend/rust-lib/flowy-server/src/default_impl.rs @@ -1,6 +1,6 @@ use client_api::entity::ai_dto::RepeatedRelatedQuestion; use client_api::entity::{ChatMessageType, MessageCursor, RepeatedChatMessage}; -use flowy_chat_pub::cloud::{ChatCloudService, ChatMessage, ChatMessageStream}; +use flowy_chat_pub::cloud::{ChatCloudService, ChatMessage, ChatMessageStream, StreamAnswer}; use flowy_error::FlowyError; use lib_infra::async_trait::async_trait; use lib_infra::future::FutureResult; @@ -30,6 +30,39 @@ impl ChatCloudService for DefaultChatCloudServiceImpl { Err(FlowyError::not_support().with_context("Chat is not supported in local server.")) } + fn send_question( + &self, + _workspace_id: &str, + _chat_id: &str, + _message: &str, + _message_type: ChatMessageType, + ) -> FutureResult { + FutureResult::new(async move { + Err(FlowyError::not_support().with_context("Chat is not supported in local server.")) + }) + } + + fn save_answer( + &self, + _workspace_id: &str, + _chat_id: &str, + _message: &str, + _question_id: i64, + ) -> FutureResult { + FutureResult::new(async move { + Err(FlowyError::not_support().with_context("Chat is not supported in local server.")) + }) + } + + async fn stream_answer( + &self, + _workspace_id: &str, + _chat_id: &str, + _message_id: i64, + ) -> Result { + Err(FlowyError::not_support().with_context("Chat is not supported in local server.")) + } + fn get_chat_messages( &self, _workspace_id: &str, diff --git a/frontend/rust-lib/lib-infra/Cargo.toml b/frontend/rust-lib/lib-infra/Cargo.toml index 82f39cbf1b..c19b7a50cc 100644 --- a/frontend/rust-lib/lib-infra/Cargo.toml +++ b/frontend/rust-lib/lib-infra/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["cdylib", "rlib"] [dependencies] -chrono = { workspace = true, default-features = false, features = ["clock"] } +chrono = { workspace = true, default-features = false, features = ["clock"] } bytes = { version = "1.5" } pin-project = "1.1.3" futures-core = { version = "0.3" } @@ -21,6 +21,8 @@ tempfile = "3.8.1" validator = "0.16.0" tracing.workspace = true atomic_refcell = "0.1" +allo-isolate = { version = "^0.1", features = ["catch-unwind"], optional = true } +futures = "0.3.30" [dev-dependencies] rand = "0.8.5" @@ -28,7 +30,8 @@ futures = "0.3.30" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] zip = { version = "0.6.6", features = ["deflate"] } -brotli = { version = "3.4.0", optional = true } +brotli = { version = "3.4.0", optional = true } [features] -compression = ["brotli"] \ No newline at end of file +compression = ["brotli"] +isolate_flutter = ["allo-isolate"] diff --git a/frontend/rust-lib/lib-infra/src/isolate_stream.rs b/frontend/rust-lib/lib-infra/src/isolate_stream.rs new file mode 100644 index 0000000000..19f692dda4 --- /dev/null +++ b/frontend/rust-lib/lib-infra/src/isolate_stream.rs @@ -0,0 +1,44 @@ +use allo_isolate::{IntoDart, Isolate}; +use futures::Sink; +use pin_project::pin_project; +use std::pin::Pin; +use std::task::{Context, Poll}; + +#[pin_project] +pub struct IsolateSink { + isolate: Isolate, +} + +impl IsolateSink { + pub fn new(isolate: Isolate) -> Self { + Self { isolate } + } +} + +impl Sink for IsolateSink +where + T: IntoDart, +{ + type Error = (); + + fn poll_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn start_send(self: Pin<&mut Self>, item: T) -> Result<(), Self::Error> { + let this = self.project(); + if this.isolate.post(item) { + Ok(()) + } else { + Err(()) + } + } + + fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } +} diff --git a/frontend/rust-lib/lib-infra/src/lib.rs b/frontend/rust-lib/lib-infra/src/lib.rs index f6f1b4b1b0..18539e49aa 100644 --- a/frontend/rust-lib/lib-infra/src/lib.rs +++ b/frontend/rust-lib/lib-infra/src/lib.rs @@ -19,6 +19,8 @@ if_wasm! { } } +#[cfg(feature = "isolate_flutter")] +pub mod isolate_stream; pub mod priority_task; pub mod ref_map; pub mod util; From 38d2bd7ee8f8f8250dd3f78aa43f0f19785acc0b Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Mon, 10 Jun 2024 09:04:01 +0800 Subject: [PATCH 15/16] fix: board shortcuts conflict with textfield (#5487) * fix: board shortcuts conflict with text field * fix: typo * fix: favorite icon issue in dark mode --- .../board/presentation/board_page.dart | 113 +++++++-------- .../widgets/board_column_header.dart | 8 -- .../widgets/board_focus_scope.dart | 42 +++--- .../widgets/board_shortcut_container.dart | 136 ++++++++++-------- .../plugins/shared/callback_shortcuts.dart | 17 +-- .../application/favorite/favorite_bloc.dart | 3 +- .../presentation/widgets/favorite_button.dart | 2 +- 7 files changed, 165 insertions(+), 156 deletions(-) diff --git a/frontend/appflowy_flutter/lib/plugins/database/board/presentation/board_page.dart b/frontend/appflowy_flutter/lib/plugins/database/board/presentation/board_page.dart index a32abd33aa..a1f3a78f75 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/board/presentation/board_page.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/board/presentation/board_page.dart @@ -14,7 +14,6 @@ import 'package:appflowy/plugins/database/tab_bar/tab_bar_view.dart'; import 'package:appflowy/plugins/database/widgets/card/card_bloc.dart'; import 'package:appflowy/plugins/database/widgets/cell/card_cell_style_maps/desktop_board_card_cell_style.dart'; import 'package:appflowy/plugins/database/widgets/row/row_detail.dart'; -import 'package:appflowy/plugins/shared/callback_shortcuts.dart'; import 'package:appflowy/shared/conditional_listenable_builder.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; @@ -29,7 +28,6 @@ import 'package:flowy_infra_ui/widget/flowy_tooltip.dart'; import 'package:flutter/material.dart' hide Card; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:provider/provider.dart'; import '../../widgets/card/card.dart'; import '../../widgets/cell/card_cell_builder.dart'; @@ -322,67 +320,64 @@ class _BoardContentState extends State<_BoardContent> { }, ), ], - child: Provider( - create: (context) => AFCallbackShortcutsProvider(), - child: FocusScope( - autofocus: true, - child: BoardShortcutContainer( - focusScope: widget.focusScope, - child: Padding( - padding: const EdgeInsets.only(top: 8.0), - child: AppFlowyBoard( - boardScrollController: scrollManager, - scrollController: scrollController, - controller: context.read().boardController, - groupConstraints: const BoxConstraints.tightFor(width: 256), - config: config, - leading: HiddenGroupsColumn(margin: config.groupHeaderPadding), - trailing: context - .read() - .groupingFieldType - ?.canCreateNewGroup ?? - false - ? BoardTrailing(scrollController: scrollController) - : const HSpace(40), - headerBuilder: (_, groupData) => BlocProvider.value( - value: context.read(), - child: BoardColumnHeader( - groupData: groupData, - margin: config.groupHeaderPadding, - ), + child: FocusScope( + autofocus: true, + child: BoardShortcutContainer( + focusScope: widget.focusScope, + child: Padding( + padding: const EdgeInsets.only(top: 8.0), + child: AppFlowyBoard( + boardScrollController: scrollManager, + scrollController: scrollController, + controller: context.read().boardController, + groupConstraints: const BoxConstraints.tightFor(width: 256), + config: config, + leading: HiddenGroupsColumn(margin: config.groupHeaderPadding), + trailing: context + .read() + .groupingFieldType + ?.canCreateNewGroup ?? + false + ? BoardTrailing(scrollController: scrollController) + : const HSpace(40), + headerBuilder: (_, groupData) => BlocProvider.value( + value: context.read(), + child: BoardColumnHeader( + groupData: groupData, + margin: config.groupHeaderPadding, ), - footerBuilder: (_, groupData) => MultiBlocProvider( - providers: [ - BlocProvider.value( - value: context.read(), - ), - BlocProvider.value( - value: context.read(), - ), - ], - child: BoardColumnFooter( - columnData: groupData, - boardConfig: config, - scrollManager: scrollManager, + ), + footerBuilder: (_, groupData) => MultiBlocProvider( + providers: [ + BlocProvider.value( + value: context.read(), ), + BlocProvider.value( + value: context.read(), + ), + ], + child: BoardColumnFooter( + columnData: groupData, + boardConfig: config, + scrollManager: scrollManager, ), - cardBuilder: (_, column, columnItem) => MultiBlocProvider( - key: ValueKey("board_card_${column.id}_${columnItem.id}"), - providers: [ - BlocProvider.value( - value: context.read(), - ), - BlocProvider.value( - value: context.read(), - ), - ], - child: _BoardCard( - afGroupData: column, - groupItem: columnItem as GroupItem, - boardConfig: config, - notifier: widget.focusScope, - cellBuilder: cellBuilder, + ), + cardBuilder: (_, column, columnItem) => MultiBlocProvider( + key: ValueKey("board_card_${column.id}_${columnItem.id}"), + providers: [ + BlocProvider.value( + value: context.read(), ), + BlocProvider.value( + value: context.read(), + ), + ], + child: _BoardCard( + afGroupData: column, + groupItem: columnItem as GroupItem, + boardConfig: config, + notifier: widget.focusScope, + cellBuilder: cellBuilder, ), ), ), diff --git a/frontend/appflowy_flutter/lib/plugins/database/board/presentation/widgets/board_column_header.dart b/frontend/appflowy_flutter/lib/plugins/database/board/presentation/widgets/board_column_header.dart index 53cd3c1e4f..4504563a97 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/board/presentation/widgets/board_column_header.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/board/presentation/widgets/board_column_header.dart @@ -3,7 +3,6 @@ import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/plugins/database/board/application/board_bloc.dart'; import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart'; import 'package:appflowy/plugins/database/grid/presentation/widgets/header/field_type_extension.dart'; -import 'package:appflowy/plugins/shared/callback_shortcuts.dart'; import 'package:appflowy/workspace/presentation/widgets/dialogs.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart'; import 'package:appflowy_board/appflowy_board.dart'; @@ -32,7 +31,6 @@ class BoardColumnHeader extends StatefulWidget { class _BoardColumnHeaderState extends State { final FocusNode _focusNode = FocusNode(); final FocusNode _keyboardListenerFocusNode = FocusNode(); - late final AFCallbackShortcutsProvider _shortcutsProvider; late final TextEditingController _controller = TextEditingController.fromValue( @@ -47,21 +45,15 @@ class _BoardColumnHeaderState extends State { @override void initState() { super.initState(); - _shortcutsProvider = context.read(); _focusNode.addListener(() { if (!_focusNode.hasFocus) { _saveEdit(); } }); - _keyboardListenerFocusNode.addListener(() { - _shortcutsProvider.isShortcutsEnabled.value = - !_keyboardListenerFocusNode.hasFocus; - }); } @override void dispose() { - _shortcutsProvider.isShortcutsEnabled.value = true; _focusNode.dispose(); _keyboardListenerFocusNode.dispose(); _controller.dispose(); diff --git a/frontend/appflowy_flutter/lib/plugins/database/board/presentation/widgets/board_focus_scope.dart b/frontend/appflowy_flutter/lib/plugins/database/board/presentation/widgets/board_focus_scope.dart index e636ab626d..ed329904b9 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/board/presentation/widgets/board_focus_scope.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/board/presentation/widgets/board_focus_scope.dart @@ -39,14 +39,14 @@ class BoardFocusScope extends ChangeNotifier notifyListeners(); } - void focusNext() { + bool focusNext() { _deepCopy(); // if no card is focused, focus on the first card in the board if (_focusedCards.isEmpty) { _focusFirstCard(); notifyListeners(); - return; + return true; } final lastFocusedCard = _focusedCards.last; @@ -58,7 +58,7 @@ class BoardFocusScope extends ChangeNotifier if (iterable == null || iterable.isEmpty) { _focusFirstCard(); notifyListeners(); - return; + return true; } if (iterable.length == 1) { @@ -90,16 +90,18 @@ class BoardFocusScope extends ChangeNotifier } notifyListeners(); + + return true; } - void focusPrevious() { + bool focusPrevious() { _deepCopy(); // if no card is focused, focus on the last card in the board if (_focusedCards.isEmpty) { _focusLastCard(); notifyListeners(); - return; + return true; } final lastFocusedCard = _focusedCards.last; @@ -111,7 +113,7 @@ class BoardFocusScope extends ChangeNotifier if (iterable == null || iterable.isEmpty) { _focusLastCard(); notifyListeners(); - return; + return true; } if (iterable.length == 1) { @@ -143,16 +145,18 @@ class BoardFocusScope extends ChangeNotifier } notifyListeners(); + + return true; } - void adjustRangeDown() { + bool adjustRangeDown() { _deepCopy(); // if no card is focused, focus on the first card in the board if (_focusedCards.isEmpty) { _focusFirstCard(); notifyListeners(); - return; + return true; } final firstFocusedCard = _focusedCards.first; @@ -171,7 +175,7 @@ class BoardFocusScope extends ChangeNotifier if (firstGroupIndex == -1 || lastGroupIndex == -1) { _focusFirstCard(); notifyListeners(); - return; + return true; } if (firstGroupIndex < lastGroupIndex) { @@ -189,7 +193,7 @@ class BoardFocusScope extends ChangeNotifier if (firstCardIndex == -1 || lastCardIndex == -1) { _focusFirstCard(); notifyListeners(); - return; + return true; } isExpand = firstCardIndex < lastCardIndex; @@ -203,7 +207,7 @@ class BoardFocusScope extends ChangeNotifier if (groupController == null) { _focusFirstCard(); notifyListeners(); - return; + return true; } final iterable = groupController.items @@ -236,16 +240,17 @@ class BoardFocusScope extends ChangeNotifier } notifyListeners(); + return true; } - void adjustRangeUp() { + bool adjustRangeUp() { _deepCopy(); // if no card is focused, focus on the first card in the board if (_focusedCards.isEmpty) { _focusLastCard(); notifyListeners(); - return; + return true; } final firstFocusedCard = _focusedCards.first; @@ -264,7 +269,7 @@ class BoardFocusScope extends ChangeNotifier if (firstGroupIndex == -1 || lastGroupIndex == -1) { _focusLastCard(); notifyListeners(); - return; + return true; } if (firstGroupIndex < lastGroupIndex) { @@ -282,7 +287,7 @@ class BoardFocusScope extends ChangeNotifier if (firstCardIndex == -1 || lastCardIndex == -1) { _focusLastCard(); notifyListeners(); - return; + return true; } isExpand = firstCardIndex > lastCardIndex; @@ -296,7 +301,7 @@ class BoardFocusScope extends ChangeNotifier if (groupController == null) { _focusLastCard(); notifyListeners(); - return; + return true; } final iterable = groupController.items.reversed @@ -329,12 +334,15 @@ class BoardFocusScope extends ChangeNotifier } notifyListeners(); + + return true; } - void clear() { + bool clear() { _deepCopy(); _focusedCards.clear(); notifyListeners(); + return true; } void _focusFirstCard() { diff --git a/frontend/appflowy_flutter/lib/plugins/database/board/presentation/widgets/board_shortcut_container.dart b/frontend/appflowy_flutter/lib/plugins/database/board/presentation/widgets/board_shortcut_container.dart index 1035364702..b45b849bf4 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/board/presentation/widgets/board_shortcut_container.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/board/presentation/widgets/board_shortcut_container.dart @@ -22,56 +22,7 @@ class BoardShortcutContainer extends StatelessWidget { @override Widget build(BuildContext context) { return AFCallbackShortcuts( - canAcceptEvent: (_, __) => - context.read().isShortcutsEnabled.value, - bindings: { - const SingleActivator(LogicalKeyboardKey.arrowUp): - focusScope.focusPrevious, - const SingleActivator(LogicalKeyboardKey.arrowDown): - focusScope.focusNext, - const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true): - focusScope.adjustRangeUp, - const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true): - focusScope.adjustRangeDown, - const SingleActivator(LogicalKeyboardKey.escape): focusScope.clear, - const SingleActivator(LogicalKeyboardKey.keyE): () { - if (focusScope.value.length != 1) { - return; - } - context - .read() - .startEditingRow(focusScope.value.first); - }, - const SingleActivator(LogicalKeyboardKey.keyN): () { - if (focusScope.value.length != 1) { - return; - } - context - .read() - .startCreateBottomRow(focusScope.value.first.groupId); - focusScope.clear(); - }, - const SingleActivator(LogicalKeyboardKey.delete): () => - _removeHandler(context), - const SingleActivator(LogicalKeyboardKey.backspace): () => - _removeHandler(context), - SingleActivator( - LogicalKeyboardKey.arrowUp, - shift: true, - meta: Platform.isMacOS, - control: !Platform.isMacOS, - ): () => _shiftCmdUpHandler(context), - const SingleActivator(LogicalKeyboardKey.enter): () => - _enterHandler(context), - const SingleActivator(LogicalKeyboardKey.numpadEnter): () => - _enterHandler(context), - const SingleActivator(LogicalKeyboardKey.enter, shift: true): () => - _shitEnterHandler(context), - const SingleActivator(LogicalKeyboardKey.comma): () => - _moveGroupToAdjacentGroup(context, true), - const SingleActivator(LogicalKeyboardKey.period): () => - _moveGroupToAdjacentGroup(context, false), - }, + bindings: _shortcutBindings(context), child: FocusScope( child: Focus( child: Builder( @@ -92,16 +43,75 @@ class BoardShortcutContainer extends StatelessWidget { ); } - void _enterHandler(BuildContext context) { + Map _shortcutBindings( + BuildContext context, + ) { + return { + const SingleActivator(LogicalKeyboardKey.arrowUp): + focusScope.focusPrevious, + const SingleActivator(LogicalKeyboardKey.arrowDown): focusScope.focusNext, + const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true): + focusScope.adjustRangeUp, + const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true): + focusScope.adjustRangeDown, + const SingleActivator(LogicalKeyboardKey.escape): focusScope.clear, + const SingleActivator(LogicalKeyboardKey.delete): () => + _removeHandler(context), + const SingleActivator(LogicalKeyboardKey.backspace): () => + _removeHandler(context), + SingleActivator( + LogicalKeyboardKey.arrowUp, + shift: true, + meta: Platform.isMacOS, + control: !Platform.isMacOS, + ): () => _shiftCmdUpHandler(context), + const SingleActivator(LogicalKeyboardKey.enter): () => + _enterHandler(context), + const SingleActivator(LogicalKeyboardKey.numpadEnter): () => + _enterHandler(context), + const SingleActivator(LogicalKeyboardKey.enter, shift: true): () => + _shiftEnterHandler(context), + const SingleActivator(LogicalKeyboardKey.comma): () => + _moveGroupToAdjacentGroup(context, true), + const SingleActivator(LogicalKeyboardKey.period): () => + _moveGroupToAdjacentGroup(context, false), + const SingleActivator(LogicalKeyboardKey.keyE): () => + _keyEHandler(context), + const SingleActivator(LogicalKeyboardKey.keyN): () => + _keyNHandler(context), + }; + } + + bool _keyEHandler(BuildContext context) { if (focusScope.value.length != 1) { - return; + return false; + } + context.read().startEditingRow(focusScope.value.first); + return true; + } + + bool _keyNHandler(BuildContext context) { + if (focusScope.value.length != 1) { + return false; + } + context + .read() + .startCreateBottomRow(focusScope.value.first.groupId); + focusScope.clear(); + return true; + } + + bool _enterHandler(BuildContext context) { + if (focusScope.value.length != 1) { + return false; } context .read() .openCardWithRowId(focusScope.value.first.rowId); + return true; } - void _shitEnterHandler(BuildContext context) { + bool _shiftEnterHandler(BuildContext context) { if (focusScope.value.isEmpty) { context .read() @@ -111,10 +121,13 @@ class BoardShortcutContainer extends StatelessWidget { focusScope.value.first, CreateBoardCardRelativePosition.after, ); + } else { + return false; } + return true; } - void _shiftCmdUpHandler(BuildContext context) { + bool _shiftCmdUpHandler(BuildContext context) { if (focusScope.value.isEmpty) { context .read() @@ -124,19 +137,23 @@ class BoardShortcutContainer extends StatelessWidget { focusScope.value.first, CreateBoardCardRelativePosition.before, ); + } else { + return false; } + return true; } - void _removeHandler(BuildContext context) { - if (focusScope.value.isEmpty) { - return; + bool _removeHandler(BuildContext context) { + if (focusScope.value.length != 1) { + return false; } context.read().add(BoardEvent.deleteCards(focusScope.value)); + return true; } - void _moveGroupToAdjacentGroup(BuildContext context, bool toPrevious) { + bool _moveGroupToAdjacentGroup(BuildContext context, bool toPrevious) { if (focusScope.value.length != 1) { - return; + return false; } context.read().add( BoardEvent.moveGroupToAdjacentGroup( @@ -145,5 +162,6 @@ class BoardShortcutContainer extends StatelessWidget { ), ); focusScope.clear(); + return true; } } diff --git a/frontend/appflowy_flutter/lib/plugins/shared/callback_shortcuts.dart b/frontend/appflowy_flutter/lib/plugins/shared/callback_shortcuts.dart index 26e188511e..238b6bd85d 100644 --- a/frontend/appflowy_flutter/lib/plugins/shared/callback_shortcuts.dart +++ b/frontend/appflowy_flutter/lib/plugins/shared/callback_shortcuts.dart @@ -1,26 +1,24 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -class AFCallbackShortcutsProvider { - final ValueNotifier isShortcutsEnabled = ValueNotifier(true); -} +typedef AFBindingCallback = bool Function(); class AFCallbackShortcuts extends StatelessWidget { const AFCallbackShortcuts({ super.key, required this.bindings, - required this.canAcceptEvent, required this.child, }); - final Map bindings; - final bool Function(FocusNode node, KeyEvent event) canAcceptEvent; + // The bindings for the shortcuts + // + // The result of the callback will be used to determine if the event is handled + final Map bindings; final Widget child; bool _applyKeyEventBinding(ShortcutActivator activator, KeyEvent event) { if (activator.accepts(event, HardwareKeyboard.instance)) { - bindings[activator]!.call(); - return true; + return bindings[activator]?.call() ?? false; } return false; } @@ -31,9 +29,6 @@ class AFCallbackShortcuts extends StatelessWidget { canRequestFocus: false, skipTraversal: true, onKeyEvent: (FocusNode node, KeyEvent event) { - if (!canAcceptEvent(node, event)) { - return KeyEventResult.ignored; - } KeyEventResult result = KeyEventResult.ignored; for (final ShortcutActivator activator in bindings.keys) { result = _applyKeyEventBinding(activator, event) diff --git a/frontend/appflowy_flutter/lib/workspace/application/favorite/favorite_bloc.dart b/frontend/appflowy_flutter/lib/workspace/application/favorite/favorite_bloc.dart index 8bc1e549ee..13322807b3 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/favorite/favorite_bloc.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/favorite/favorite_bloc.dart @@ -60,7 +60,8 @@ class FavoriteBloc extends Bloc { ); }, toggle: (view) async { - if (view.isFavorite) { + final isFavorited = state.views.any((v) => v.item.id == view.id); + if (isFavorited) { await _service.unpinFavorite(view); } else if (state.pinnedViews.length < 3) { // pin the view if there are less than 3 pinned views diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/widgets/favorite_button.dart b/frontend/appflowy_flutter/lib/workspace/presentation/widgets/favorite_button.dart index 68e8073db3..6e1c377277 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/widgets/favorite_button.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/widgets/favorite_button.dart @@ -35,7 +35,7 @@ class ViewFavoriteButton extends StatelessWidget { child: FlowySvg( isFavorite ? FlowySvgs.favorited_s : FlowySvgs.favorite_s, size: const Size.square(18), - blendMode: null, + blendMode: isFavorite ? null : BlendMode.srcIn, ), ), ), From b6d873db1b11e1874e64b12799351822b86a1a3c Mon Sep 17 00:00:00 2001 From: Mathias Mogensen <42929161+Xazin@users.noreply.github.com> Date: Mon, 10 Jun 2024 03:04:28 +0200 Subject: [PATCH 16/16] chore: remove build bot (#5500) --- .github/workflows/build_bot.yaml | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 .github/workflows/build_bot.yaml diff --git a/.github/workflows/build_bot.yaml b/.github/workflows/build_bot.yaml deleted file mode 100644 index 65854b94d1..0000000000 --- a/.github/workflows/build_bot.yaml +++ /dev/null @@ -1,28 +0,0 @@ -name: Build Bot - -on: - issue_comment: - types: [created] - -jobs: - dispatch_slash_command: - runs-on: ubuntu-latest - steps: - - name: Checkout source code - uses: actions/checkout@v4 - - # get build name from pubspec.yaml - - name: Get build version - working-directory: frontend/appflowy_flutter - id: get_build_name - run: | - echo "fetching version from pubspec.yaml..." - echo "build_name=$(grep 'version: ' pubspec.yaml | awk '{print $2}')" >> $GITHUB_OUTPUT - - - uses: peter-evans/slash-command-dispatch@v4 - with: - token: ${{ secrets.PAT }} - commands: build - static-args: | - ref=refs/pull/${{ github.event.issue.number }}/head - build_name=${{ steps.get_build_name.outputs.build_name }}